Any language
On this page
Outlet's server side is six calls over HTTPS. Any language can make them. The npm and Python packages wrap these same calls.
Direct needs none of them. The user's Direct API key goes from your app to the provider.
- App ID
- From useoutlet.dev/register.
- App secret
- From useoutlet.dev/register.
- Return address
- The address Outlet sends the user back to. Registered with the app.
- Base URL
- https://api.useoutlet.dev
Start
Create a Vault connection request and send the user to its grant URL.
curl -X POST https://api.useoutlet.dev/v0/grants \
-H "content-type: application/json" \
-H "x-outlet-app-secret: apps_yourappsecret" \
-d '{
"app_id": "app_yourapp",
"providers": ["openai"],
"requested_cap_usd": 10
}'
{
"grantRequestId": "grant_7cef7de3250245d1a88c6c9e2b41023e",
"grantUrl": "https://useoutlet.dev/grant/grant_7cef7de3250245d1a88c6c9e2b41023e"
}
Public client, no app secret:
curl -X POST https://api.useoutlet.dev/v0/grants \
-H "content-type: application/json" \
-d '{
"app_id": "app_yourapp",
"providers": ["openai"],
"requested_cap_usd": 10,
"redirect_uri": "https://yourapp.com/outlet/return",
"code_challenge": "Fl4GxMhZXnSPlTxaLWt77AvuJC6j1W7TsnixwlRjAdw",
"code_challenge_method": "S256",
"state": "YHRerIAgPKqREIx4KwaPCQ"
}'
{
"grant_request_id": "grant_7cef7de3250245d1a88c6c9e2b41023e",
"grant_url": "https://useoutlet.dev/grant/grant_7cef7de3250245d1a88c6c9e2b41023e"
}
Wait
Poll the request until the user approves. The answer holds the Vault App key.
curl https://api.useoutlet.dev/v0/grants/grant_7cef7de3250245d1a88c6c9e2b41023e \ -H "x-outlet-app-secret: apps_yourappsecret"
While pending:
{
"status": "pending"
}
After approval:
{
"status": "complete",
"grantId": "grant_7cef7de3250245d1a88c6c9e2b41023e",
"keys": {
"openai": "sk-svcacct-…"
},
"capUsd": 10,
"expiresAt": "2026-09-26T21:15:00.000Z"
}
Exchange
Public clients without an app secret exchange the code and the PKCE verifier instead.
curl -X POST https://api.useoutlet.dev/v0/grants/token \
-H "content-type: application/json" \
-d '{
"grant_request_id": "grant_7cef7de3250245d1a88c6c9e2b41023e",
"code": "kP9XbiMwt569W7g01d8ufYbpfGvfswvvoZ1VmF10DIA",
"code_verifier": "nfOUVZs_vIiRQ_d2Smi3CYcx-D1-kTeTAdxwcarmUuE"
}'
{
"status": "complete",
"grantId": "grant_7cef7de3250245d1a88c6c9e2b41023e",
"keys": {
"openai": "sk-svcacct-…"
},
"capUsd": 10,
"expiresAt": "2026-09-26T21:15:00.000Z",
"refresh_token": "rt_WPdTGLgzWnYqEksm-Kh_APx28Rkq1qovKzFOjCr1nVQ"
}
Refresh
Get the current key again. The refresh token rotates; keep the new one.
curl -X POST https://api.useoutlet.dev/v0/grants/grant_7cef7de3250245d1a88c6c9e2b41023e/refresh \ -H "x-outlet-app-secret: apps_yourappsecret"
{
"status": "complete",
"grantId": "grant_7cef7de3250245d1a88c6c9e2b41023e",
"keys": {
"openai": "sk-svcacct-…"
},
"capUsd": 10,
"expiresAt": "2026-09-26T21:30:00.000Z"
}
Public client, no app secret:
curl -X POST https://api.useoutlet.dev/v0/grants/grant_7cef7de3250245d1a88c6c9e2b41023e/refresh \ -H "authorization: Bearer rt_WPdTGLgzWnYqEksm-Kh_APx28Rkq1qovKzFOjCr1nVQ"
{
"status": "complete",
"grantId": "grant_7cef7de3250245d1a88c6c9e2b41023e",
"keys": {
"openai": "sk-svcacct-…"
},
"capUsd": 10,
"expiresAt": "2026-09-26T21:30:00.000Z",
"refresh_token": "rt_SNQl9c3K-g8kteF9SQMjH1bUNw8fE_uy_4CP81DZ4kA"
}
Status
A pure read. active, capped, revoked or pending, and the month's spend. Never a key.
curl https://api.useoutlet.dev/v0/grants/grant_7cef7de3250245d1a88c6c9e2b41023e/status \ -H "x-outlet-app-secret: apps_yourappsecret"
{
"grantId": "grant_7cef7de3250245d1a88c6c9e2b41023e",
"status": "active",
"providers": [
"openai"
],
"capUsd": 10,
"spendUsd": 0.42
}
Public client, no app secret:
curl https://api.useoutlet.dev/v0/grants/grant_7cef7de3250245d1a88c6c9e2b41023e/status \ -H "authorization: Bearer rt_SNQl9c3K-g8kteF9SQMjH1bUNw8fE_uy_4CP81DZ4kA"
{
"grantId": "grant_7cef7de3250245d1a88c6c9e2b41023e",
"status": "active",
"providers": [
"openai"
],
"capUsd": 10,
"spendUsd": 0.42
}
Revoke
End the connection from the app's side.
curl -X DELETE https://api.useoutlet.dev/v0/grants/grant_7cef7de3250245d1a88c6c9e2b41023e \ -H "x-outlet-app-secret: apps_yourappsecret"
{
"ok": true
}
Public client, no app secret:
curl -X DELETE https://api.useoutlet.dev/v0/grants/grant_7cef7de3250245d1a88c6c9e2b41023e \ -H "authorization: Bearer rt_SNQl9c3K-g8kteF9SQMjH1bUNw8fE_uy_4CP81DZ4kA"
{
"ok": true
}
When a connection ends
Status answers capped or revoked. A capped connection comes back when the user raises the Vault cap; call Refresh then. A revoked one needs the user to connect again.