API reference
Partner
One tag: method, path, summary, auth, and scopes. Request and response fields ship in this page — expand a row to read the contract.
Endpoints
13
POST
/api/v1/partner/workspaces
partner token
Provision or link a marketplace workspace
workspaces:provision
/api/v1/partner/workspaces
partner token
Provision or link a marketplace workspace
Description
PartnerAuth: Authorization: Bearer mpk_… (not an agk_ workspace key). Idempotent find-or-link workspace provisioning for a marketplace partner user. On first contact it creates the user, workspace and bridge service agent; on repeat calls it links, and a previously disconnected link is reactivated. No long-lived key is issued: runtimes are credentialed per engagement. Created workspaces write settings.quota_overrides.traces_per_month = infinity so sponsored ingest never 429s mid-hire; other quota dimensions stay on the workspace plan. The workspace is marketplace-managed: invitations are refused (marketplace_managed_workspace) and it stays single-member.
Auth
partner tokenRequired Scopes
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | No | Display name |
| string | Yes | Human email, stored on the identity account (never the login address) | |
| workspace | object | Yes | Workspace mapping: external_ref (stable key) and name |
| external_user_id | string | Yes | The marketplace's stable user UUID |
Responses
200
Already linked; identical fields to the created response
Already linked; identical fields to the created response
Example
{
"status": "linked",
"service_agent_id": "1a2b3c4d-5e6f-4a4b-8c8d-333333333333",
"workspace_id": "0f0e0d0c-0b0a-4a4b-8c8d-222222222222",
"user_id": "8f14e45f-ea4c-4c8b-9d2c-111111111111",
"workspace_slug": "alex-owner-agrenting"
}
201
Workspace created
Workspace created
Example
{
"status": "created",
"service_agent_id": "1a2b3c4d-5e6f-4a4b-8c8d-333333333333",
"workspace_id": "0f0e0d0c-0b0a-4a4b-8c8d-222222222222",
"user_id": "8f14e45f-ea4c-4c8b-9d2c-111111111111",
"workspace_slug": "alex-owner-agrenting"
}
401
PartnerAuth failed. Body is {error: "invalid_partner_credential"}
PartnerAuth failed. Body is {error: "invalid_partner_credential"}
403
Partner lacks workspaces:provision. Body is {error: "insufficient_partner_scope"}
Partner lacks workspaces:provision. Body is {error: "insufficient_partner_scope"}
DELETE
/api/v1/partner/workspaces/:external_ref
partner token
Disconnect a linked workspace
workspaces:provision
/api/v1/partner/workspaces/:external_ref
partner token
Disconnect a linked workspace
Description
PartnerAuth: Authorization: Bearer mpk_…. Revokes every credential the partner holds in the workspace: active engagements are revoked, legacy bridge credentials and the bridge service agent are revoked, partner webhook subscriptions are disabled and the linked user's browser sessions are cut. The workspace, user, membership and identity provider are untouched — they are the user's own account — and the link row is kept as disconnected so a later provision call reconnects to the same workspace.
Auth
partner tokenRequired Scopes
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| external_ref | path | string | Yes | Workspace mapping key used at provisioning |
Responses
200
Workspace disconnected
Workspace disconnected
Example
{
"status": "disconnected",
"workspace_id": "0f0e0d0c-0b0a-4a4b-8c8d-222222222222",
"engagements_revoked": 3
}
401
PartnerAuth failed. Body is {error: "invalid_partner_credential"}
PartnerAuth failed. Body is {error: "invalid_partner_credential"}
403
Partner lacks workspaces:provision. Body is {error: "insufficient_partner_scope"}
Partner lacks workspaces:provision. Body is {error: "insufficient_partner_scope"}
404
Body is {error: "identity_not_linked"}
Body is {error: "identity_not_linked"}
POST
/api/v1/partner/sso_handoffs
partner token
Mint a single-use browser SSO handoff
sso:handoff
/api/v1/partner/sso_handoffs
partner token
Mint a single-use browser SSO handoff
Description
PartnerAuth: Authorization: Bearer mpk_…. Mints a 120-second, single-use handoff URL that logs the linked marketplace user into their workspace and redirects to return_to (must start with /app).
Auth
partner tokenRequired Scopes
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| return_to | string | No | In-app path to land on; defaults to /app |
| external_ref | string | Yes | Workspace mapping key used at provisioning |
| external_user_id | string | Yes | Marketplace user UUID |
Responses
201
Handoff minted
Handoff minted
Example
{
"expires_at": "2026-08-05T12:02:00Z",
"handoff_url": "https://robotscenter.net/sso/partner/abc123"
}
401
PartnerAuth failed. Body is {error: "invalid_partner_credential"}
PartnerAuth failed. Body is {error: "invalid_partner_credential"}
403
Partner lacks sso:handoff. Body is {error: "insufficient_partner_scope"}
Partner lacks sso:handoff. Body is {error: "insufficient_partner_scope"}
404
Body is {error: "identity_not_linked"}
Body is {error: "identity_not_linked"}
422
Body is {error: "invalid_return_to"}
Body is {error: "invalid_return_to"}
POST
/api/v1/partner/webhook_subscriptions
partner token
Register a webhook subscription on a linked workspace
webhooks:manage
/api/v1/partner/webhook_subscriptions
partner token
Register a webhook subscription on a linked workspace
Description
PartnerAuth: Authorization: Bearer mpk_…. Creates a webhook subscription in the linked workspace and returns the HMAC signing secret. Supply an Idempotency-Key to make exact retries replay the same subscription and secret for 24 hours; reusing the key with a different body returns 409. Without the header, every request creates a new subscription. Omitted event_types default to trace.event.appended and trace.finalized only — not failure_group.created. Reconciliation is webhooks only: an mpk_ key cannot GET /api/v1/traces/:id.
Auth
partner tokenRequired Scopes
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| url | string | Yes | HTTPS delivery URL |
| event_types | array<object> | No | Event type filters. Defaults to ["trace.event.appended", "trace.finalized"] when omitted. failure_group.created is not in the default set. |
| external_ref | string | Yes | Workspace mapping key used at provisioning |
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| Idempotency-Key | header | string | No | Partner-scoped exact-retry key retained for 24 hours |
Responses
200
Exact Idempotency-Key replay; same subscription and secret
Exact Idempotency-Key replay; same subscription and secret
201
Subscription created; secret shown once
Subscription created; secret shown once
Example
{
"secret": "base64url-signing-secret",
"subscription_id": "4d5e6f70-8192-4a4b-8c8d-444444444444"
}
401
PartnerAuth failed. Body is {error: "invalid_partner_credential"}
PartnerAuth failed. Body is {error: "invalid_partner_credential"}
403
Partner lacks webhooks:manage. Body is {error: "insufficient_partner_scope"}
Partner lacks webhooks:manage. Body is {error: "insufficient_partner_scope"}
404
Body is {error: "identity_not_linked"}
Body is {error: "identity_not_linked"}
409
Idempotency-Key was reused with a different body. Body is {error: "idempotency_conflict"}
Idempotency-Key was reused with a different body. Body is {error: "idempotency_conflict"}
422
Idempotency-Key is blank, duplicated, contains non-visible ASCII, or exceeds 200 bytes
Idempotency-Key is blank, duplicated, contains non-visible ASCII, or exceeds 200 bytes
POST
/api/v1/partner/engagements
partner token
Open the engagement for one marketplace hiring
engagements:manage
/api/v1/partner/engagements
partner token
Open the engagement for one marketplace hiring
Description
PartnerAuth: Authorization: Bearer mpk_…. Idempotent per (partner, external_engagement_ref). Creates or adopts the trace for this hiring and binds it to an engagement row. The engagement is the unit of authorization: it is what a runtime token names, and the trace a runtime may append to is read from this row rather than from the runtime's request.
Auth
partner tokenRequired Scopes
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | No | Trace name |
| metadata | object | No | Stamped onto the trace under metadata.marketplace |
| expires_at | string | No | ISO8601; defaults to 7 days, clamped to 30 |
| external_ref | string | Yes | Workspace mapping key used at provisioning |
| external_engagement_ref | string | Yes | The marketplace's stable hiring id |
Responses
200
Engagement already open; same body
Engagement already open; same body
201
Engagement created
Engagement created
Example
{
"status": "active",
"epoch": 1,
"expires_at": "2026-08-12T00:00:00Z",
"workspace_id": "0f0e0d0c-0b0a-4a4b-8c8d-222222222222",
"trace_id": "6c7d8e9f-0112-4a4b-8c8d-666666666666",
"engagement_id": "5b6c7d8e-9f01-4a4b-8c8d-555555555555",
"events_url": "https://robotscenter.net/api/v1/engagements/5b6c7d8e-9f01-4a4b-8c8d-555555555555/events"
}
401
PartnerAuth failed. Body is {error: "invalid_partner_credential"}
PartnerAuth failed. Body is {error: "invalid_partner_credential"}
403
Partner lacks engagements:manage. Body is {error: "insufficient_partner_scope"}
Partner lacks engagements:manage. Body is {error: "insufficient_partner_scope"}
404
Body is {error: "identity_not_linked"}
Body is {error: "identity_not_linked"}
409
Body is {error: "engagement_closed"}
Body is {error: "engagement_closed"}
422
Body is {error: "invalid_external_ref"}
Body is {error: "invalid_external_ref"}
POST
/api/v1/partner/engagements/:id/tokens
partner token
Mint a runtime token for an engagement
engagements:manage
/api/v1/partner/engagements/:id/tokens
partner token
Mint a runtime token for an engagement
Description
PartnerAuth: Authorization: Bearer mpk_…. Returns the only credential a rented runtime ever holds: append-only, bound to one engagement and one trace, and dead the moment the engagement is closed or revoked. It authenticates on events_url via EngagementAuth and nowhere else. TTL defaults to 86400 seconds, is clamped to the engagement's own expiry, and is hard-capped at 604800 seconds (7 days). A 30-day engagement cannot mint a 30-day token.
Auth
partner tokenRequired Scopes
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| ttl_seconds | integer | No | Must be positive when present. Defaults to 86400. Clamped to the engagement's own expiry and hard-capped at 604800 seconds (7 days). |
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| id | path | string | Yes | Engagement UUID |
Responses
201
Token minted
Token minted
Example
{
"token": "SFMyNTY.opaque",
"expires_at": "2026-08-07T12:00:00Z",
"scopes": [
"engagement:append"
],
"engagement_id": "5b6c7d8e-9f01-4a4b-8c8d-555555555555",
"events_url": "https://robotscenter.net/api/v1/engagements/5b6c7d8e-9f01-4a4b-8c8d-555555555555/events"
}
401
PartnerAuth failed. Body is {error: "invalid_partner_credential"}
PartnerAuth failed. Body is {error: "invalid_partner_credential"}
403
Partner lacks engagements:manage. Body is {error: "insufficient_partner_scope"}
Partner lacks engagements:manage. Body is {error: "insufficient_partner_scope"}
404
Body is {error: "engagement_not_found"}
Body is {error: "engagement_not_found"}
409
Body is {error: "engagement_closed"}
Body is {error: "engagement_closed"}
422
Body is {error: "invalid_ttl_seconds"}
Body is {error: "invalid_ttl_seconds"}
POST
/api/v1/partner/engagements/:id/events
partner token
Append events to an engagement's trace (marketplace)
engagements:manage
/api/v1/partner/engagements/:id/events
partner token
Append events to an engagement's trace (marketplace)
Description
PartnerAuth: Authorization: Bearer mpk_…. The marketplace's own server-side export leg, for events it observes rather than the runtime does. Events land on the trace named by the engagement row; a trace_id in the body is refused on mismatch and is never used to select a target. Retries are safe: an event whose source_event_id the trace already holds is counted as a duplicate rather than appended twice.
Auth
partner tokenRequired Scopes
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| events | array<object> | Yes | Up to 50 events; each needs a stable source_event_id of at most 128 bytes |
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| id | path | string | Yes | Engagement UUID |
Responses
200
Events appended
Events appended
Example
{
"rejected": 0,
"accepted": 3,
"duplicates": 1
}
401
PartnerAuth failed. Body is {error: "invalid_partner_credential"}
PartnerAuth failed. Body is {error: "invalid_partner_credential"}
403
Partner lacks engagements:manage ({error: "insufficient_partner_scope"}), or {error: "engagement_mismatch"}
Partner lacks engagements:manage ({error: "insufficient_partner_scope"}), or {error: "engagement_mismatch"}
404
Body is {error: "engagement_not_found"}
Body is {error: "engagement_not_found"}
409
Body is {error: "engagement_closed"}
Body is {error: "engagement_closed"}
413
Body is {error: "too_many_events"}
Body is {error: "too_many_events"}
422
Body is {error: "invalid_events"}
Body is {error: "invalid_events"}
POST
/api/v1/engagements/:engagement_id/events
engagement token
Append runtime events to an engagement's trace
engagement:append
/api/v1/engagements/:engagement_id/events
engagement token
Append runtime events to an engagement's trace
Description
EngagementAuth: Authorization: Bearer <engagement token> only. A workspace agk_ key fails signature verification; an mpk_ partner key is not accepted. The rented runtime's entire authority. Append-only: there is no read, no list, no finalize and no trace id in the path, because the trace written to is read from the engagement row. Errors are {error: code}, not RFC 9457. 401 from the plug (invalid_token, token_expired, token_revoked, engagement_closed, engagement_expired) and 403 from the controller (engagement_mismatch, insufficient_scope) are terminal — stop exporting.
Auth
engagement tokenRequired Scopes
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| events | array<object> | Yes | Up to 50 events; each needs a stable source_event_id of at most 128 bytes |
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| engagement_id | path | string | Yes | Engagement UUID; must match the one the token names |
Responses
200
Events appended
Events appended
Example
{
"rejected": 0,
"accepted": 3,
"duplicates": 1
}
401
{error: "invalid_token"|"token_expired"|"token_revoked"|"engagement_closed"|"engagement_expired"} — all terminal; stop exporting
{error: "invalid_token"|"token_expired"|"token_revoked"|"engagement_closed"|"engagement_expired"} — all terminal; stop exporting
403
{error: "engagement_mismatch"} or {error: "insufficient_scope"}
{error: "engagement_mismatch"} or {error: "insufficient_scope"}
413
{error: "too_many_events"}
{error: "too_many_events"}
422
{error: "invalid_events"}
{error: "invalid_events"}
GET
/api/v1/partner/engagements
partner token
Reconcile marketplace engagements
engagements:manage
/api/v1/partner/engagements
partner token
Reconcile marketplace engagements
Description
PartnerAuth with engagements:manage. Returns only partner-owned operational status; it never returns event or payload bodies. Results use an opaque updated_at/id cursor.
Auth
partner tokenRequired Scopes
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| cursor | query | string | No | |
| limit | query | integer | No | |
| status | query | string | No | |
| external_ref | query | string | No | |
| external_engagement_ref | query | string | No |
Responses
200
Partner engagement page
Partner engagement page
400
Invalid cursor
Invalid cursor
401
Invalid partner credential
Invalid partner credential
403
Insufficient partner scope
Insufficient partner scope
GET
/api/v1/partner/engagements/:id
partner token
Read marketplace engagement status
engagements:manage
/api/v1/partner/engagements/:id
partner token
Read marketplace engagement status
Description
Partner-scoped operational status including immutable runtime outcome and the separate commercial projection.
Auth
partner tokenRequired Scopes
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| id | path | string | Yes |
Responses
200
Engagement status
Engagement status
401
Invalid partner credential
Invalid partner credential
403
Insufficient partner scope
Insufficient partner scope
404
Engagement not found
Engagement not found
GET
/api/v1/partner/engagements/:id/commercial_events
partner token
Reconcile immutable commercial outcome history
engagements:manage
/api/v1/partner/engagements/:id/commercial_events
partner token
Reconcile immutable commercial outcome history
Description
Partner-scoped, revision-ordered commercial event history. Use after_revision and the returned next_after_revision for bounded pagination. Event metadata and internal request hashes are never returned.
Auth
partner tokenRequired Scopes
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| id | path | string | Yes | |
| after_revision | query | integer | No | |
| limit | query | integer | No |
Responses
200
Commercial event page
Commercial event page
400
Invalid revision
Invalid revision
401
Invalid partner credential
Invalid partner credential
403
Insufficient partner scope
Insufficient partner scope
404
Engagement not found
Engagement not found
POST
/api/v1/partner/engagements/:id/commercial_events
partner token
Record a commercial outcome transition
engagements:manage
/api/v1/partner/engagements/:id/commercial_events
partner token
Record a commercial outcome transition
Description
Appends an idempotent commercial event without changing the immutable runtime trace outcome.
Auth
partner tokenRequired Scopes
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| state | string | Yes | open | settled | disputed | refunded |
| metadata | object | No | |
| reason_code | string | No | |
| effective_at | string | No | |
| external_event_id | string | Yes | |
| external_state | string | No |
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| id | path | string | Yes |
Responses
200
Existing idempotent event
Existing idempotent event
201
Commercial event recorded
Commercial event recorded
409
Idempotency conflict
Idempotency conflict
422
Invalid transition
Invalid transition
POST
/api/v1/partner/engagements/:id/close
partner token
Finalize the trace and close the engagement
engagements:manage
/api/v1/partner/engagements/:id/close
partner token
Finalize the trace and close the engagement
Description
PartnerAuth: Authorization: Bearer mpk_…. Finalizes the bound trace with a terminal status and bumps the engagement epoch, so every outstanding runtime token for this hiring is refused at its next request. Idempotent. EngagementExpiryWorker also closes still-active engagements 900 seconds after expires_at as final_status partial and bumps the epoch the same way.
Auth
partner tokenRequired Scopes
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| reason | string | No | Failure detail, <= 512 chars |
| status | string | No | ok | error | partial; defaults to ok |
| ended_at | string | No | ISO8601; defaults to now |
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| id | path | string | Yes | Engagement UUID |
Responses
200
Engagement closed
Engagement closed
Example
{
"status": "closed",
"trace_status": "ok",
"engagement_id": "5b6c7d8e-9f01-4a4b-8c8d-555555555555",
"final_status": "ok"
}
401
PartnerAuth failed. Body is {error: "invalid_partner_credential"}
PartnerAuth failed. Body is {error: "invalid_partner_credential"}
403
Partner lacks engagements:manage. Body is {error: "insufficient_partner_scope"}
Partner lacks engagements:manage. Body is {error: "insufficient_partner_scope"}
404
Body is {error: "engagement_not_found"}
Body is {error: "engagement_not_found"}