Hosted gateway

Start a hosted gateway sign-on for a paying tenant (fleet operator)

POST
/v1/hosted-gateway/authorizations

Device-authorization grant (RFC 8628 shaped) by which a paying tenant of the AgentSafe hosted gateway fleet receives its workspace key without anyone copying one. The fleet operator (Tenant.py) starts it with a Microsoft Entra access token for api://decionis-operator/Operator.Act whose roles holds the operator role; who asked (oid, sign-in name) is recorded from the verified token, never from the body, and a body naming a requester is refused. The customer then approves at verification_uri_complete while signed in to Decionis as owner_email by a sign-in that proved that address, ADMIN or above in a workspace on a paid plan with an active entitlement, and the operator polls the token endpoint. Codes live 30 minutes; poll every interval seconds. Twenty starts per hour per operator. Without Entra configuration (DECIONIS_OPERATOR_ENTRA_TENANT_ID, DECIONIS_OPERATOR_ENTRA_CLIENT_ID, and a well-formed DECIONIS_OPERATOR_ENTRA_CLIENT_APPS when set) every call answers 503 OPERATOR_AUTH_NOT_CONFIGURED.

Authorization

OperatorEntraAuth
AuthorizationBearer <token>

A fleet operator's Microsoft Entra v2 access token for the "Decionis Operator API" app registration (Application ID URI api://decionis-operator), as az account get-access-token --scope api://decionis-operator/Operator.Act returns it: issuer https://login.microsoftonline.com//v2.0, audience the app's client id, scp holding Operator.Act, roles holding HostedGateway.Operator (or DECIONIS_OPERATOR_ENTRA_ROLE), and azp Azure CLI (04b07795-8ddb-461a-bbee-02f9e1bf7b46) or a client DECIONIS_OPERATOR_ENTRA_CLIENT_APPS names (403 OPERATOR_CLIENT_NOT_ALLOWED otherwise), verified against the tenant's JWKS. The app registration should make Operator.Act admin-consent only and require assignment on its enterprise application.

In: header

Request Body

application/json

tenant_label*string

The tenant id in the fleet registry; www, api, status, admin and console are reserved.

Match^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$
tenant_host*string

Where the tenant is served, <tenant_label>.<fleet domain>.

Lengthlength <= 253
upstream*string

The tenant's upstream, https without credentials, query or fragment; its origin is what the customer is shown and approves.

Lengthlength <= 2048
owner_email*string

Only a signed-in user with exactly this email (case-insensitive) may approve or deny.

Formatemail
Lengthlength <= 320
max_embedded_body_bytes?integer

The tenant's embedding limit, so the approval page states it exactly.

Range1 <= value <= 16777216
Default65536

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

curl -X POST "https://example.com/v1/hosted-gateway/authorizations" \  -H "Content-Type: application/json" \  -d '{    "tenant_label": "acme",    "tenant_host": "acme.decionisedge.com",    "upstream": "https://api.acme.example",    "owner_email": "user@example.com"  }'
{  "authorization_id": "be63c26c-03c0-4635-ae2b-58f14bd033f9",  "device_code": "string",  "user_code": "string",  "verification_uri": "https://decionis.com/connect/edge",  "verification_uri_complete": "https://decionis.com/connect/edge?code=BCDF-GHJK",  "expires_in": 1800,  "interval": 5}

Grant a workspace capacity for more hosted gateways (fleet operator) POST

The fleet operator, with their own Microsoft Entra token (GatewayOperations.py limit), sets how many hosted gateways the workspace may hold, from 1 to 10. Core locks the workspace, refuses a limit below the gateways it already holds, and records the verified operator and the reason in hosted_gateway.limit.changed. It changes neither billing nor any customer consent, and accepts no operator identity, plan or workspace key from the body. Twenty calls per hour per operator.

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.