---
title: "Poll a device authorization"
method: POST
path: "/v1/auth/device/poll"
tags: ["Account"]
---

# Poll a device authorization

`POST /v1/auth/device/poll`

## Request

- Base URL: `https://api.spacefast.com`
- URL: `https://api.spacefast.com/v1/auth/device/poll`
- Auth: none declared

Polls a pending device login at the advised interval and redeems the one-time API key once the user approves.

## Request body

- object
  - `deviceCode` string, required: Device code returned by POST /v1/auth/device. Body-only, never a URL.

## Response `200`

Response for status 200

- object
  - `$schema` string, uri: Canonical JSON Schema URL for this response body. The server also sends it in the `Link: rel="describedby"` response header.
  - `data` object, required
    - `status` 'pending' | 'approved' | 'denied' | 'expired' | 'consumed', required: Device authorization state. `approved` carries the one-time API key exactly once, then the record is `consumed`.
    - `apiKey` object: The minted API key including its one-time `secret`. Present only on the first poll after approval.
      - `id` string, required: API key id.
      - `name` string, nullable, required: Human-readable key name.
      - `tenantId` string, nullable, required: Tenant the key belongs to.
      - `mode` 'live' | 'test', required: `test` when the key belongs to a linked test tenant, `live` otherwise.
      - `subject` object, nullable, required: Subject the key acts as.
        - `type` 'user' | 'team' | 'external' | 'system', required: Subject kind the key acts as in audit records.
        - `id` string, required: Stable subject id.
      - `ownerPrincipal` object, nullable, required: Owning principal (ownership metadata, never the authorization gate).
        - `type` 'team' | 'external', required: Principal type that owns this key.
        - `id` string, required: Stable principal id (Better Auth team id, or external id).
      - `createdByUserId` string, nullable, required: User who created the key, or null for automation. Tenant-key creators are recorded for audit and do not own the key's authority.
      - `collection` 'team' | 'tenant', required: Disjoint resource collection this key addresses.
      - `preset` 'ci_deploy' | 'space_publisher' | 'space_admin' | 'domain_manager' | 'team_admin' | 'billing_viewer' | 'partner_admin', nullable, required: Preset compiled into a concrete access policy when the key is created.
      - `teamScope` union, required: Membership-following team scope for a device-login key, or null for legacy keys.
        - object
          - `mode` 'all', required
        - object
          - `mode` 'teams', required
          - `teamIds` string[], required
        - object
          - `mode` 'none', required
      - `policy` object, nullable, required: IAM-lite access policy evaluated for every credentialed request.
        - `version` '2026-06-09', required: Must be the current platform policy version.
        - `statements` object[], required: Evaluation order: explicit deny wins, explicit allow permits, otherwise implicit deny.
          - `effect` 'allow' | 'deny', required: Explicit deny always wins over allow.
          - `actions` string[], required: Actions this statement covers.
          - `resources` string[], required: Resource URIs this statement covers (wildcards cover subtrees).
          - `conditions` object: AND condition attributes. Unresolvable attributes fail closed: no match for allow, and match for deny.
            - `request.client` 'dashboard' | 'cli' | 'api' | 'worker': Restricts the statement to one resolved request client.
      - `metadata` object, required: Caller-supplied metadata.
      - `secretPreview` string, required: Masked secret preview (prefix and last characters).
      - `secret` string: Full secret. Returned once, at creation only.
      - `notBefore` string, date-time, nullable, required: Key is rejected before this instant.
      - `expiresAt` string, date-time, nullable, required: Key is rejected from this instant.
      - `ipAllowlist` string[], nullable, required: CIDR/IP allowlist. Requests from other addresses are rejected.
      - `revokedAt` string, date-time, nullable, required: Revocation instant.
      - `enabled` boolean, required: Whether the key currently authenticates.
      - `createdAt` string, date-time, required: Creation instant.
      - `updatedAt` string, date-time, required: Last update instant.
      - `lastRequestAt` string, date-time, nullable, required: Last authenticated request instant.
    - `access` object: What was granted, in the words the approval page used. Present alongside `apiKey`.
      - `profile` 'read' | 'agent' | 'agent-personal-pages', nullable, required: Access profile the granted scopes exactly match, or null for a customized grant.
      - `scopes` string[], required: Exact scopes the approver granted. The one authoritative description.
      - `teams` union, required: Team access the approver granted.
        - object
          - `mode` 'all', required
        - object
          - `mode` 'teams', required
          - `teamIds` string[], required
        - object
          - `mode` 'none', required
    - `claimedSpaceId` string, nullable: Space claimed during approval, when the device flow was started by `sf spaces claim`.

## Other responses

- `default`: Problem details (RFC 9457). Any 4xx/5xx response is one `application/problem+json` document.

---

[API](https://skmtc.dev/spacefast/apis/spacefast-api.md) · [All operations](https://skmtc.dev/spacefast/apis/spacefast-api/llms.txt) · [OpenAPI document](https://skmtc.dev/spacefast/apis/spacefast-api/revisions/bd165bc7c983?raw)
