Log in Create workspace
Skip to content

API reference

Partner

Provision marketplace-linked workspaces, issue browser handoffs, manage engagements, and grant rented runtimes append-only telemetry access.

Jump to 18 endpoints
On this page

Overview

Use the partner API when a marketplace needs to give a customer a workspace and track a rented agent's work. Each job is represented by an engagement: a bounded record connecting the marketplace, workspace, and execution trace. Your marketplace authenticates with an mpk_ partner key; the rented runtime gets a separate short-lived token limited to appending its own engagement events.

Partner, runtime, workspace, and browser identities differ
The mpk_ key manages linked workspaces and engagements but cannot read workspace traces. An engagement token works only on one append URL and has no read/finalize authority. Workspace agk_ keys use the ordinary machine plane, while SSO handoffs are 120-second single-use browser credentials.
An engagement is the authorization boundary
It binds one hiring to one workspace trace. Runtime and partner event routes select that trace from the engagement row, not caller input; stable source_event_id values deduplicate events, and closing increments the epoch so outstanding runtime tokens stop immediately.
Runtime and commercial outcomes are separate
Closing records the immutable runtime outcome and finalizes the trace. Later open, settled, disputed, or refunded commercial events form a revision-ordered history without rewriting what the runtime did.

Before you begin

  • The command-line examples require curl and jq; any exception is identified in its introduction.
  • A marketplace partner credential (mpk_) provisioned with only the needed workspaces:provision, sso:handoff, webhooks:manage, engagements:manage, runs:manage, or runs:viewer_handoff scopes.
  • Stable external user, workspace, engagement, and commercial-event identifiers owned by the marketplace.
  • A secure server-side store for partner keys, webhook signing secrets, and short-lived engagement tokens.

How it works

  1. Provision or reconnect the workspace

    POST the stable external user/workspace mapping. First contact creates the managed workspace and bridge agent; repeats link or reactivate the same mapping without issuing a long-lived workspace key.

  2. Open one engagement per hiring

    Use the partner's stable hiring ID, retain the returned engagement and trace IDs, then mint a runtime token with a TTL no longer than seven days or the engagement's own expiry.

  3. Append, reconcile, and close

    The runtime posts bounded event batches to its events URL; the partner uses its own scoped routes for server-observed events and status reconciliation. Close once with the final runtime status, then record commercial transitions separately.

Examples

These examples are illustrative. Replace the sample values with your own. Keep credentials in environment variables or a secret manager, never in client-side code.

Provision a marketplace-linked workspace

Repeating the same stable mapping links the existing workspace instead of creating another.

bash
export AGENTOPS_BASE_URL="https://robotscenter.net"
export PARTNER_API_KEY="mpk_value_from_partner_secret_manager"

curl --fail-with-body --silent --show-error \
  -X POST -H 'content-type: application/json' \
  -H "Authorization: Bearer $PARTNER_API_KEY" \
  --data '{"external_user_id":"a1905ed7-0314-4cd3-9fc2-5a27c42d65fe","email":"marketplace-owner@example.com","name":"Example Owner","workspace":{"external_ref":"tenant-example-1042","name":"Example Automation Workspace"}}' \
  "$AGENTOPS_BASE_URL/api/v1/partner/workspaces" | jq .
What to expect

First contact returns HTTP 201 with status: created; repeats return 200 with status: linked. Both include user, workspace, slug, and bridge service-agent IDs but no workspace API key.

Open an engagement and mint its runtime token

The partner key creates and mints; only the returned engagement token belongs on the runtime events URL.

bash
export AGENTOPS_BASE_URL="https://robotscenter.net"
export PARTNER_API_KEY="mpk_value_from_partner_secret_manager"

ENGAGEMENT_RESPONSE=$(curl --fail-with-body --silent --show-error \
  -X POST -H 'content-type: application/json' \
  -H "Authorization: Bearer $PARTNER_API_KEY" \
  --data '{"external_ref":"tenant-example-1042","external_engagement_ref":"hiring-example-7788","name":"Example hiring 7788","metadata":{"source":"example-marketplace"}}' \
  "$AGENTOPS_BASE_URL/api/v1/partner/engagements")

export ENGAGEMENT_ID=$(printf '%s' "$ENGAGEMENT_RESPONSE" | jq -r '.engagement_id')
curl --fail-with-body --silent --show-error \
  -X POST -H 'content-type: application/json' \
  -H "Authorization: Bearer $PARTNER_API_KEY" \
  --data '{"ttl_seconds":86400}' \
  "$AGENTOPS_BASE_URL/api/v1/partner/engagements/$ENGAGEMENT_ID/tokens" | jq .
What to expect

Engagement creation returns 201 or idempotent 200. Token mint returns 201 with an opaque token, engagement ID, expiry, engagement:append, and the only URL that token can call.

Troubleshooting

Partner errors use two response families
Named partner authentication, authorization, lifecycle, and engagement errors use bare {"error": "code"} bodies. Validation changesets rendered by the shared fallback and 429 responses from the authentication-failure or principal rate limiter use the shared problem JSON shape, so branch on both HTTP status and content type rather than assuming every partner error is bare.
A runtime receives 401 or 403
Stop blind retries and inspect the code. Invalid, expired, revoked, or closed/expired engagement tokens need partner remediation and, where the engagement is still active, a newly minted token. engagement_mismatch means a valid token was sent to the wrong engagement URL; pair that token with its returned engagement_id and events_url instead. insufficient_scope requires a correctly authorized token. A 503 with workspace_paused or workspace_frozen is not a credential problem: keep the events and retry after the Retry-After seconds.
A partner key cannot read the trace
This is intentional isolation. Reconcile through partner engagement/status and webhook routes; an mpk_ credential is not accepted by GET /api/v1/traces/:id.
A webhook retry creates a conflict
Partner webhook-subscription idempotency lasts 24 hours for the exact body. Reusing the same key with changed URL or event types returns idempotency_conflict.

Endpoint reference

Ready to integrate? Open an endpoint for its required permissions, request fields, response format, and status codes. The examples above explain the workflow; these details define each individual request.

POST
/api/v1/partner/workspaces partner token

Provision or link a marketplace workspace

workspaces:provision

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 token

Required Scopes

workspaces:provision
Request Body
Field Type Required Description
name string No Display name
email 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

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-example"
}
201

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-example"
}
401

PartnerAuth failed. Body is {error: "invalid_partner_credential"}

403

Partner lacks workspaces:provision. Body is {error: "insufficient_partner_scope"}

409

Body is {error: "idempotency_conflict"} for a provisioning race or conflicting identity mapping

422

Body is {error: "invalid_external_ref" | "invalid_external_user_id" | "invalid_email"}, or a validation problem for other invalid fields

DELETE
/api/v1/partner/workspaces/:external_ref partner token

Disconnect a linked workspace

workspaces:provision

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 token

Required Scopes

workspaces:provision
Parameters
Name In Type Required Description
external_ref path string Yes Workspace mapping key used at provisioning
Responses
200

Workspace disconnected

Example
{
  "status": "disconnected",
  "workspace_id": "0f0e0d0c-0b0a-4a4b-8c8d-222222222222",
  "engagements_revoked": 3
}
401

PartnerAuth failed. Body is {error: "invalid_partner_credential"}

403

Partner lacks workspaces:provision. Body is {error: "insufficient_partner_scope"}

404

Body is {error: "identity_not_linked"}

POST
/api/v1/partner/workspaces/:external_ref/session_revocations partner token

End a linked user's Robots Center sessions

sso:handoff

Description

PartnerAuth: Authorization: Bearer mpk_…. Deletes the browser sessions of the user the workspace link maps to, so a marketplace that has secured an account can end the Robots Center sessions it created. The body is empty or ignored. The link, engagements, engagement tokens, webhook subscriptions and run viewer sessions are untouched, and another partner's users are never reached. Answers 204 in every success case, including an unknown external_ref, an unlinked workspace or a user with no sessions, so a retry is safe.

Auth

partner token

Required Scopes

sso:handoff
Parameters
Name In Type Required Description
external_ref path string Yes Workspace mapping key used at provisioning
Responses
204

Sessions ended, or there was nothing to end. Empty body

401

PartnerAuth failed. Body is {error: "invalid_partner_credential"}

403

Partner lacks sso:handoff. Body is {error: "insufficient_partner_scope"}

POST
/api/v1/partner/sso_handoffs partner token

Mint a single-use browser SSO handoff

sso:handoff

Description

PartnerAuth: Authorization: Bearer mpk_…. Mints a 120-second, single-use handoff URL. Opening it shows the account and workspace; once the user clicks Continue it logs the linked marketplace user into their workspace and redirects to return_to (/app or a path under it).

Auth

partner token

Required Scopes

sso:handoff
Request Body
Field Type Required Description
return_to string No In-app path to land on; defaults to /app
external_user_id string Yes Marketplace user UUID
external_ref string Yes Workspace mapping key used at provisioning
Responses
201

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"}

403

Partner lacks sso:handoff. Body is {error: "insufficient_partner_scope"}

404

Body is {error: "identity_not_linked"}

422

Body is {error: "invalid_return_to"}: return_to must be /app or a path under it (/app/, /app?, /app#), printable ASCII, at most 255 characters, with no backslash

POST
/api/v1/partner/webhook_subscriptions partner token

Register a webhook subscription on a linked workspace

webhooks:manage

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 token

Required Scopes

webhooks:manage
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

201

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"}

403

Partner lacks webhooks:manage ({error: "insufficient_partner_scope"}), or the linked workspace is paused, archived or frozen ({error: "workspace_paused" | "workspace_archived" | "workspace_frozen"})

404

Body is {error: "identity_not_linked"}

409

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

POST
/api/v1/partner/engagements partner token

Open the engagement for one marketplace hiring

engagements:manage

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 token

Required Scopes

engagements:manage
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

201

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"}

403

Partner lacks engagements:manage ({error: "insufficient_partner_scope"}), or the linked workspace is paused, archived or frozen ({error: "workspace_paused" | "workspace_archived" | "workspace_frozen"})

404

Body is {error: "identity_not_linked"}

409

Body is {error: "engagement_closed"} when this external_engagement_ref was closed (a retried hiring needs a new ref), or {error: "idempotency_conflict"} when this external_engagement_ref is already bound to another external_ref's workspace

422

Body is {error: "invalid_external_ref"} (blank external_engagement_ref)

POST
/api/v1/partner/engagements/:id/tokens partner token

Mint a runtime token for an engagement

engagements:manage

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 token

Required Scopes

engagements:manage
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

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"}

403

Partner lacks engagements:manage. Body is {error: "insufficient_partner_scope"}

404

Body is {error: "engagement_not_found"}

409

Body is {error: "engagement_closed"} for a closed or revoked engagement, {error: "engagement_expired"} once expires_at has passed, or, when the partner is suspended, loses engagements:manage or is removed while the request is in flight, {error: "partner_suspended" | "partner_scope_revoked" | "partner_unavailable"}. PartnerAuth checks the key, not the engagement, so these arrive as 409 rather than 401/403.

422

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

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. Events are stored with origin partner, may use the hiring.status, hiring.message and hiring.artifact types, and keep their source_event_id as sent. An id beginning with runtime: is reserved for the runtime route and is counted as rejected.

Auth

partner token

Required Scopes

engagements:manage
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

Example
{
  "rejected": 0,
  "accepted": 3,
  "duplicates": 1
}
401

PartnerAuth failed. Body is {error: "invalid_partner_credential"}

403

Partner lacks engagements:manage ({error: "insufficient_partner_scope"}), {error: "engagement_mismatch"}, or the workspace is paused, archived or frozen ({error: "workspace_paused" | "workspace_archived" | "workspace_frozen"})

404

Body is {error: "engagement_not_found"}

409

Body is {error: "engagement_closed"}

413

Body is {error: "too_many_events"}

422

Body is {error: "invalid_events"}

POST
/api/v1/engagements/:engagement_id/events engagement token

Append runtime events to an engagement's trace

engagement:append

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. Events are stored with origin runtime and their source_event_id under an opaque runtime:sha512: digest, so a runtime's ids never meet the marketplace's; dedupe is per writer. An event whose event_type or name starts with hiring. (the marketplace's lifecycle vocabulary, any case) is counted as rejected. Metadata keys must be short identifiers, and a string value that is not a short label (no whitespace, <= 128 bytes) is stored only as {sha256, byte_size}; a name that is not one is replaced by the event type. One event's metadata keys and labels share a 512-byte budget, past which labels are fingerprinted and keys dropped. Errors are {error: code}, not RFC 9457. A paused or frozen workspace answers 503 with Retry-After: the token is still good, so keep the events and retry after that many seconds. Every 401 and 403 is terminal — stop exporting: 401 from the plug (invalid_token, or a state reached after the signature verified) and 403 from the controller (engagement_mismatch, insufficient_scope, or engagement_closed when the engagement closed during the request).

Auth

engagement token

Required Scopes

engagement:append
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

Example
{
  "rejected": 0,
  "accepted": 3,
  "duplicates": 1
}
401

{error: "invalid_token"} for a missing, forged or foreign credential; after the signature verified: "token_expired", "token_revoked", "engagement_closed" (closed, revoked or disconnected), "engagement_expired", "partner_suspended", "partner_scope_revoked", "partner_unavailable", "workspace_archived" or "workspace_unavailable". All terminal; stop exporting. A paused or frozen workspace is not among them: it answers 503.

403

{error: "engagement_mismatch"}, {error: "insufficient_scope"}, or {error: "engagement_closed"} when the engagement closed between authentication and the append

413

{error: "too_many_events"}

422

{error: "invalid_events"}, or the workspace state ("workspace_paused", "workspace_archived", "workspace_frozen") when it changed between authentication and the append; the next request answers 503 for paused or frozen and 401 for archived

503

{error: "workspace_paused"} or {error: "workspace_frozen"}, with a Retry-After header in seconds: 60, or the time until the freeze expires when that is sooner. An operator reverses both states, so the token stays valid; keep the events and retry.

GET
/api/v1/partner/engagements partner token

Reconcile marketplace engagements

engagements:manage

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 token

Required Scopes

engagements:manage
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

400

Body is {error: "invalid_cursor"} or {error: "invalid_status"}

401

Invalid partner credential

403

Insufficient partner scope

GET
/api/v1/partner/engagements/:id partner token

Read marketplace engagement status

engagements:manage

Description

Partner-scoped operational status including immutable runtime outcome and the separate commercial projection.

Auth

partner token

Required Scopes

engagements:manage
Parameters
Name In Type Required Description
id path string Yes
Responses
200

Engagement status

401

Invalid partner credential

403

Insufficient partner scope

404

Body is {error: "engagement_not_found"}

GET
/api/v1/partner/engagements/:id/commercial_events partner token

Reconcile immutable commercial outcome history

engagements:manage

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 token

Required Scopes

engagements:manage
Parameters
Name In Type Required Description
id path string Yes
after_revision query integer No
limit query integer No
Responses
200

Commercial event page

400

Body is {error: "invalid_revision"}

401

Invalid partner credential

403

Insufficient partner scope

404

Body is {error: "engagement_not_found"}

POST
/api/v1/partner/engagements/:id/commercial_events partner token

Record a commercial outcome transition

engagements:manage

Description

Appends an idempotent commercial event without changing the immutable runtime trace outcome.

Auth

partner token

Required Scopes

engagements:manage
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

201

Commercial event recorded

404

Body is {error: "engagement_not_found"}, or {error: "identity_not_linked"} once the workspace was disconnected

409

Body is {error: "idempotency_conflict"}: this external_event_id was already recorded with a different body

422

Body is {error: code} for an invalid state or transition

POST
/api/v1/partner/engagements/:id/close partner token

Finalize the trace and close the engagement

engagements:manage

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 token

Required Scopes

engagements:manage
Request Body
Field Type Required Description
reason string No Failure detail, <= 512 chars
status string No Legacy alias of runtime_outcome. Sending both with different values is refused with runtime_outcome_conflict.
ended_at string No ISO8601; defaults to now
runtime_outcome string No ok | error | partial; defaults to ok
Parameters
Name In Type Required Description
id path string Yes Engagement UUID
Responses
200

Engagement closed. The first close fixes the runtime outcome: closing again returns the stored one unchanged with requested_outcome_ignored true when the request asked for another.

Example
{
  "status": "closed",
  "trace_status": "ok",
  "engagement_id": "5b6c7d8e-9f01-4a4b-8c8d-555555555555",
  "runtime_outcome": "ok",
  "final_status": "ok",
  "requested_outcome_ignored": false,
  "runtime_outcome_immutable": true
}
401

PartnerAuth failed. Body is {error: "invalid_partner_credential"}

403

Partner lacks engagements:manage. Body is {error: "insufficient_partner_scope"}

404

Body is {error: "engagement_not_found"}

422

Body is {error: "runtime_outcome_conflict"} when status and runtime_outcome disagree; an outcome outside ok, error and partial is a problem JSON validation error

PUT
/api/v1/partner/runs/:external_swarm_ref partner token

Synchronize a purchased marketplace run

runs:manage

Description

PartnerAuth requires an active mpk_ key with runs:manage. Owner SSO, workspace, runtime append and viewer credentials never qualify. Send a complete flat snapshot, not a patch. No arbitrary metadata or provider identity is accepted. References are 1–255 ASCII bytes matching [a-zA-Z0-9][a-zA-Z0-9._:-]*. Statuses, phases, aliases and roles are partner-chosen labels matching \A[a-z][a-z0-9_]{0,31}\z, stored and shown verbatim. A run has 1–32 members with distinct child refs, unique aliases and contiguous positions from 0. Their external_child_ref must exactly equal the engagement's persisted external_engagement_ref under this partner, including any attempt suffix. Order in the JSON array is canonicalized by position. Purchased roster and hirer are immutable. Null engagement retains an existing binding; a later attachment must match the exact partner/child and cannot replace a binding or reparent a child. Equal revision/data replays; changed equal revision conflicts; older valid snapshots return current truth without mutation. Positive signed-64-bit revisions are monotonic. terminal_at alone marks a run terminal; a terminal run's status, phase and time cannot reopen or move. read_expires_at is terminal_at + 90 days and cannot be extended by retries. Partial commercial outcome is separate from telemetry_partial (derived from unavailable lanes). No workspace membership, commercial action or viewer session is created.

Auth

partner token

Required Scopes

runs:manage
Request Body
Field Type Required Description
status string Yes Run status: a label matching \A[a-z][a-z0-9_]{0,31}\z
members array<object> Yes Complete 1–32 ordered lanes. Every object requires external_child_ref, alias, role, position (0–31, contiguous), engagement_id (UUID or null), status, phase and telemetry_availability. Alias, role, status and phase (which may be null) are labels matching \A[a-z][a-z0-9_]{0,31}\z; aliases are unique within the run. Same availability vocabulary as run
partial boolean Yes Authoritative commercial execution partiality
phase string Yes Run phase: a label matching \A[a-z][a-z0-9_]{0,31}\z
revision integer Yes Positive monotonically increasing signed-64-bit revision
external_hirer_ref string Yes Immutable exact purchasing hirer reference
telemetry_availability string Yes pending, available, stale or unavailable
terminal_at string Yes UTC ISO8601 timestamp once the run is terminal; null otherwise. Alone marks the run terminal. Original authoritative clock, not receipt time
Parameters
Name In Type Required Description
external_swarm_ref path string Yes Stable partner-owned swarm reference, 1–255 ASCII bytes
Responses
200

Exact no-store object: id, external_swarm_ref, external_hirer_ref, revision, status, phase, partial, telemetry_availability, telemetry_partial, terminal_at, read_expires_at, members. Members contain exactly the eight snapshot lane fields, sorted by position. Dates are ISO8601 UTC or null. No partner/workspace IDs, trace metadata, tokens or internal digest.

401

{error: "invalid_partner_credential"} for absent, invalid, suspended or stale partner authority

403

{error: "insufficient_partner_scope"} without current runs:manage

409

{error: "snapshot_conflict"} for changed equal revision; {error: "binding_conflict"} for immutable hirer/roster, child reparenting, engagement replacement or terminal-clock change. No rows change

422

{error: "invalid_snapshot"} for incomplete/unknown fields, malformed shapes or invalid typed values; {error: "invalid_engagement_binding"} for foreign, missing or wrong-child engagements. Entire update rejected

GET
/api/v1/partner/runs/:external_swarm_ref partner token

Read a partner's own run acknowledgement

runs:manage

Description

PartnerAuth requires runs:manage, not runs:viewer_handoff or legacy partner scopes. Bounded own-run reconciliation only, not raw telemetry or viewer login. Always no-store. Partner suspension/withdrawal is rechecked transactionally.

Auth

partner token

Required Scopes

runs:manage
Parameters
Name In Type Required Description
external_swarm_ref path string Yes Stable partner-owned swarm reference, 1–255 ASCII bytes
Responses
200

Exact no-store object: id, external_swarm_ref, external_hirer_ref, revision, status, phase, partial, telemetry_availability, telemetry_partial, terminal_at, read_expires_at, members. Members contain exactly the eight snapshot lane fields, sorted by position. Dates are ISO8601 UTC or null. No partner/workspace IDs, trace metadata, tokens or internal digest.

401

{error: "invalid_partner_credential"} for absent, invalid, suspended or stale partner authority

403

{error: "insufficient_partner_scope"} without current runs:manage

404

{error: "run_not_found"} for foreign, malformed or missing references

POST
/api/v1/partner/runs/:external_swarm_ref/viewer_handoffs partner token

Mint a confirmed run-only viewer handoff

runs:viewer_handoff

Description

Requires current runs:viewer_handoff, not owner sso:handoff or runs:manage. Flat body contains exactly external_hirer_ref matching the stored purchaser. The calling marketplace must authenticate the exact hirer first. Hash-only, single-use run_viewer/robotscenter_monitor handoff expires at 120 seconds; GET only confirms, CSRF-protected POST exchanges for a separate read-only server session. Sessions expire at 8 hours absolute or 30 minutes idle, rechecking current run/partner epochs and terminal retention. No workspace membership or owner login changes. All responses no-store/no-referrer. Do not log or persist handoff_url. An unusable handoff lands on /monitor/expired, which links back only when Robots Center identifies an active partner with a configured https settings.viewer_return_url; otherwise it shows generic back-navigation text.

Auth

partner token

Required Scopes

runs:viewer_handoff
Request Body
Field Type Required Description
external_hirer_ref string Yes Exact stored purchasing hirer reference
Parameters
Name In Type Required Description
external_swarm_ref path string Yes Stable partner-owned swarm reference, 1–255 ASCII bytes
Responses
201

Exact object: handoff_url (absolute confirmation URL), expires_at (UTC ISO8601). No session secret, provider or workspace credentials

401

{error: "invalid_partner_credential"} for absent, invalid, suspended or stale partner authority

403

{error: "insufficient_partner_scope"} without the explicit current operation scope

404

{error: "run_not_found"} for foreign, malformed, missing or wrong-hirer bindings

410

{error: "invalid_or_expired"} when run viewer authority is revoked or terminal read retention expired

422

{error: "invalid_request"} for missing, unknown or malformed body fields

POST
/api/v1/partner/runs/:external_swarm_ref/viewer_revocations partner token

Revoke run-viewer authority

runs:manage

Description

Requires current runs:manage and an empty body. Idempotently marks run viewer authority revoked, bumps its epoch and notifies connected viewers. Stored and preminted handoffs/sessions fail. Does not close child ingestion, delete history, change commercial state or invalidate unrelated runs/owner sessions. No restore operation.

Auth

partner token

Required Scopes

runs:manage
Parameters
Name In Type Required Description
external_swarm_ref path string Yes Stable partner-owned swarm reference, 1–255 ASCII bytes
Responses
200

Exact object: {id: "<run UUID>", viewer_status: "revoked"}. Always no-store/no-referrer

401

{error: "invalid_partner_credential"} for absent, invalid, suspended or stale partner authority

403

{error: "insufficient_partner_scope"} without the explicit current operation scope

404

{error: "run_not_found"} for foreign, malformed, missing or wrong-hirer bindings

422

{error: "invalid_request"} for missing, unknown or malformed body fields

Where to go next

see also