# HXP Machine Integrations
> Source: /hxp/machine-integrations
> Organization-scoped API keys, workspace permissions, message events, and Action progress for third-party systems

<Warning>
  The M2M service was deployed and enabled on September 19, 2026, from HXP commit `974da1f9ae67dbf040029bcc0d7c64cc2fd6c1bb`. The production migration and six WorkOS permissions are configured, and unauthenticated requests return 401. End-to-end issuance, Action updates and revocation still require a connected check in an authorized organization. Confirm that check before onboarding a production consumer. Other deployments return 503 while disabled.
</Warning>

WorkOS issues and validates organization-owned credentials. HXP adds explicit workspace and conversation grants. Use a separate integration key for each system; an API key is a machine identity, not a saved operator session.

## Create an organization API key [#create-an-organization-api-key]

In the active organization's **Settings → Developer API → Messaging integrations**, choose **Create key**. Select a name, expiration, permissions, exact workspaces, and shared staff or team audiences. Copy the secret once into the integrating server's secret manager. Expand **Connection details** on the key to copy its workspace IDs and permission scopes. HXP never stores the raw key. Do not put it in a browser or mobile app.

Management requires HXP `hxp:integrations:manage` and WorkOS `widgets:api-keys:manage` in the exact selected organization. Only workspaces and teams accessible to that operator can be granted. Action write permissions additionally require `hxp:organizations:manage`. A Journey superadmin viewing another organization's route cannot mint its keys without a real selected WorkOS membership and key-management permission.

| Permission | Capability |
| --- | --- |
| `hxp:api:threads:read` | Read eligible conversation comments |
| `hxp:api:events:read` | Poll change metadata; also grant the corresponding resource read permission |
| `hxp:api:actions:read` | Read eligible Actions and their current versions |
| `hxp:api:actions:claim` | Claim unowned Actions |
| `hxp:api:actions:complete` | Complete this integration's Actions with evidence |
| `hxp:api:actions:cancel` | Cancel this integration's Actions |

Keys do not inherit creator permissions. The effective grant is the intersection of live WorkOS permissions and the active HXP grant. Selecting an organization workspace does not imply access to every brand or venue. Team Actions need both conversation-audience access and the matching team grant. Sensitive/deleted notes, AI-authored or source-derived messages, private AI history, legacy guest context, and Actions sourced from excluded messages are omitted. This API does not export canonical guest profiles or attachments.

Revoke a key in Settings to stop HXP access. Local revocation commits before the provider call; use **Retry provider revocation** if WorkOS is unavailable. Changes already accepted before revocation may finish. To change permissions or rotate a secret, create a replacement key, update the integration, then revoke the old one. Ownership is per key: finish existing work before replacing a key; a new key cannot impersonate the old integration to complete its Actions.

## API contract [#api-contract]

Base: `https://v3.hxp.journey.com/api/external/v1`. Authenticate every request with `Authorization: Bearer <organization-api-key>`. The credential determines the organization. Never send an organization override. `scope` is an exact workspace ID selected in Settings.

```sh
curl --get "$HXP_BASE/messaging" \
  -H "Authorization: Bearer $HXP_API_KEY" \
  --data-urlencode "scope=$HXP_SCOPE" \
  --data-urlencode 'view=thread' \
  --data-urlencode "guest=$GUEST_ID"
```

Reads:

- `GET /messaging?scope=…&view=thread&guest=…` → `{ "data": { "messages": [], "nextCursor": null } }`.
- `GET /messaging?scope=…&view=actions` → `{ "data": { "items": [], "nextCursor": null } }`. Add `id` to read one Action.
- Continue thread/Action pages using `before=<nextCursor>` until `nextCursor` is null. Pages scan up to 100 records before visibility filtering; keep following cursors even if the visible list is empty.
- `GET /messaging?scope=…&view=events&after=0` → `{ "data": { "events": [], "cursor": 0 } }`. Events contain `id`, `sequence`, `type`, `resourceId`, `actorId`, `createdAt`; fetch the resource for its current state.

Persist the event cursor after processing each page, even when filtered events are empty. Keep a separate cursor per integration and workspace. Poll sequentially with backoff (for example every 5–15 seconds), handle duplicates, and periodically reconcile your authorized resource snapshots. Do not treat this feed as a complete audit/replication stream: events whose resources are now deleted, sensitive or inaccessible are omitted. No third-party webhook subscription, SSE or WebSocket API is provided by this release.

Write using `POST /messaging?scope=…` with `Content-Type: application/json` and a stable `Idempotency-Key` (8–180 letters, digits, `_`, `:` or `-`):

```json
{ "type": "claim", "id": "action_example", "expectedVersion": 1 }
```

Re-read the Action for its new `version`, then finish it:

```json
{ "type": "finish", "id": "action_example", "expectedVersion": 2, "evidence": "Synthetic test task completed." }
```

Cancel with `type: "cancel_action"`, `id`, and `expectedVersion`. Terminal states cannot be reopened. Completion evidence is required (8–2000 trimmed characters). The result is `{ "result": { "id": "action_example", "kind": "action", "receiptId": "…" } }`. A retry with the same operation key and identical body returns the original receipt. Different input with that key returns 409. On a version conflict, refresh and decide whether to issue a new operation; do not automatically overwrite concurrent human work.

This API records HXP Action progress only. It does not send a guest message, approve an AI draft, fulfill a benefit in Core, charge a payment, or claim provider delivery. There is no arbitrary status patch, operator impersonation, message creation, or private AI execution endpoint.

Errors use `application/problem+json` with `code`, `status`, `title`, `request_id`, `retryable`. 401 means invalid credential; 403 means missing permission/grant/scope; 404 masks inaccessible work; 409 means stale version or conflicting replay; 429 includes retry guidance; 503 means disabled/unavailable integration. Successful requests include per-key rate headers; the default budget is 120 requests/minute, shared with the external API. Honor `Retry-After` and never log credentials or guest message bodies.

The complete schema is [OpenAPI](https://v3.hxp.journey.com/hxp-api/openapi-v1.json).
