Getting started
Developer platform
Sign in, register apps, hold credentials, and read usage, request logs and limits at platform.tabbio.com.
Everything you own as a developer lives at platform.tabbio.com: your apps and their credentials, your API keys, who has connected to you, what you called and how it went, and the limits you are working inside. The documentation you are reading is separate and public; the platform is yours and signed in.
It moved
Credentials used to live inside the Tabbio app under Settings > Developer. They do not any more. The Tabbio app keeps only the two surfaces a person needs: the consent screen and Settings > Connected apps, where they manage what they have shared with you.
Signing in
Open the platform
Go to platform.tabbio.com. You are asked for an email and a password, or you can ask for a sign-in code by email instead.
Use your Tabbio account, or make a login
A developer is a Tabbio account. If you already use Tabbio, sign in with it and you are in. If you do not, choose Create a login and make one with your work address. Either way the account is the owner of everything you create next, so use an address your team still controls in two years.
Name yourself
The first sign-in asks for a display name, and optionally your organisation, website and a contact address. The contact address is what Tabbio writes to about a limit, a deprecation or an incident, so keep it a mailbox somebody reads.
Applications
Applications is the list of everything you have registered, with its client id, type, status, key count, connection count and requests over the last seven days.
An app carries:
- Client id (
tbo_ci_). Public. It identifies you in an authorization request and is safe in a browser bundle or a mobile binary. - Client secrets (
tbo_cs_). Confidential clients only. A secret is shown once, at creation, and stored hashed. Nobody at Tabbio can read it back to you. - Redirect URIs. Matched exactly. A trailing slash,
httpagainst a registeredhttps, or an extra query parameter is a different URI and is refused. - Allowed scopes. The ceiling on what the app may ask a person for. Asking for
anything outside it fails with
OAUTH_INVALID_SCOPE.
Rotating a secret
The Credentials tab creates a second secret alongside the first, so you deploy the new one and then delete the old one. There is no overlap window to configure and no downtime if you do it in that order. Delete the old secret as soon as the new one is live: two working secrets is twice the surface.
API keys
API keys (tbo_sk_) are for the partner API, where there is no person in the loop. They
are created per app, and the API keys page lists every key across all of your apps
with the app it belongs to, its scopes, when it was last used and how many requests it
served in the last seven days.
| Field | Type | Description |
|---|---|---|
| Scopes | Required | Company scopes only. A key can never carry a user scope, so it can never read a CV that was shared with your app through consent. |
| Expiry | Optional | Set one for a trial or a contractor integration. An expired key answers |
| Name | Editable | Rename a key at any time. The secret does not change. |
| Revoke | Immediate | Takes effect on the next request. There is no grace period, so deploy the replacement first. |
The key is shown once, in full, at creation. If you lose it, create another and revoke the old one; it cannot be shown again.
One key per environment, at least
Sharing a key between staging and production means an incident in one is an incident in both, and revoking becomes a decision instead of a reflex. A key per customer is reasonable too when you resell the integration.
Connections
A connection is one person who went through the consent screen for one of your apps. The Connections tab on an app shows what you already have access to, and nothing more.
| Field | Type | Description |
|---|---|---|
| Connection id | Always | The id your access and refresh tokens belong to. |
| Granted scopes | Always | What they actually approved, which can be less than you asked for. |
| CV shared | Always | Whether they picked a CV to share, and nothing about its contents. |
| Connected and last used | Always | When it started and when your app last called with it. |
| Name | With profile | Their display name, only when they granted the |
There is no email address, no CV content and no browsing history here. Revoking a connection from the platform is the same act as the person revoking it in Settings > Connected apps: the tokens stop working immediately and any durable CV link dies with them. Use it when a customer offboards, not as a way to force a re-consent.
Usage
Usage is the graph of what you called and how it went, over the last 24 hours, 7 days, 30 days or 90 days. Every request is counted, including the ones that failed before your code was reached, which is the point: a 401 loop is invisible in your own logs if the token never got as far as your handler.
Each request is filed under one outcome.
| Field | Type | Description |
|---|---|---|
| success | 2xx, 3xx | It worked. |
| client_error | 4xx | Malformed, not found, or refused by a rule. Yours to fix. |
| auth_error | 401, 403 | A dead credential or a missing scope. Usually one bad deployment, not a pattern. |
| rate_limited | 429 | You hit a limit. See below. |
| server_error | 5xx | Ours. If it persists, mail us with a request id. |
Alongside the graph: p50 and p95 latency, so a slow endpoint shows up before a customer reports it, a breakdown by app, endpoint or credential, and Export CSV for the range you are looking at when you want it in your own spreadsheet.
Request log
Logs is the individual requests, newest first, kept for 30 days. Filter by app, outcome, endpoint, status, credential or date, and open a row to see everything stored about it: method, route, status, error code, latency, which credential was used and which connection it belonged to.
The log stores route templates, never bodies, query strings, tokens or raw IP addresses. That is deliberate: a request to a durable CV link carries a live credential in its path, and a log that keeps those is a credential store nobody asked for.
Every /v1 and /oauth response carries an x-request-id header, failures included.
Paste it into the log filter to find the exact request. It is also the first thing
support asks for.
const response = await fetch(`${issuer}/v1/companies`, {
headers: { Authorization: `Bearer ${apiKey}` },
});
if (!response.ok) {
// Log it next to your own trace id: it is what turns "it failed at some point
// this morning" into one row on the platform.
console.error("tabbio request failed", {
status: response.status,
requestId: response.headers.get("x-request-id"),
});
}Limits
Limits shows the plan you are on, the numbers that apply to you, what you have spent today and when each window resets.
| Plan | Requests per minute | Requests per day | Who gets it |
|---|---|---|---|
| Standard | 300 | 20,000 | Every developer account starts here. No request needed. |
| Elevated | 1,000 | 200,000 | Granted on request once your integration is live. |
| Custom | Set by Tabbio | Set by Tabbio | Agreed for a volume integration. The platform shows the numbers you were given. |
Limits are per developer account, not per app or per key: every app you own draws on one
budget, on every /v1 resource route. Two windows run at once, a rolling minute and a
UTC day, and each answers 429 with its own code.
| Code | HTTP | Meaning |
|---|---|---|
RATE_LIMIT_EXCEEDED | 429 | You are over the per-minute limit for your developer account. meta.retryAfter is the seconds to wait. |
QUOTA_EXCEEDED | 429 | You have spent the daily quota for your developer account. meta.retryAfter counts down to the next UTC midnight. |
DEVELOPER_ACCOUNT_SUSPENDED | 403 | The account is suspended, so every app it owns is refused. Mail developers@tabbio.com. |
Read where you stand from the response headers rather than guessing.
| Header | What it carries |
|---|---|
x-ratelimit-limit | Requests allowed in the current minute. |
x-ratelimit-remaining | Requests left in the current minute. |
x-ratelimit-reset | Epoch seconds at which the minute window resets. |
x-quota-limit | Requests allowed in the current UTC day. |
x-quota-remaining | Requests left today. |
x-quota-reset | Epoch seconds at the next UTC midnight. |
x-request-id | On every /v1 and /oauth response, failures included. The platform's request log is keyed on it, and support asks for it first. |
To ask for more, mail developers@tabbio.com from the contact address on your account with what you call, how often, and why the volume is what it is. Errors and rate limits has the per-surface burst tiers that sit underneath these, and the backoff to write.
Account settings
Settings holds your display name, organisation, website and contact address, a password change, and sign out everywhere for when a laptop goes missing. Deleting the Tabbio account itself is done in the Tabbio app, and it takes your apps with it, so transfer anything a customer depends on first.