Skip to main content

API keys

An API key authenticates your account. No redirect, no consent screen, no expiring access token — which makes it the right credential for your own backend, and the wrong one to put anywhere a customer could read it.

Create one​

In the admin center: Integrations → API Keys.

SettingNotes
NameFor your own reference. Required.
ScopesWhat the key may do — see Scopes. Select only what the integration needs.
ExpiryRequired. There is no never-expiring key. You are emailed before it lapses.
OwnersAccount users notified about this key's expiry, and shown as responsible for it. Defaults to whoever created it. At least one is required.
Allowed IPsOptional allowlist of exact IPs or CIDR blocks. If set, requests from anywhere else are refused.
Limit it to specific objectsOptional resource grants. The flow picker appears once flows:call is ticked; it is only used by the flow call trigger.

Scopes to select for the whole API​

Every endpoint on this API accepts a key — there is no OAuth-only endpoint. A key reaches an endpoint only if it carries that endpoint's scope, so a key meant to do everything needs all twelve:

webhooks:read webhooks:write
sms:read sms:send sms:write
messages:read messages:write
users:read reports:read recordings:read
fax:read fax:send

The admin center renders this list from the server, so it is always current — GET /api/v1/api-keys/scopes is where it comes from, and a scope we add appears there without a portal release.

:::danger A key with no scopes selected reaches nothing It does not default to "everything" — it defaults to flows:call, the flow call-trigger scope, which no REST endpoint uses. Every request returns 403 insufficient_scope. Select scopes explicitly. :::

Scopes are fixed at creation and are not extended automatically. When we add an endpoint that needs a new scope, existing keys 403 on it until their owner edits the key and selects it.

The key is displayed once, at creation. Store it in your secret manager immediately — we keep only a hash and cannot show it to you again. If you lose it, reissue.

Send it​

curl https://api.account.telebroad.com/api/public/v1/sms/lines \
-H "Authorization: Bearer tbk_live_…"

Authorization: Bearer is the only accepted header. There is no X-API-Key fallback — the same header carries an OAuth token, so your HTTP layer needs one code path either way. (The one exception is the flow call trigger, outside this API, which also reads X-API-Key. Use Authorization there too.)

What a key can reach​

A key is checked on six things. All six must pass:

  1. The key exists and matches its stored hash.
  2. It has not been revoked.
  3. It has not expired.
  4. It carries the scope the endpoint requires.
  5. The request's source IP is in the allowed IPs, if any are set.
  6. The object it names is within the key's resource grants, if any are set.

Without resource grants, a key gets the whole account, within its scopes — there is no user role narrowing it, because a key authenticates an account rather than a person. GET /users returns every user; GET /sms/lines returns every SMS-capable number.

Resource grants: narrowing a key to specific objects​

A scope says what a key may do. A grant says which objects it may do it to.

{
"scopes": ["sms:send", "messages:read"],
"resources": {
"mode": "selected",
"grants": [
{ "type": "number", "id": "12125550188" },
{ "type": "number", "id": "12125550199" }
]
}
}

That key can text and read messages on those two numbers and nothing else, even though the account owns forty. Ask for GET /api/v1/api-keys/resource-types for the current list of grantable types — today flow, number, hha and phone.

A number grant may name a texting number, a fax line or a voice number. It limits which lines a key may text from, read messages on and act on conversations for, and which fax lines it may send faxes from and read faxes on. It is one list for all of them, so a key granted only a fax line is also limited to that line for SMS. On the fax endpoints a grant narrows the role of the user the key runs as; it never adds a number that role does not have. See Faxes.

A number grant also limits caller ID. A key with number grants may only show one of those numbers as the caller ID on a call it places with POST /calls. It may name any number of the account: a texting number, a fax line or a voice number.

Phones: required for placing calls​

A phone grant names a phone (line) the key may ring first with POST /calls, for example {"type": "phone", "id": "6589455"}. Each phone must be a phone of your account; it does not have to belong to the user the key runs as.

A key with calls:make must list its phones. Unlike every other type, no phone grants does not mean unrestricted: a key with no phones selected cannot place calls, and every POST /calls gets 403 permission_denied ("this API key has no phones it may ring; add phones to the key to place calls"). See Click to call.

modeMeaning
allNo restriction. The default, and what every key created before this feature means.
selectedThe grants apply. At least one grant is required.

:::caution Grants apply per type, not globally Under selected, a type with grants is restricted to them, and a type with no grants is unrestricted.

So a key granted two flows and no numbers is limited on flows and reaches every number — and a key granted only numbers can still call every flow, if it holds flows:call. That is deliberate: the alternative would mean pinning a key to a flow silently removed its messaging access, and every resource type we add later would break every existing key.

To restrict a type, grant at least one object of it.

The one exception is phone: with no phone grants, a key cannot place calls at all. See Phones. :::

A flow grant names a flow by its id — the number at the end of the flow editor's address. It is enforced by the flow call trigger: a key with flow grants may call only those flows, and never a flow on another account, whatever its grants say.

An hha grant names one of the account's HHA Exchange connections by its id. A key with hha grants looks callers up only in those connections, and only in connections the user it runs as may already use; a grant never adds one.

Grants are validated when you save them. A flow, number or phone that is not on your account is rejected there and then, rather than stored as a grant that can never match anything. A number may be a texting number, a fax line or a voice number.

flowId still works​

The older flowId field is the same idea in its original one-flow shape, and keys and clients still using it are unaffected — it is read as {"type": "flow", "id": "…"}. If you send both, resources wins, because it is the one that can express what flowId cannot. Prefer resources for anything new; flowId cannot describe two flows, or a number.

:::info This is changing A key will run as its owner, so the owner's admin-center role applies on top of the scopes — the same rule OAuth already follows:

effective access = key scopes ∩ owner's role

When it ships, a key whose owner lacks a permission loses the matching access, and this page will say so plainly. Nothing has changed yet; what is documented above is what the API does today. :::

One thing no key unlocks: if the account has sensitive-content re-verification enabled, call recordings are unavailable over the API entirely. That gate wants a live human at a browser, and there is nothing a machine credential can present. See Recordings.

Rotate a key​

Reissue keeps the key's identity — same name, scopes, IP allowlist, owners — and mints a new secret with a fresh expiry.

:::caution There is no grace period The old secret stops working the moment the new one is issued. Deploy the new secret first, or accept the gap. If you need overlapping validity, create a second key, migrate, then revoke the first. :::

A revoked key cannot be reissued — revocation is final. Create a new key instead.

Revoke a key​

Revoking takes effect on the next request. Do it immediately if a key is exposed — in a log, a git commit, a screenshot, a support ticket.

Because a key carries the whole account within its scopes, a leaked key is an account-level incident, not a per-user one. Revoke first, investigate second.

Keeping a key safe​

  • Server-side only. Never in a browser bundle, a mobile app, or anything shipped to a customer.
  • One key per integration. Shared keys cannot be revoked without breaking everything at once, and the audit trail cannot tell you which system acted.
  • Narrow scopes. An export job does not need sms:send. See Scopes.
  • Narrow resources. A key that texts from one number should be granted that one number. A leaked key is then limited to it — see Resource grants.
  • Use the IP allowlist when the caller has a stable egress address. It is the one control that survives the key itself leaking.
  • Never log the key. Log its prefix (tbk_live_ab…) if you need to correlate.

Audit trail​

Writes made with a key are recorded with source api and the key's id, so an account owner can tell a portal action from an integration's. Reads are not audited — an entry per number-picker refresh would bury the writes that matter.

Rate limits​

None are enforced today, on keys or otherwise. The per-key call-limit fields are not applied to this API. See Rate limits before you build on that.