Customers

Create, list, retrieve, and update merchant customers in Tokeflow — the canonical buyer records that anchor transactions, orders, and subscriptions.

A Customer is the canonical buyer record for a single merchant. It stores the buyer's identity (email, name, phone, tax document) and a billing address, and it anchors the buyer's transactions, orders, and subscriptions under one record.

Customers are unique by email per merchant. Creating a customer is idempotent on email: if a customer with the same email already exists for the merchant, Tokeflow returns the existing record instead of creating a duplicate. This makes customer creation safe to retry from checkout and server-to-server flows.

Tokeflow is a payment orchestration platform — it standardizes buyer records across every connected provider so you keep one customer identity regardless of which provider ultimately handles a charge. Tokeflow does not process or settle funds; that is handled by your connected providers.

The customer object

FieldTypeDescription
idstringUnique identifier, prefixed cust_.
merchant_idstringMerchant that owns this customer, prefixed mrc_.
emailstring | nullBuyer email. Stored lowercase; unique per merchant.
namestring | nullBuyer full name.
phonestring | nullBuyer phone in E.164 format (e.g. +5511999990000).
document_typestring | nullOne of cpf, cnpj, passport, tax_id.
metadataobject | nullArbitrary key/value pairs you attach. Max 5 KB serialized.
created_atstringCreation timestamp (ISO 8601 UTC).
updated_atstringLast-update timestamp (ISO 8601 UTC).

The tax document number (document_number) and billing_address are accepted on write for compliance and processing, but they are never returned in API responses. The customer object exposes document_type only.

Authentication & scopes

All customer endpoints require a Merchant secret key (sk_live_mer_…). The merchant is inferred from the key, so you never pass a merchant_id. Use the customers:read scope for read operations and customers:write for create/update.

Authorization: Bearer sk_live_mer_xxxxxxxxxxxxxxxxxxxxxxxx

Secret keys are server-side only. Never embed an sk_* key in browser or mobile code. See Authentication for key anatomy and scopes.


POST/api/v1/customers

Merchant

Auth: Merchant key (scope customers:write)

Creates a customer for the merchant resolved from the API key. Idempotent by email: if a customer with the same email already exists, the existing record is returned with HTTP 200; a new customer returns HTTP 201.

Body parameters

FieldTypeRequiredDescription
emailstringYesBuyer email. Normalized to lowercase; unique per merchant.
namestringYesBuyer full name.
phonestringYesE.164 phone, at least 10 digits incl. country/area code (e.g. +5511999990000).
document_typestringYesOne of cpf, cnpj, passport, tax_id.
document_numberstringYesTax document (max 40 chars). Stored encrypted at rest; never returned.
billing_addressobjectYesBilling address (see below).
metadataobjectNoArbitrary key/value pairs. Max 5 KB serialized.

billing_address object

FieldTypeRequiredDescription
line_1stringYesStreet and number (max 255).
line_2stringNoApartment, suite, etc. (max 255).
zip_codestringYesZIP/postal code (max 20).
citystringYesCity (max 100).
statestringYesState/province code (max 100).
countrystringYesISO 3166-1 alpha-2 country code, e.g. BR (max 2).

Send an Idempotency-Key header on create. Combined with email idempotency, this guarantees retries never produce duplicate customers and return the original result.

Request

curl -X POST https://api.tokeflow.com/api/v1/customers \
  -H "Authorization: Bearer sk_live_mer_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 4f1d8c2a-9b07-4f3e-9a1c-7e2b6d0c5a11" \
  -d '{
    "email": "joao@example.com",
    "name": "Joao da Silva",
    "phone": "+5511999990000",
    "document_type": "cpf",
    "document_number": "123.456.789-00",
    "billing_address": {
      "line_1": "Av Paulista, 1000",
      "line_2": "Apto 42",
      "zip_code": "01310-100",
      "city": "São Paulo",
      "state": "SP",
      "country": "BR"
    },
    "metadata": { "source": "checkout_web" }
  }'

Response 201 Created

{
  "success": true,
  "data": {
    "id": "cust_a1b2c3d4e5",
    "merchant_id": "mrc_9f8e7d6c5b",
    "email": "joao@example.com",
    "name": "Joao da Silva",
    "created_at": "2026-01-15T12:30:00.000Z"
  },
  "request_id": "req_8f3c1a2b4d",
  "timestamp": "2026-01-15T12:30:00.000Z"
}

The create response is a confirmation payload containing id, merchant_id, email, name, and created_at. To read the full customer object, call GET /api/v1/customers/:id.

When the email already exists, the identical body is returned with status 200 OK instead of 201.


GET/api/v1/customers

Merchant

Auth: Merchant key (scope customers:read)

Lists customers for the merchant, newest first. Supports an email filter and pagination.

Query parameters

FieldTypeRequiredDescription
emailstringNoExact, case-insensitive email filter.
pageintegerNoPage number (default 1, min 1).
limitintegerNoItems per page (default 20, max 100).

Request

curl -X GET "https://api.tokeflow.com/api/v1/customers?page=1&limit=20&email=joao@example.com" \
  -H "Authorization: Bearer sk_live_mer_xxxxxxxxxxxxxxxxxxxxxxxx"

Response 200 OK

{
  "success": true,
  "data": [
    {
      "id": "cust_a1b2c3d4e5",
      "merchant_id": "mrc_9f8e7d6c5b",
      "email": "joao@example.com",
      "name": "Joao da Silva",
      "phone": "+5511999990000",
      "document_type": "cpf",
      "metadata": { "source": "checkout_web" },
      "created_at": "2026-01-15T12:30:00.000Z",
      "updated_at": "2026-01-15T12:30:00.000Z"
    }
  ],
  "meta": {
    "pagination": {
      "page": 1,
      "limit": 20,
      "total": 42,
      "total_pages": 3,
      "has_next": true,
      "has_prev": false
    }
  },
  "request_id": "req_8f3c1a2b4d",
  "timestamp": "2026-01-15T12:30:00.000Z"
}

Because email is unique per merchant, filtering by email returns at most one customer — a convenient lookup before deciding whether to create.


GET/api/v1/customers/:customerId

Merchant

Auth: Merchant key (scope customers:read)

Retrieves a single customer by ID.

Path parameters

FieldTypeRequiredDescription
customerIdstringYesCustomer ID, prefixed cust_.

Request

curl -X GET https://api.tokeflow.com/api/v1/customers/cust_a1b2c3d4e5 \
  -H "Authorization: Bearer sk_live_mer_xxxxxxxxxxxxxxxxxxxxxxxx"

Response 200 OK

{
  "success": true,
  "data": {
    "id": "cust_a1b2c3d4e5",
    "merchant_id": "mrc_9f8e7d6c5b",
    "email": "joao@example.com",
    "name": "Joao da Silva",
    "phone": "+5511999990000",
    "document_type": "cpf",
    "metadata": { "source": "checkout_web" },
    "created_at": "2026-01-15T12:30:00.000Z",
    "updated_at": "2026-01-15T12:30:00.000Z"
  },
  "request_id": "req_8f3c1a2b4d",
  "timestamp": "2026-01-15T12:30:00.000Z"
}

Response 404 Not Found

{
  "error": {
    "type": "not_found_error",
    "code": "RESOURCE_NOT_FOUND",
    "message": "Customer with ID \"cust_a1b2c3d4e5\" not found",
    "details": {},
    "request_id": "req_8f3c1a2b4d",
    "timestamp": "2026-01-15T12:30:00.000Z"
  }
}

PATCH/api/v1/customers/:customerId

Merchant

Auth: Merchant key (scope customers:write)

Updates a customer. All body fields are optional; only the fields you send are changed. Changing email to one already used by another customer of the merchant returns 409 Conflict.

Path parameters

FieldTypeRequiredDescription
customerIdstringYesCustomer ID, prefixed cust_.

Body parameters

FieldTypeRequiredDescription
emailstringNoNew email. Must be unique per merchant.
namestringNoNew name.
phonestringNoNew E.164 phone.
document_typestringNoOne of cpf, cnpj, passport, tax_id.
document_numberstringNoTax document (max 40 chars). Never returned.
metadataobjectNoReplaces stored metadata. Max 5 KB serialized.
billing_addressobjectNoBilling address (same shape as on create).

Request

curl -X PATCH https://api.tokeflow.com/api/v1/customers/cust_a1b2c3d4e5 \
  -H "Authorization: Bearer sk_live_mer_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Joao P. da Silva",
    "phone": "+5511988887777",
    "metadata": { "source": "checkout_web", "tier": "gold" }
  }'

Response 200 OK

{
  "success": true,
  "data": {
    "id": "cust_a1b2c3d4e5",
    "merchant_id": "mrc_9f8e7d6c5b",
    "email": "joao@example.com",
    "name": "Joao P. da Silva",
    "phone": "+5511988887777",
    "document_type": "cpf",
    "metadata": { "source": "checkout_web", "tier": "gold" },
    "created_at": "2026-01-15T12:30:00.000Z",
    "updated_at": "2026-01-15T13:05:00.000Z"
  },
  "request_id": "req_8f3c1a2b4d",
  "timestamp": "2026-01-15T13:05:00.000Z"
}

Response 409 Conflict

Returned when the new email already belongs to another customer of the merchant. The conflicting customer's ID is included in details.

{
  "error": {
    "type": "conflict_error",
    "code": "CUSTOMER_EMAIL_EXISTS",
    "message": "A customer with this email already exists for this merchant",
    "details": { "existing_customer_id": "cust_f6e5d4c3b2" },
    "request_id": "req_8f3c1a2b4d",
    "timestamp": "2026-01-15T13:05:00.000Z"
  }
}

Errors

Customer endpoints use the standard Tokeflow error envelope. Common cases:

HTTPtypeWhen
400validation_errorMissing/invalid field, bad document_type, malformed phone, or metadata over 5 KB.
401authentication_errorMissing or invalid API key.
403authorization_errorKey lacks the required scope, or a non-Merchant key was used.
404not_found_errorNo customer with that ID for this merchant.
409conflict_errorEmail already in use by another customer (PATCH).
429rate_limit_errorRate limit exceeded — back off exponentially.

On this page