Hosted gateway

Read a hosted gateway sign-on request by its user code (signed-in customer)

POST
/v1/hosted-gateway/authorizations/lookup

What the approval page shows: the tenant and its host, the upstream origin, the operator who asked, when it expires, exactly what the gateway records (disclosure), and the signed-in user's workspaces with whether each can take the key by the rules the database answers (ADMIN or above, a paid plan, API access); Accounts' entitlement is asked at approval. The owner email is shown in full only to that owner, and workspaces are listed only for them. Never returns the device code.

A POST so the user code is never in a URL (and so never in a request log line), from the page itself: Sec-Fetch-Site: same-origin (or, without it, the web application's own Origin) and a JSON body, as approve requires.

Authorization

AccountSessionCookie
decionis_account_session<token>

The signed HttpOnly account session the web app holds after sign-in (also accepted as a Bearer acct_ token).

In: cookie

Request Body

application/json

user_code*string
Lengthlength <= 32

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

application/json

curl -X POST "https://example.com/v1/hosted-gateway/authorizations/lookup" \  -H "Content-Type: application/json" \  -d '{    "user_code": "BCDF-GHJK"  }'
{  "authorization": {    "authorization_id": "be63c26c-03c0-4635-ae2b-58f14bd033f9",    "status": "pending",    "user_code": "string",    "tenant_label": "string",    "tenant_host": "string",    "upstream_origin": "string",    "owner_email": "string",    "requested_by": {      "name": "string"    },    "requested_at": "2019-08-24T14:15:22Z",    "expires_at": "2019-08-24T14:15:22Z",    "org_id": "a40f5d1f-d889-42e9-94ea-b9b33585fc6b"  },  "disclosure": {    "statement": "string",    "evaluated_methods": [      "POST",      "PUT",      "PATCH",      "DELETE"    ],    "metering": "string",    "refusals": "string",    "recorded": [      "method"    ],    "json_body_max_bytes": 0,    "header_values_recorded": [      "Content-Type",      "Idempotency-Key"    ],    "never_recorded": [      "other request headers",      "response bodies"    ],    "key": {      "name": "string",      "role": "string",      "scopes": [        "string"      ],      "power": "string"    },    "disconnect": "string"  },  "approver": {    "email": "string",    "email_matches": true,    "session_org_id": "a051a9ed-5c73-492a-a0ba-3ff5805fe4af"  },  "workspaces": [    {      "org_id": "a40f5d1f-d889-42e9-94ea-b9b33585fc6b",      "name": "string",      "role": "OWNER",      "plan_code": "string",      "paid": true,      "eligible": true,      "refusal": "HOSTED_GATEWAY_ADMIN_REQUIRED"    }  ],  "pricing_url": "http://example.com"}

Poll a hosted gateway sign-on for its workspace key (fleet operator) POST

The operator's poll, with the same Entra token as the start: a device code redeems only for the operator who started it. Until the customer decides, it answers `authorization_pending` (or `slow_down`, with a 5 s wider `interval`, when polled sooner than the interval allows). Once approved, the next poll first applies approval's workspace rules again (the approver ADMIN or above, a paid plan, an active entitlement); a workspace that no longer qualifies denies the authorization (`access_denied` with a `reason`), and Accounts being unreachable answers 503 `temporarily_unavailable` to retry, nothing minted. Otherwise it mints the key in the same transaction that consumes the authorization and makes it the tenant's current key (one per organization and tenant label), and returns it exactly once: a MEMBER key named `agentsafe-hosted-<tenant_label>` with scopes `["decision:shadow"]`, created by the approver. The key expires at `confirm_by` (10 minutes) unless the holder calls POST /v1/hosted-gateway/keys/confirm with it, so a key whose delivery was never confirmed does not stay active. The tenant's earlier keys (`replaced_key_ids`) stay live until that confirmation revokes them, except one that was itself never delivered, which is revoked now; a new key that is lost in transit never leaves the tenant without one. Later polls answer `invalid_grant`. Sixty polls per minute per operator.

Approve a hosted gateway sign-on into one of the customer's workspaces POST

From the page itself: the request must carry `Sec-Fetch-Site: same-origin` (`same-site` is refused: the session cookie reaches every subdomain) or, without it, an `Origin` that is the web application's own (the web proxy forwards the browser's headers), and a JSON body (415 JSON_CONTENT_TYPE_REQUIRED otherwise, so no form can send it). The session must come from a sign-in that proved its email (an email code, a password, Accounts, or an OAuth provider that asserted the address verified; otherwise 403 VERIFIED_EMAIL_REQUIRED, sign in again), that email must equal the request's owner email (case-insensitive), and the user must be ADMIN or above in `org_id`, a workspace on a paid plan (`org_entitlements.plan_code`; a Stripe subscription in `trialing` counts as its plan) whose entitlement Accounts holds active, all read at approval. On success the session is bound to `org_id` (a new account-session cookie is set when it was bound elsewhere), so the console's key list and billing show the workspace that now holds the gateway's key.