Authentication

Authorization: Bearer sk_sinter_...

API keys

  • Created on the Dashboard page after signing in, or by a device login.
  • Shown once. Store it in an environment variable, such as SINTER_API_KEY.
  • Never put a key in files, prompts or logs. Anything done with a key is done by its account.
  • Revoke a key on the Dashboard page.
  • Not needed for GET /v1/materials, POST /v1/device/start and POST /v1/device/token.

Scopes

ScopeAllows
quotesUpload models; read, requote, claim and withdraw quotes; price delivery.
ordersRead and cancel orders.
purchaseAccept quotes and open their checkout. Only when the account owner turns on Allow purchases for the key or agent.
  • New keys and device logins get quotes and orders. purchase only when asked for and allowed.
  • Keys made before purchase existed can’t accept. Make a new key with Allow purchases.
  • A person signed in on the site has every scope.
HTTPMeaning
401Missing, wrong or revoked key.
403The key lacks the scope.

Device login

1. Start

curl -sS -X POST https://sinter.systems/v1/device/start \
  -H "Content-Type: application/json" \
  -d '{"name": "Claude Code on laptop", "scopes": ["quotes", "orders"]}'

200

{
  "device_code": "...",
  "user_code": "WDJB-MJHT",
  "verification_url": "https://sinter.systems/device",
  "verification_url_complete": "https://sinter.systems/device?code=WDJB-MJHT",
  "expires_in": 600,
  "interval": 5
}
  • scopes: any of quotes, orders, purchase. Default quotes and orders. Ask for purchase only to buy for the user; the person approving decides whether to grant it.
  • Keep device_code private.

2. Approve

Give the user verification_url_complete, or verification_url and user_code. They sign in and approve the code.

3. Poll for the key

Every interval seconds:

curl -sS -X POST https://sinter.systems/v1/device/token \
  -H "Content-Type: application/json" \
  -d '{"device_code": "..."}'

200 once approved

{
  "api_key": "sk_sinter_...",
  "key": { "name": "Claude Code on laptop", "prefix": "sk_sinter_ab12", "scopes": ["quotes", "orders"] }
}

api_key is shown once. key.scopes is what the person granted, which may be fewer than asked for.

400 errorMeaning
authorization_pendingNot approved yet. Keep polling.
slow_downPolling too fast. Wait longer.
access_deniedDenied. Final.
expired_tokenExpired after 10 minutes. Final; start again.
invalid_grantUnknown or already used code. Final.

Signed-in person only

  • API keys get 403.
  • GET /v1/keys, POST /v1/keys, DELETE /v1/keys/{key_id}
  • POST /v1/billing/portal
  • GET /v1/device/{user_code}, POST /v1/device/{user_code}/approve, POST /v1/device/{user_code}/deny

OAuth for MCP

The MCP server at https://quote.sinter.systems/mcp uses OAuth 2.1. MCP clients discover it, register and open the approval page; the user signs in to Sinter and approves. No API key is needed. An API key also works: Authorization: Bearer sk_sinter_....

Protected resource metadata
https://quote.sinter.systems/.well-known/oauth-protected-resource
Authorization server metadata
https://quote.sinter.systems/.well-known/oauth-authorization-server
Registration
Dynamic (RFC 7591) or a client ID metadata document URL.
PKCE
S256
Access token
1 hour. Accepted only by /mcp, never by /v1.
Refresh token
30 days. Rotates on every use; a reused one ends the connection.

Scopes

  • The API key scopes: quotes, orders, purchase.
  • A client that names no known scope gets quotes and orders. Unknown scopes are ignored.
  • purchase only when the client asks for it and the user ticks Allow purchases on the approval page. Unticked by default.
  • No scope pays: a purchase is paid at its checkout link.

Revoking

  • The user revokes a connected app under Dashboard → Devices. Its tokens stop working at once.
  • A client revokes its refresh token at https://quote.sinter.systems/oauth/revoke (RFC 7009).

See MCP.