Quickstart

Exchange a server-side client credential for a short-lived access token, then call Vision with only the scopes your operation needs. This page takes about five minutes.

Before you begin

You need three things:

  1. A client ID and secret. An owner or administrator makes an API key in Vision under Settings → Developer, picks where it runs and what it can do, and copies the secret, which is shown once. See API keys.
  2. The base URL for the environment you were given. Production Vision Core is https://app.runonvision.com. See Environments.
  3. A server. Client credentials belong on a trusted server. Never put them in browser JavaScript, a mobile app, a repository, a log, or an AI prompt.

Request a token

Send form-encoded client credentials to the token endpoint. JSON bodies are rejected. You can send the credentials in the body (shown) or as HTTP Basic authentication.

Exchange client credentials

POST
/oauth/token
curl https://app.runonvision.com/oauth/token \
  --request POST \
  --header 'content-type: application/x-www-form-urlencoded' \
  --data-urlencode 'grant_type=client_credentials' \
  --data-urlencode "client_id=$VISION_CLIENT_ID" \
  --data-urlencode "client_secret=$VISION_CLIENT_SECRET" \
  --data-urlencode 'scope=vision.apps:read'

Response

{
  "access_token": "eyJhbGciOiJFUzI1NiIsImtpZCI6...",
  "token_type": "Bearer",
  "expires_in": 300,
  "scope": "vision.apps:read"
}

Tokens last at most 300 seconds and there is no refresh token: request a new one shortly before expires_in runs out, and reuse it for every call until then. To call an App directly (for example To-Do), add resource=<the App's audience>; the token is then bound to that one App. See Authentication.

Make your first call

List the Apps your client may use.

List installed Apps

GET
/vision-core/v1/apps
curl https://app.runonvision.com/vision-core/v1/apps \
  --header "authorization: Bearer $TOKEN" \
  --header 'accept: application/json'

Every response carries an x-request-id header (req_...). Log it: it is the fastest way to get help with a failed call.

Handle errors

The token endpoint uses the OAuth 2.0 error format. These are real responses from production:

StatusBodyWhat to do
400{"error":"invalid_request","error_description":"Use application/x-www-form-urlencoded."}Send a form-encoded body, not JSON.
400{"error":"unsupported_grant_type"}Use grant_type=client_credentials.
400{"error":"invalid_scope"}Ask only for scopes granted to the client.
401{"error":"invalid_client"}Wrong ID or secret, or the client was revoked or rotated. Do not retry.
429{"error":"temporarily_unavailable"}Too many exchanges. Cache tokens; wait and retry.

Resource APIs use a JSON error envelope that differs slightly per App while the platform is in preview. See Errors.

Production checklist

  • Request only the scopes the operation needs.
  • Cache the access token in server memory and refresh it about 30 seconds before it expires; never exchange per request.
  • Set connection and total timeouts on every call.
  • Retry only 429 and errors marked "retryable": true, with exponential backoff and jitter.
  • Send an idempotency key on every command so a retry cannot create a duplicate. See Idempotency.
  • Store the client secret in a secret manager. Rotate it with an overlap window, and revoke it at once if it may have leaked.