Customers

A customer is the account that owns your VerifyAI data. Every API key acts on behalf of exactly one customer, and that customer_id is what scopes everything else: the verifications you can read, the policies your keys can run, and the webhook endpoints you register all belong to a single customer.

If you run VerifyAI for one organization, you have one customer and rarely touch these endpoints — your key already resolves to it. If you're a platform reselling VerifyAI to your own users, customers are how you keep each tenant's data isolated.

How customer_id flows through the API

customer_id is the spine of account isolation:

  • API keys resolve to a customer_id at authentication time. A key can only read and write data for its own customer.
  • Policies are either system policies (customer_id = null, like the built-in scooter_parking) or custom policies owned by one customer.
  • Verifications are written under the authenticating key's customer_id, and list/retrieve only ever return that customer's rows.
  • Inspection sessions and webhook deliveries carry the customer_id so you can route them per tenant — the inspection.submitted webhook payload includes it directly.
You usually don't pass customer_id

Because the key already resolves to a customer, the verify and verifications endpoints never ask you for a customer_id — they infer it from the key. These customer endpoints exist for reading your own account record and, for platform integrations, provisioning sub-accounts.

The customer object

json
{
  "id": "cus_forest1",
  "name": "Forest (HumanForest)",
  "status": "active",
  "created_at": "2026-01-08T09:00:00Z",
  "metadata": {
    "region": "london",
    "external_account_id": "acct_8821"
  }
}

Fields

| Field | Type | Description | | ------------ | -------- | --------------------------------------------------------------------------------- | | id | string | Stable customer identifier, prefix cus_. This is the customer_id on keys/policies. | | name | string | Display name for the account. | | status | string | active, paused, or cancelled. A non-active customer's keys return 403. | | created_at | ISO 8601 | When the customer was created. | | metadata | object? | Free-form key/value data you attach (e.g. your own account ID, region). |

Authentication

| Header | Required | Value | | ----------- | -------- | ------------------------------------------------------ | | X-API-Key | Yes | Your vai_… key. See Authentication. |

Availability

Most accounts manage their customer record from Dashboard → Settings, and platform sub-account provisioning is enabled per integration. If a call below returns 404, the programmatic surface isn't enabled for your account yet — the request and response shapes match what ships. Contact support to turn on multi-customer provisioning.

Retrieve the current customer

text
GET /api/v1/customers/me

Returns the customer the authenticating key belongs to. This is the call to make when you want to confirm which account a key resolves to, or read your own status.

curl https://verify.switchlabs.dev/api/v1/customers/me \
-H "X-API-Key: vai_your_api_key"
json
{
  "id": "cus_forest1",
  "name": "Forest (HumanForest)",
  "status": "active",
  "created_at": "2026-01-08T09:00:00Z",
  "metadata": { "region": "london" }
}

List customers

text
GET /api/v1/customers

For platform integrations only. Returns the sub-accounts you've provisioned, newest first. A single-tenant account sees just its own record.

Query parameters

| Parameter | Type | Default | Description | | --------- | ------ | ------- | ---------------------------------------------------- | | limit | number | 20 | Page size. Clamped to a maximum of 100. | | cursor | string | — | Pagination cursor. Pass next_cursor from the prior page. | | status | string | — | Filter by active, paused, or cancelled. |

curl "https://verify.switchlabs.dev/api/v1/customers?limit=20&status=active" \
-H "X-API-Key: vai_your_api_key"
json
{
  "data": [
    {
      "id": "cus_forest1",
      "name": "Forest (HumanForest)",
      "status": "active",
      "created_at": "2026-01-08T09:00:00Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}

Pagination follows the same cursor contract as Verifications: pass next_cursor back as cursor until has_more is false.

Create a customer

text
POST /api/v1/customers

For platform integrations. Provisions a new sub-account under your organization. Issue that customer a key via the API keys endpoint to let it submit verifications independently.

Body parameters

| Parameter | Type | Required | Description | | ---------- | ------ | -------- | ------------------------------------------------------------------------ | | name | string | Yes | Display name for the new customer. | | metadata | object | No | Free-form data to attach (your own account ID, region, plan, etc.). |

curl -X POST https://verify.switchlabs.dev/api/v1/customers \
-H "X-API-Key: vai_your_api_key" \
-H "Content-Type: application/json" \
-d '{ "name": "Acme Mobility", "metadata": { "external_account_id": "acct_991" } }'
json
{
  "id": "cus_9q2v8m",
  "name": "Acme Mobility",
  "status": "active",
  "created_at": "2026-06-01T12:00:00Z",
  "metadata": { "external_account_id": "acct_991" }
}

Errors

| Status | Reason | | ------ | ------------------------------------------------------------------- | | 400 | Missing name, or invalid metadata. | | 401 | Missing or invalid API key. | | 403 | Key not valid for VerifyAI, not linked to a customer, or lacks platform provisioning. | | 404 | No customer with that id, or it belongs to a different organization. | | 429 | Rate limit — check the Retry-After header. | | 503 | Authentication service unavailable. Retry. |

What's next

Get in Touch

Questions about pricing, integrations, or custom deployments? We'd love to hear from you.