Skip to main content

Overview

Every request to the Recoup API must be authenticated using exactly one of two mechanisms:
MethodHeaderUse case
API Keyx-api-keyServer-to-server integrations
Access TokenAuthorization: Bearer <token>Frontend apps authenticated via Privy
Providing both headers in the same request will result in a 401 error.

API Keys

API keys are the primary way to authenticate programmatic access to the Recoup API.

Creating an API Key

  1. Navigate to chat.recoupable.com/keys
  2. Enter a descriptive name (e.g. "Production Server")
  3. Click Create API Key
Copy your API key immediately — it is only shown once. Keys are stored as a secure HMAC-SHA256 hash and cannot be retrieved after creation.

Using an API Key

Pass your key in the x-api-key header:
curl -X GET "https://api.recoupable.com/api/tasks" \
  -H "x-api-key: YOUR_API_KEY"

Access Tokens (Privy)

If you’re building a frontend application that authenticates users via Privy, you can pass the user’s Privy JWT as a Bearer token instead of an API key.
curl -X GET "https://api.recoupable.com/api/tasks" \
  -H "Authorization: Bearer YOUR_PRIVY_JWT"
The API validates the token against Privy, extracts the user’s email, and resolves it to the corresponding Recoup account. Bearer tokens always authenticate as a personal account — they cannot act on behalf of an organization.

Personal vs. Organization API Keys

API keys inherit the type of account they were created under.

Personal API Keys

  • Created by a standard user account
  • Can only access your own account’s data
  • orgId is null on the resolved auth context

Organization API Keys

  • Created by an organization account (an account that has members)
  • Can access data for any member account within the organization
  • orgId is set to the organization’s account ID
An account is recognized as an organization when it has at least one member in the account_organization_ids table.

How We Determine Key Type at Creation

When a key is created under an account, the API checks whether that account has any organization members:
Has members in account_organization_ids?
  ├── Yes → Organization API Key (orgId = accountId)
  └── No  → Personal API Key    (orgId = null)
This check happens at authentication time (not creation time), so key behavior automatically reflects the current state of the account.

How We Verify Access on API Calls

Every authenticated request goes through validateAuthContext, which enforces the following access rules:

Personal API Key or Bearer Token

Can only access their own account. Attempting to pass an account_id belonging to another account returns 403 Forbidden.

Organization API Key

Can access any account that is a member of the organization:
Request includes account_id override?
  ├── Same as key owner → Allowed (self-access)
  ├── Is a member of the org → Allowed
  └── Not a member → 403 Forbidden
Membership is verified by querying the account_organization_ids table for a record linking the target account to the organization.
The Recoup internal admin organization has universal access to all accounts.

Organization Access via organization_id

Some endpoints accept an organization_id parameter. When provided, the API additionally validates that the authenticated account is either:
  • A member of the organization, or
  • The organization account itself

Error Responses

StatusCause
401Missing or invalid credentials, or both x-api-key and Authorization headers provided
403Valid credentials but insufficient access to the requested account_id or organization_id

Security Notes

  • API keys are never stored in plaintext — only an HMAC-SHA256 hash (keyed with your project secret) is persisted in the database
  • Never include account_id in your API key creation request — the account is always derived from your authenticated credentials
  • Rotate keys immediately if compromised via the API Keys Management Page