Skip to content

CLI And Headless Clients

Use this profile for single-user automation clients such as CLIs, local scripts, agents, and other headless tools.

When To Use This Path

Choose this profile if your client:

  • Cannot safely store a client secret.
  • Needs a good login experience without a redirect listener.
  • Represents one Beyond user automating their own account.

This profile is intentionally different from partner integrations:

  • Each personal automation app is bound to exactly one Beyond user.
  • Device approval must be performed by that same user.
  • Delegated tokens are always user-bound.

Flow Overview

The device grant avoids putting a client secret on the user’s machine. The user approves access in a browser while your client polls the token endpoint. Longer-lived access uses refresh tokens (see Step 4).

sequenceDiagram
    participant Client as AutomationClient
    participant Device as DeviceAuthorizationEndpoint
    participant User as UserBrowser
    participant Token as OAuthTokenEndpoint
    participant API as PartnersAPI

    Client->>Device: POST /o/device-authorization/ client_id, scope
    Device-->>Client: device_code, user_code, verification_uri, interval
    Client->>User: Display user_code and verification URL
    User->>User: Approve requested scopes at Beyond
    loop Poll until authorized or expired
        Client->>Token: POST /o/token/ device_code grant
        Token-->>Client: authorization_pending or tokens
    end
    Client->>API: GET /api/v1/... Authorization Bearer access_token
    Note over Client,Token: Refresh access with grant_type=refresh_token

If Beyond has provisioned a personal access token for your personal app instead, you skip /o/* at runtime and send Authorization: Bearer bpat_… on API calls. See Authentication for when to use a PAT versus this device flow.

Setting Value
App mode personal
Client type public
Grant device_code
Access token lifetime 1 hour
Refresh token lifetime 30 days, rotated on refresh

Step 1: Start Device Authorization

curl -X POST $BASE_URL/o/device-authorization/ \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "scope=listings:read user:read"

Response

{
  "device_code": "d3vice-c0de",
  "user_code": "ABCD-EFGH",
  "verification_uri": "https://v2.beyondpricing.com/oauth/device",
  "verification_uri_complete": "https://v2.beyondpricing.com/oauth/device?user_code=ABCD-EFGH",
  "expires_in": 300,
  "interval": 5
}

Show the user_code and verification_uri_complete to the user in your CLI or app.

Step 2: User Approves The Request

The user opens the verification URL in their browser. If they are not already signed in to Beyond, they will be prompted to log in first. Once authenticated, they review the requested scopes and approve or deny the request.

Step 3: Poll For Tokens

curl -X POST $BASE_URL/o/token/ \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=urn:ietf:params:oauth:grant-type:device_code" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "device_code=DEVICE_CODE_FROM_STEP_1"

Poll at the interval returned by the device authorization response. Once approved, the token response includes an access token and refresh token.

Step 4: Refresh For Long-Lived Access

curl -X POST $BASE_URL/o/token/ \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=refresh_token" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "refresh_token=YOUR_REFRESH_TOKEN"

Always persist the newest refresh token returned by the refresh response.

Personal App Rules

  • user_id is not accepted on personal app token requests.
  • The authorizing user must match the app's bound user.
  • Tokens issued through this flow are automatically bound to that user.
  • If the wrong Beyond user tries to approve the request, approval is rejected.

Security Notes

  • Device codes are short-lived and single-use.
  • Refresh tokens rotate on every refresh.
  • Request only the scopes your automation needs.
  • Prefer device authorization for interactive sign-in. Use a personal access token only when an explicit credential-scoped PAT has been provisioned for non-interactive automation.

Next Steps