BluetickedDeveloper docs

Businesses

5 endpoints, each with examples that open in the console prefilled.

All resources
GET/api/v1/businesses/{id}/keysbusinesses:writeTry in console

List credentials you issued to a customer

List only keys minted by the calling API key for this business. Secrets and hashes are never returned.

Query parameters
limitstring
cursorstring
  • Requires businesses:write on an organization-wide API key. Another key in the same workspace cannot list keys you minted. Session-created and older keys with no minter attribution remain managed through the dashboard.
  • Includes active, expired and revoked keys. expires_at and revoked_at can be null. limit defaults to 50, maximum 100; pass next_cursor as cursor for the next page. next_cursor is null when has_more is false.
  • SDK listKeys support follows in the next SDK release; call this REST endpoint until then. To replace a credential, mint a new one, deploy it, then revoke the old one. There is no in-place API rotation endpoint.
curl -X GET "https://app.blueticked.com/api/v1/businesses/{id}/keys?limit=50" \
  -H "Authorization: Bearer $BLUETICKED_API_KEY"
Response
{
  "data": [
    {
      "id": "44444444-4444-4444-9444-444444444444",
      "name": "Acme reporting",
      "prefix": "blu_live_z9y",
      "scopes": [
        "contacts:read"
      ],
      "created_at": "2026-10-15T00:00:00.000Z",
      "expires_at": "2027-01-01T00:00:00.000Z",
      "revoked_at": "2026-10-15T01:00:00.000Z"
    }
  ],
  "has_more": true,
  "next_cursor": "44444444-4444-4444-9444-444444444444",
  "request_id": "req_b2e3d610e10f1b07468721ee98f0e1d2"
}
DELETE/api/v1/businesses/{id}/keysbusinesses:writeTry in console

Revoke a credential you issued to a customer

Revoke one key minted by the calling API key for this business, preserving its audit history.

Query parameters
key_idstring
  • key_id is required and must be a UUID. The business must belong to this workspace and the key must have been minted by this exact caller for that business; all other keys return 404.
  • Idempotent: an already-revoked matching key returns 200 with already_revoked:true, preserving its original revocation timestamp and writing no duplicate audit event.
  • SDK revokeKey support follows in the next SDK release; call this REST endpoint until then. Keys created in the dashboard or before minter attribution was recorded must be managed in the dashboard.
curl -X DELETE "https://app.blueticked.com/api/v1/businesses/{id}/keys" \
  -H "Authorization: Bearer $BLUETICKED_API_KEY"
Response
{
  "id": "44444444-4444-4444-9444-444444444444",
  "revoked": true,
  "already_revoked": false,
  "request_id": "req_b2e3d610e10f1b07468721ee98f0e1d2"
}
GET/api/v1/businessesbusinesses:readTry in console

List your customers

List the businesses in this workspace, one per customer you have onboarded.

  • A key restricted to one business sees only that business here, so it is safe to hand this scope to the per-customer keys you issue.
  • Reconcile against your own customer records with the id you stored at create time. We do not hold your identifiers.
curl -X GET "https://app.blueticked.com/api/v1/businesses" \
  -H "Authorization: Bearer $BLUETICKED_API_KEY"
Response
{
  "data": [
    {
      "id": "22222222-2222-4222-9222-222222222222",
      "name": "Acme Dental",
      "slug": "acme-dental",
      "timezone": "Africa/Johannesburg",
      "is_default": false,
      "created_at": "2026-08-09T10:00:00.000Z"
    }
  ],
  "request_id": "req_b2e3d610e10f1b07468721ee98f0e1d2"
}
POST/api/v1/businessesbusinesses:writeTry in console

Onboard a customer

Create a business for one of your customers, and optionally mint a credential scoped to it in the same call.

Body parameters
namerequiredstring
create_keyobject
  • When another business costs money on your plan, nothing is created until you accept its price. The first request answers 403 plan_limit_reached with reason business_charge_required and details.billing: unit_zar_cents (a month), part_zar_cents (the rest of this billing period) and charged_now (whether that part goes on the card on file now, or the next renewal bills it). Send the same request again with accept_business_charge: { monthly_zar_cents: <unit_zar_cents> }. If the price moved in between, the answer is business_charge_changed with today's price, and still nothing is created. A blu_test_ key cannot add a business that costs money (business_charge_live_key_required).
  • billing in the answer is the price you accepted, or null when adding the business cost nothing (no paid plan, a trial, a plan that includes it).
  • The whole onboarding is now machine-driven: create the business, mint its key, send it a connect link, and wait for channel.connected. No step needs a human in our dashboard.
  • create_key accepts true to copy this key's own scopes, or an object to name the key and narrow its scopes. Minting it here rather than in a second call means a failure cannot strand a business you have no credential for.
  • api_key.key is returned ONCE and is never retrievable. Store it before you respond to your own caller.
  • The minted key is always pinned to that one business, never carries businesses:write, and can only hold scopes your key holds. Its environment is inherited from yours: a blu_test_ key mints only blu_test_ keys.
  • The key doing the creating must be organization-wide. A key already restricted to a business cannot create more, or a per-customer credential would become a master one.
  • Slugs are derived from the name and de-duplicated automatically, so two customers may share a name without colliding.
curl -X POST "https://app.blueticked.com/api/v1/businesses" \
  -H "Authorization: Bearer $BLUETICKED_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Acme Dental",
  "create_key": {
    "name": "Acme Dental (production)",
    "scopes": [
      "messages:send",
      "contacts:write"
    ]
  }
}'
Response
{
  "id": "22222222-2222-4222-9222-222222222222",
  "organization_id": "2706d599-3078-45f1-abbf-4c6ba1ed8d63",
  "name": "Acme Dental",
  "slug": "acme-dental",
  "timezone": "Africa/Johannesburg",
  "is_default": false,
  "api_key": {
    "id": "33333333-3333-4333-9333-333333333333",
    "prefix": "blu_live_a1b",
    "scopes": [
      "contacts:write",
      "messages:send"
    ],
    "key": "blu_live_a1b2c3d4e5f6g7h8i9j0k"
  },
  "billing": {
    "unit_zar_cents": 29900,
    "part_zar_cents": 14950,
    "charged_now": true
  },
  "request_id": "req_b2e3d610e10f1b07468721ee98f0e1d2"
}
POST/api/v1/businesses/{id}/keysbusinesses:writeTry in console

Issue a credential for a customer

Mint an API key restricted to one existing business, for rotation, or a second narrower key.

Body parameters
namestring
scopesstring[]
expires_in_daysnumber
monthly_spend_cap_randsnumber
  • {id} is the business id returned when you created the customer.
  • Use this to rotate a customer's credential after a leak: mint the replacement, deploy it, then revoke the old one. There is no window where that customer cannot send.
  • monthly_spend_cap_rands is the per-customer spend guardrail. All customers draw on your one workspace wallet, so a cap per key is what stops one customer's runaway loop from spending another's headroom.
  • Omit scopes to copy your own. Anything you do not hold is dropped rather than erroring, so issuing 500 keys from one template does not fail when your own scopes change.
  • key is returned ONCE. Only a hash is stored.
curl -X POST "https://app.blueticked.com/api/v1/businesses/{id}/keys" \
  -H "Authorization: Bearer $BLUETICKED_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Acme Dental (reporting)",
  "scopes": [
    "messages:read",
    "contacts:read"
  ],
  "expires_in_days": 90,
  "monthly_spend_cap_rands": 2500
}'
Response
{
  "id": "44444444-4444-4444-9444-444444444444",
  "business_id": "22222222-2222-4222-9222-222222222222",
  "prefix": "blu_live_z9y",
  "scopes": [
    "contacts:read",
    "messages:read"
  ],
  "expires_at": "2026-11-07T10:00:00.000Z",
  "key": "blu_live_z9y8x7w6v5u4t3s2r1q0p",
  "request_id": "req_b2e3d610e10f1b07468721ee98f0e1d2"
}