Management APIs

Cloud Connect

Reference for the Cloud Connect operations of the Spice Cloud Management API: issue a Cloud Connect enrollment token, enroll a Cloud Connect cluster or standalone runtime, attach an existing project to an enrolled instance, and list projects available for Cloud Connect attachment.

OpenAPIapi.spice.ai/openapi.json

Issue a Cloud Connect enrollment token

POST/v1/cloud-connect/token

Issues a one-time standalone or cluster enrollment token. Requires a user-derived bearer, X-Org-Name, the kind-appropriate write scope, and org admin/owner role. Client-credential tokens are rejected because enrollment admission must retain user audit attribution.

Header parameters

NameTypeRequiredDescription
AuthorizationstringYes

Bearer <token>. Authentication lists the tokens it accepts.

X-Org-NamestringYes

Request body

Required

application/json

One of

kind: standaloneobject
  • kindstringRequired

    • Value: standalone
  • ttl_secondsinteger

    • Default: 3600
    • Minimum: 1
    • Maximum: 86400
kind: cluster, with nameobject
  • kindstringRequired

    • Value: cluster
  • namestringRequired

  • regionstring

  • cloud_account_idstring

  • cloud_providerstring

    • Value: aws
  • operations_modestring

    • Allowed values: managed, approval_required
  • ttl_secondsinteger

    • Default: 3600
    • Minimum: 1
    • Maximum: 86400
kind: cluster, with connection_idobject
  • kindstringRequired

    • Value: cluster
  • connection_idstringRequired

  • ttl_secondsinteger

    • Default: 3600
    • Minimum: 1
    • Maximum: 86400

Example request

curl -X POST "https://api.spice.ai/v1/cloud-connect/token" \
  -H "Authorization: Bearer <token>" \
  -H "X-Org-Name: <X-Org-Name>" \
  -H "Content-Type: application/json" \
  -d '{
    "kind": "standalone"
  }'

Responses

  • 201Created

    Enrollment token issued

    application/json

    • kindstringRequired

      • Allowed values: standalone, cluster
    • tokenstringRequired

      • Pattern: ^spice-enroll-[A-Za-z0-9_-]{32}$
    • expires_atstring (date-time)Required

    • organizationobjectRequired

      2 properties
      • idintegerRequired

      • namestringRequired

    • targetobject | nullRequired

      The created cluster or rotated connection identifier.

  • 400Bad Request

    Invalid request or missing organization assertion

  • 401Unauthorized

    Unauthorized

  • 403Forbidden

    Insufficient scope, role, or plan

  • 409Conflict

    Cluster has already enrolled

  • 413Content Too Large

    Request body too large

  • 429Too Many Requests

    Token issuance rate limit exceeded

  • 500Internal Server Error

    Internal token issuance failure

Enroll a Cloud Connect cluster or standalone runtime

POST/v1/cloud-connect/enroll

Token enrollment accepts a canonical kind-bound enrollment token. Standalone enrollment may instead use user Authorization plus X-Org-Name. Idempotency-Key is required for standalone enrollment.

Header parameters

NameTypeRequiredDescription
AuthorizationstringNo

Bearer <token>. Authentication lists the tokens it accepts.

Idempotency-Keystring (uuid)No
X-Org-NamestringNo

Required with Bearer authorization for authenticated standalone enrollment; omitted for token enrollment.

Request body

Required

application/json

One of

kind: standalone, with tokenobject
  • kindstringRequired

    • Value: standalone
  • tokenstringRequired

    • Pattern: ^spice-enroll-[A-Za-z0-9_-]{32}$
  • expected_orgstring

  • csr_pemstringRequired

  • enc_pubkey_pemstringRequired

  • instanceobjectRequired

  • regionstring

kind: clusterobject
  • kindstringRequired

    • Value: cluster
  • tokenstringRequired

    • Pattern: ^spice-enroll-[A-Za-z0-9_-]{32}$
  • expected_orgstring

  • csr_pemstringRequired

  • enc_pubkey_pemstringRequired

kind: standalone, without tokenobject
  • kindstringRequired

    • Value: standalone
  • csr_pemstringRequired

  • enc_pubkey_pemstringRequired

  • instanceobjectRequired

  • regionstring

Example request

curl -X POST "https://api.spice.ai/v1/cloud-connect/enroll" \
  -H "Content-Type: application/json" \
  -d '{
    "kind": "standalone",
    "token": "string",
    "csr_pem": "string",
    "enc_pubkey_pem": "string",
    "instance": {}
  }'

Responses

  • 200OK

    Enrollment completed or exactly replayed

    application/json

    One of

    kind: standaloneobject
    • kindstringRequired

      • Value: standalone
    • instance_idstringRequired

    • identity_cert_pemstringRequired

    • ca_bundle_pemstringRequired

    • gateway_addrstringRequired

    • not_afterstring (date-time)Required

    • organizationobjectRequired

      2 properties
      • idintegerRequired

      • namestringRequired

    • regionstringRequired

    • portalobjectRequired

      1 property
      • new_project_urlstring (uri)Required

    • attachmentnullRequired

    • recoveredbooleanRequired

    kind: clusterobject
    • kindstringRequired

      • Value: cluster
    • connection_idstringRequired

    • identity_cert_pemstringRequired

    • ca_bundle_pemstringRequired

    • gateway_addrstringRequired

    • not_afterstring (date-time)Required

    • organizationobjectRequired

      2 properties
      • idintegerRequired

      • namestringRequired

    • regionstringRequired

    • attachmentnullRequired

  • 400Bad Request

    Invalid request, kind mismatch, or unsupported project field

  • 401Unauthorized

    Invalid credential or authorization

  • 403Forbidden

    Authenticated caller lacks the required scope or organization role

  • 409Conflict

    Consumed token, connection already enrolled, unavailable connection, organization mismatch, or idempotency mismatch

  • 410Gone

    Enrollment token or authenticated recovery window expired

  • 413Content Too Large

    Request body too large

  • 500Internal Server Error

    Internal or identity-provider failure; use the retryable response field

Attach an existing project to an enrolled instance

POST/v1/cloud-connect/attach

Attaches an existing standalone project to an enrolled standalone instance and assigns the project's region and cname from the stamp whose gateway terminates that instance's control stream. The optional location field is reserved for multi-region use and is ignored today. This operation is dual-authorized. A user-derived bearer plus the X-Org-Name assertion authorizes the project mutation; OAuth client credentials are refused. The caller must have the instances:write and apps:write scopes and the organization admin or owner role. The cert_pem and pop_sig body fields prove only that the request concerns the named instance. Instance proof by itself never authorizes project attachment. pop_sig is a base64 DER ECDSA (SHA-256) signature over the UTF-8 bytes spice-cloud-connect/attach/v1\n{X-Org-Name}\n{instance_id}\n{project_id}. The project must already have kind standalone and no cluster target. The database is the authority for attachment conflicts; clients must not pre-check or infer an attachment limit from this contract. Errors use {code, error, retryable}. A 409 always has retryable: false; a 5xx has retryable: true so the client exact replays any request whose attachment may already have committed.

Header parameters

NameTypeRequiredDescription
AuthorizationstringYes

Bearer <token>. Authentication lists the tokens it accepts.

X-Org-NamestringYes

Organization that owns both the project and instance; also bound into pop_sig

  • Pattern: ^[A-Za-z0-9._-]{1,255}$

Request body

Required

application/json

  • instance_idstringRequired

    Enrolled instance caller-facing id (inst_…)

    • Minimum length: 1
    • Maximum length: 200
  • project_idintegerRequired

    Existing standalone project id

    • Minimum: 1
    • Maximum: 9007199254740991
  • locationstring

    Reserved for multi-region use; accepted and ignored today

    • Minimum length: 1
    • Maximum length: 200
  • cert_pemstringRequired

    Cloud Connect identity certificate for instance_id

    • Minimum length: 1
    • Maximum length: 8192
  • pop_sigstringRequired

    Base64 DER ECDSA signature over the documented attach challenge

    • Minimum length: 1
    • Maximum length: 512

Example request

curl -X POST "https://api.spice.ai/v1/cloud-connect/attach" \
  -H "Authorization: Bearer <token>" \
  -H "X-Org-Name: <X-Org-Name>" \
  -H "Content-Type: application/json" \
  -d '{
    "instance_id": "string",
    "project_id": 1,
    "cert_pem": "string",
    "pop_sig": "string"
  }'

Responses

  • 200OK

    Project attached, or exact same instance/project replay repaired

    application/json

    • instance_idstringRequired

    • organizationobjectRequired

      2 properties
      • idintegerRequired

      • namestringRequired

        Canonical organization name

    • projectobjectRequired

      2 properties
      • idintegerRequired

      • namestringRequired

        Canonical project name

    • monitor_urlstring (uri)Required

      Credential-free portal monitoring link for the project

      • Pattern: ^https://
  • 400Bad Request

    Invalid body or X-Org-Name (invalid_request or invalid_org_assertion)

    application/json

    • codestringRequired

      • Allowed values: invalid_request, invalid_org_assertion, unauthenticated, forbidden, org_forbidden, org_assertion_mismatch, org_deleted, invalid_instance_proof, instance_not_found, instance_not_enrolled, instance_already_attached, project_not_found, project_not_standalone, project_already_attached, internal
    • errorstringRequired

    • retryablebooleanRequired

  • 401Unauthorized

    Missing/invalid user bearer or invalid instance proof (unauthenticated or invalid_instance_proof)

    application/json

    • codestringRequired

      • Allowed values: invalid_request, invalid_org_assertion, unauthenticated, forbidden, org_forbidden, org_assertion_mismatch, org_deleted, invalid_instance_proof, instance_not_found, instance_not_enrolled, instance_already_attached, project_not_found, project_not_standalone, project_already_attached, internal
    • errorstringRequired

    • retryablebooleanRequired

  • 403Forbidden

    Non-user bearer, insufficient scope, org access, or role refusal (forbidden, org_forbidden, org_assertion_mismatch, or org_deleted)

    application/json

    • codestringRequired

      • Allowed values: invalid_request, invalid_org_assertion, unauthenticated, forbidden, org_forbidden, org_assertion_mismatch, org_deleted, invalid_instance_proof, instance_not_found, instance_not_enrolled, instance_already_attached, project_not_found, project_not_standalone, project_already_attached, internal
    • errorstringRequired

    • retryablebooleanRequired

  • 404Not Found

    Instance or project not found in the authorized organization (instance_not_found or project_not_found)

    application/json

    • codestringRequired

      • Allowed values: invalid_request, invalid_org_assertion, unauthenticated, forbidden, org_forbidden, org_assertion_mismatch, org_deleted, invalid_instance_proof, instance_not_found, instance_not_enrolled, instance_already_attached, project_not_found, project_not_standalone, project_already_attached, internal
    • errorstringRequired

    • retryablebooleanRequired

  • 409Conflict

    Instance not enrolled or already attached, project not standalone, or the database reports the project is already attached (instance_not_enrolled, instance_already_attached, project_not_standalone, or project_already_attached). These refusals carry retryable: false and prove this request did not commit an attachment.

    application/json

    • codestringRequired

      • Allowed values: invalid_request, invalid_org_assertion, unauthenticated, forbidden, org_forbidden, org_assertion_mismatch, org_deleted, invalid_instance_proof, instance_not_found, instance_not_enrolled, instance_already_attached, project_not_found, project_not_standalone, project_already_attached, internal
    • errorstringRequired

    • retryablebooleanRequired

  • 413Content Too Large

    Request body exceeds 1 MiB (invalid_request)

    application/json

    • codestringRequired

      • Allowed values: invalid_request, invalid_org_assertion, unauthenticated, forbidden, org_forbidden, org_assertion_mismatch, org_deleted, invalid_instance_proof, instance_not_found, instance_not_enrolled, instance_already_attached, project_not_found, project_not_standalone, project_already_attached, internal
    • errorstringRequired

    • retryablebooleanRequired

  • 500Internal Server Error

    Internal failure, including post-commit routing repair (internal, retryable)

    application/json

    • codestringRequired

      • Allowed values: invalid_request, invalid_org_assertion, unauthenticated, forbidden, org_forbidden, org_assertion_mismatch, org_deleted, invalid_instance_proof, instance_not_found, instance_not_enrolled, instance_already_attached, project_not_found, project_not_standalone, project_already_attached, internal
    • errorstringRequired

    • retryablebooleanRequired

List projects available for Cloud Connect attachment

GET/v1/cloud-connect/attachable-projects

Returns every project the authenticated caller may attach an enrolled Cloud Connect instance to. Policy is evaluated entirely by the server: today, results include only live, unattached standalone projects in the resolved organization, and user credentials require that organization's owner or admin role. Exactly one organization is searched per request and the response names it in org, so an empty projects states which organization has no eligible project rather than leaving a client to wonder whether the one it meant was searched at all; name another with X-Org-Name. Clients must render every returned project and instance without applying their own eligibility filters. The instances array is part of the stable contract and may be populated when server policy permits projects with existing attachments.

Query parameters

NameTypeRequiredDescription
limitintegerNo

Maximum number of projects to return.

  • Default: 50
  • Minimum: 1
  • Maximum: 100
cursorstringNo

Opaque cursor returned as next_cursor by the previous page.

Header parameters

NameTypeRequiredDescription
AuthorizationstringYes

Bearer <token>. Authentication lists the tokens it accepts.

X-Org-NamestringNo

Organization to list. A user token may name any organization its owner belongs to; naming one they do not is org_forbidden. Never ignored: a token bound to one organization that names another is org_assertion_mismatch. A portal session token is bound to none and must send it (org_assertion_required).

  • Pattern: ^[A-Za-z0-9._-]{1,255}$

Example request

curl "https://api.spice.ai/v1/cloud-connect/attachable-projects" \
  -H "Authorization: Bearer <token>"

Responses

  • 200OK

    A page of projects currently eligible for attachment.

    application/json

    • orgstringRequired

      Handle of the organization the page was scoped to, being the one X-Org-Name named or the credential's own when it named none. Always present, so an empty projects says which organization has no eligible project rather than leaving a client to guess whether its active organization was the one searched.

    • projectsarray of objectRequired

      5 properties
      • idinteger (int64)Required

      • namestringRequired

      • orgstringRequired

        Organization handle.

      • regionstring | nullRequired

        Project control-plane region, if assigned.

      • instancesarray of objectRequired

        3 properties
        • idstringRequired

          Instance external identifier.

        • locationstring | nullRequired

          Customer-declared instance location.

        • enrolled_atstring (date-time) | nullRequired

    • next_cursorstring | nullRequired

      Opaque cursor for the next page, or null at the end.

  • 400Bad Request

    Invalid organization assertion (invalid_org_assertion), none from a portal session (org_assertion_required), or invalid limit/cursor (invalid_pagination).

  • 401Unauthorized

    Missing or invalid bearer token.

  • 403Forbidden

    Organization access (org_forbidden, org_assertion_mismatch, or org_deleted), apps:read scope (insufficient_scope), or owner/admin role (forbidden) was refused.

  • 500Internal Server Error

    Organization role, project, or organization-handle lookup failed.