Authentication
Bearer-token auth. Two issuance paths, one verification layer.
Every request to /api/public/v1/* must carry an Authorization: Bearer … header. Pick the issuance path that matches your integration:
| Token kind | Prefix | Best for |
|---|---|---|
| Personal Access Token (PAT) | aibk_pat_… | Server-side scripts, CI, internal tools |
| Sandbox PAT | aibk_pat_test_… | Local development, integration tests |
| OAuth access token | aibk_oat_… | Partner apps that act on behalf of users |
Personal Access Tokens
Mint from Console → API Tokens. The raw value is shown once at creation — copy it then. Subsequent listings only show the label prefix (e.g. aibk_pat_a1b2c3d4…).
Single-org vs multi-org
PATs are single-org by default — hard-bound to the org you minted them from. Cross-org calls are refused.
Tick “All my orgs” at mint time for a multi-org PAT. The token is bound to you, not a single org; every API call must pass ?organization_id=<id> to pick which org to target. The server confirms the user has an active membership in that org on every call.
OAuth 2.0 (Authorization Code + PKCE)
Use this when end-users grant your app access to their AI Books data — Zapier-style integrations, partner connectors, third-party dashboards.
Register an app
Go to Console → OAuth Apps, click Register, set your redirect URI(s). You'll get a client_id and a one-time client_secret. Treat the secret like a password — never commit it.
Authorize
GET /oauth/authorize
?response_type=code
&client_id=<your_client_id>
&redirect_uri=<your_redirect_uri>
&code_challenge=<S256(verifier)>
&code_challenge_method=S256
&scope=AIBooks.contacts.READ AIBooks.invoices.READ
&state=<csrf_token>Omit organization_id for a multi-org token (pick the active org via the query param on each call), or pass it to bind the issued token to a single org.
Exchange the code
POST /oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code=<auth_code>
&redirect_uri=<your_redirect_uri>
&code_verifier=<verifier>
&client_id=<your_client_id>
&client_secret=<your_client_secret>Response:
{
"access_token": "aibk_oat_…",
"refresh_token": "aibk_ort_…",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "AIBooks.contacts.READ AIBooks.invoices.READ"
}Refresh
Access tokens live for 1 hour. Trade the refresh token for a new pair before then:
POST /oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token
&refresh_token=aibk_ort_…
&client_id=<your_client_id>
&client_secret=<your_client_secret>Refresh tokens are single-use. Each rotation mints a new (access, refresh) pair. Replaying an already-rotated refresh revokes the entire token family and forces re-authorization — this detects stolen-token reuse.
Scopes
Scope strings follow the pattern:
AIBooks.<resource>.<OP> # e.g. AIBooks.invoices.READ
AIBooks.<resource>.ALL # all ops on a resource
AIBooks.fullaccess.all # wildcard — everythingOAuth apps declare a maximum scope list at registration; users can narrow at consent time but cannot exceed it.