← Docs

API Reference

Base URL: https://inbox.dog

All endpoints accept and return JSON. CORS on /api/* and /oauth/* is restricted to origins in the ALLOWED_ORIGINS env var (open if unset). MCP and /.well-known routes allow all origins. Machine-readable spec: openapi.json

Authentication

Authenticated requests use your client_id and client_secret, obtained from POST /api/keys.

Credential Format Usage
client_idid_...Query param or request body
client_secretsk_...Request body or X-Client-Secret header

Never expose client_secret in client-side code.

Endpoints

POST /api/keys Create API key

Create a new API key. No authentication required.

Request Body

{
  "name": "my-app"  // optional, defaults to "default"
}

Response 200

{
  "client_id": "id_abc123...",
  "client_secret": "sk_xyz789...",
  "name": "my-app",
  "redirect_uris": []
}
GET /api/keys/{client_id} Get key info

Retrieve API key details.

Headers

X-Client-Secret Required. Your client secret.

Response 200

{
  "client_id": "id_abc123...",
  "name": "my-app",
  "created_at": 1700000000000
}
POST /api/device/code Start device auth (CLI/agent)

Get an auth URL for CLI/agent flows. Uses inbox.dog's hosted code display page as the redirect — no callback server needed. See CLI & Agent Auth guide.

Request Body

{
  "client_id": "id_...",
  "client_secret": "sk_...",
  "scope": "email:full"  // optional, defaults to "email"
}

Response 200

{
  "auth_url": "https://inbox.dog/oauth/authorize?client_id=id_...&redirect_uri=https%3A%2F%2Finbox.dog%2Fconnect%2Foauth&scope=email%3Afull",
  "redirect_uri": "https://inbox.dog/connect/oauth",
  "expires_in": 600
}
GET /oauth/authorize Start OAuth flow

Redirects the user to Google's consent screen.

Query Parameters

Parameter Required Description
client_idYesYour API key client ID
redirect_uriYesURL to redirect after authentication
scopeNoPermission scope. Default: email
stateNoOpaque value for CSRF protection, passed back in redirect
promptNoGoogle consent screen behavior. Defaults to consent (always shows consent & returns refresh token)

Callback

After consent, the user is redirected to:

https://yourapp.com/callback?code=AUTH_CODE&state=YOUR_STATE
POST /oauth/token Exchange code for tokens

Exchange an authorization code for access and refresh tokens. Auth codes expire after 5 minutes.

Request Body

{
  "code": "AUTH_CODE_FROM_CALLBACK",
  "client_id": "YOUR_CLIENT_ID",
  "client_secret": "YOUR_CLIENT_SECRET"
}

Response 200

{
  "access_token": "ya29.a0AfH6...",
  "refresh_token": "1//0eXyz...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "email": "user@example.com"
}
POST /oauth/token Refresh access token

Use a refresh token to obtain a new access token.

Request Body

{
  "grant_type": "refresh_token",
  "refresh_token": "YOUR_REFRESH_TOKEN",
  "client_id": "YOUR_CLIENT_ID",
  "client_secret": "YOUR_CLIENT_SECRET"
}

Response 200

{
  "access_token": "ya29.a0AfH6...",
  "token_type": "Bearer",
  "expires_in": 3600
}
POST /oauth/revoke Revoke a session token

Revoke an MCP session token. Requires client credentials to prove ownership. Returns 200 regardless of whether the token existed (per RFC 7009). Accepts JSON or application/x-www-form-urlencoded.

Request Body

{
  "token": "mcp_...",
  "client_id": "id_...",
  "client_secret": "sk_..."
}

Response 200

{ "revoked": true }
GET /health Health check

Check if the service is running.

Response 200

{ "status": "ok", "service": "inbox.dog-oauth" }

Scopes

Pass the scope parameter to /oauth/authorize to control Gmail permissions.

Scope Gmail Permission Google Scope
emailRead-only access (default)gmail.readonly + userinfo.email
email:readRead-only accessgmail.readonly + userinfo.email
email:sendSend emails onlygmail.send + userinfo.email
email:fullFull access (read, send, modify)gmail.modify + userinfo.email

Rate Limits & Quotas

Limit Value Notes
OAuth state TTL10 minutesUser must complete consent within this window
Authorization code TTL5 minutesExchange the code promptly after callback
Access token lifetime3600 seconds (1 hour)Set by Google. Use refresh token to renew.
POST /api/keys5/min per IPKey creation
POST /oauth/register10/min per IPDynamic client registration
POST /oauth/token20/min per IPToken exchange and refresh
GET /api/tokens20/min per IPToken retrieval
POST /mcp60/min per IPMCP JSON-RPC calls