API Reference
Base URL: https://inbox.dog
All endpoints accept and return JSON. CORS is enabled on all API and OAuth routes. Machine-readable spec: openapi.json
Authentication
Authenticated requests use your client_id and client_secret, obtained from POST /api/keys.
| Credential | Format | Usage |
|---|---|---|
| client_id | id_... | Query param or request body |
| client_secret | sk_... | Request body or X-Client-Secret header |
Never expose client_secret in client-side code.
Endpoints
/api/keys Create API key Create a new API key. Returns credentials and 10 free credits. 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",
"credits": 10
} /api/keys/{client_id} Get key info Retrieve API key details including remaining credits.
Headers
| X-Client-Secret | Required. Your client secret. |
Response 200
{
"client_id": "id_abc123...",
"name": "my-app",
"credits": 10,
"created_at": 1700000000000
} /oauth/token Exchange code for tokens Exchange an authorization code for access and refresh tokens. Costs 1 credit. 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"
} /oauth/token Refresh access token Use a refresh token to obtain a new access token. Free — no credit cost.
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
} /api/checkout Purchase credits Create a Stripe checkout session to purchase additional credits.
Request Body
{
"client_id": "YOUR_CLIENT_ID",
"client_secret": "YOUR_CLIENT_SECRET",
"credits": 100 // optional, defaults to 100
} Response 200
{
"checkout_url": "https://checkout.stripe.com/c/pay/...",
"session_id": "cs_live_..."
} Redirect the user to checkout_url to complete payment.
/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 |
|---|---|---|
| Read-only access (default) | gmail.readonly + userinfo.email | |
| email:read | Read-only access | gmail.readonly + userinfo.email |
| email:send | Send emails only | gmail.send + userinfo.email |
| email:full | Full access (read, send, modify) | gmail.modify + userinfo.email |
Rate Limits & Quotas
| Limit | Value | Notes |
|---|---|---|
| OAuth state TTL | 10 minutes | User must complete consent within this window |
| Authorization code TTL | 5 minutes | Exchange the code promptly after callback |
| Access token lifetime | 3600 seconds (1 hour) | Set by Google. Use refresh token to renew. |
| Credits per exchange | 1 credit | Only on POST /oauth/token with authorization_code |
| Token refresh cost | Free | No credit charge |
Billing
| Item | Cost |
|---|---|
| New API key | Free (includes 10 credits) |
| OAuth token exchange | 1 credit ($0.10) |
| Token refresh | Free |
| Additional credits | $0.10 per credit via Stripe |
| Self-hosted | Free (MIT license) |
Credits are only deducted on successful token exchanges. Failed flows, denied consent, and refreshes are free.