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:
- 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.
- The base URL for the environment you were given. Production Vision Core is
https://app.runonvision.com. See Environments. - 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.
Vision's developer platform is in preview. Token exchange is live in production, but most resource APIs are still restricted while their contracts are accepted. The API availability page shows what you can call today in each environment.
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
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.
As of 2026-11-03 the token exchange above works in production, but this route
still returns 404 in production and preview while the Platform read API
awaits acceptance. Check API availability before you build on it.
Today the most complete read path is the MCP server in the preview
environment.
List installed 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:
| Status | Body | What 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
429and 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.