Skip to content

Customers tools

MCP tools for Customers: customers_create, customers_credit_balance_adjustments_create, customers_credit_balance_get, customers_delete, customers_entitlement_overrides_create, customers_entitlement_overrides_delete, customers_entitlement_overrides_list, customers_entitlements_get, customers_evidence_sets_list, customers_get, customers_list, customers_tax_ids_add, customers_tax_ids_delete, customers_update.

  • customers_create: Create a customer
  • customers_credit_balance_adjustments_create: Adjust a customer's credit balance
  • customers_credit_balance_get: Get a customer's credit balance
  • customers_delete: Delete a customer
  • customers_entitlement_overrides_create: Override an entitlement
  • customers_entitlement_overrides_delete: Delete an entitlement override
  • customers_entitlement_overrides_list: List a customer's entitlement overrides
  • customers_entitlements_get: Get a customer's entitlements
  • customers_evidence_sets_list: List a customer's location evidence
  • customers_get: Get a customer
  • customers_list: List customers
  • customers_tax_ids_add: Add a tax ID to a customer
  • customers_tax_ids_delete: Remove a tax ID from a customer
  • customers_update: Update a customer

customers_create

Create a customer. Operation customers.create · Brand level · permission customers:write · risk tier write · since M4

Creates a customer of the brand in the mode of the request (spec §7.5). Checkout creates customers itself; use this to create them ahead of a sale or from your own sign-up.

  • Email: one active customer per address in a brand and mode (customer_email_taken otherwise). The same address in another brand is another customer.
  • Tax IDs: each is checked with its register before it is stored (VIES for EU VAT IDs, HMRC for UK VAT numbers, the Swiss UID register; Norwegian and US numbers by format; other types are kept unverified). The result, its source, the consultation number and the time are stored per ID. A malformed number is refused (tax_id_invalid); a number the register doesn't know is stored as invalid. Dry runs simulate the check.
  • Type: inferred (spec §13.1): business with a tax ID that isn't invalid, or with businessName when you declare type: business; otherwise what you declared. Tax is still decided per sale: only a valid tax ID makes a sale business-to-business, and the location comes from the evidence checkout captures.

Emits customer.created.

Annotations: readOnlyHint: false · destructiveHint: false · idempotentHint: false · openWorldHint: true

Arguments

ArgumentTypeRequiredDescription
emailstringyesThe customer's email address. One active customer per address in a brand and mode. (at most 254 characters)
namestringnoThe person's name. (1–200 characters)
businessNamestringnoThe business's legal name, for business customers. (1–200 characters)
typeone of individual, business, unknownnoWhat you say the customer is: individual, business (needs businessName or a tax ID) or unknown. The stored type is inferred: a tax ID that isn't rejected makes the customer a business (spec §13.1). (default "unknown")
localestringnoLanguage for checkout, the portal, emails and invoices, e.g. de.
billingAddressobjectno–
taxIdsarray of objectnoThe customer's tax IDs. Each is checked with its register (VIES, HMRC, the Swiss UID register) and stored with the result; a malformed number is refused (tax_id_invalid). (at most 5 items) (default [])
testClockIdID (clk_…)noTest mode: a test clock (clk_…) to attach the customer to. Its subscriptions bill at the clock's time (spec §16.13).
metadataobjectnoYour own key-value pairs (e.g. your user ID).
entity_idID (ent_…)noOptional: the brand's legal entity (ent_…); brand_id alone is enough.
brand_idID (brd_…)noThe brand to act on (brd_…), inside your API key's reach. Needed with an organization or entity key; a brand key acts on its own brand.
idempotency_keystringnoA unique string for this change. Retrying with the same key and arguments never acts twice. When left out, the server generates one and returns it in the result's idempotency_key. (1–255 characters)
dry_runbooleannotrue: check permissions and rules and compute the result, then roll everything back. Nothing is saved. (default false)
  • Brand: pass brand_id with an organization or entity key; a brand key acts on its own brand.
  • Idempotency: the result returns the idempotency_key used, yours or one the server generated. Retry with it: a call with the same key and arguments never acts twice (keys are kept for 24 hours).
  • Dry run: supported. dry_run: true checks permissions and rules and computes the result, then rolls everything back.

Errors

  • validation_failed: A field is missing or malformed, a tax ID is given twice, or a business customer has neither a business name nor a tax ID (details.issues).
  • tax_id_invalid: A tax ID's number isn't valid for its type and country (format, checksum, another country's prefix, a Northern Ireland XI number); details.reason says which. Nothing is stored. Types Ownrecord can't check (e.g. au_abn) are stored as unverified instead.
  • customer_email_taken: Another active customer of the brand has this email address in this mode.
  • resource_not_found: No test clock with testClockId exists for the brand in test mode.
  • test_clock_mode: testClockId was given in live mode: test clocks belong to test mode.
  • test_clock_advancing: The test clock is advancing: wait until it is ready.
  • test_clock_customer_limit: The test clock already has 10 customers.
  • idempotency_key_reused: The idempotency key was used before with another input.
  • scope_required: The request names no brand (an org or entity key without Ownrecord-Brand).
  • livemode_not_allowed: You have no live-mode access, so you can't act on live customers.
  • permission_denied: You can't change this brand's customers (customers:write: owners, admins and support).

Examples

A business in Austria with its VAT ID

VIES confirms the VAT ID, so the customer is a business.

Arguments:

JSON
{
  "email": "billing@alpenapps.example",
  "name": "Lena Huber",
  "businessName": "Alpen Apps GmbH",
  "type": "business",
  "locale": "de-AT",
  "billingAddress": {
    "line1": "Mariahilfer Straße 1",
    "city": "Wien",
    "postalCode": "1060",
    "country": "AT"
  },
  "taxIds": [
    {
      "type": "eu_vat",
      "value": "ATU 0000 0000",
      "country": "AT"
    }
  ],
  "metadata": {
    "userId": "u_4821"
  },
  "brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz",
  "idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}

Result output:

JSON
{
  "id": "cus_01m4ty3c2b5qx7mhd9k8w6s0aa",
  "object": "customer",
  "livemode": false,
  "entityId": "ent_01m4tx5nj8emwbyf7y9vcf47x2",
  "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
  "email": "billing@alpenapps.example",
  "name": "Lena Huber",
  "businessName": "Alpen Apps GmbH",
  "locale": "de-AT",
  "type": "business",
  "declaredType": "business",
  "billingAddress": {
    "line1": "Mariahilfer Straße 1",
    "line2": null,
    "city": "Wien",
    "postalCode": "1060",
    "region": null,
    "country": "AT"
  },
  "taxIds": [
    {
      "id": "ATU00000000",
      "type": "eu_vat",
      "value": "ATU 0000 0000",
      "country": "AT",
      "number": "ATU00000000",
      "verification": {
        "status": "valid",
        "source": "VIES",
        "reason": null,
        "checkedAt": "2026-10-14T09:00:00.000Z",
        "consultationNumber": "WAPIAAAAZ1x2y3",
        "simulated": false
      },
      "history": [],
      "addedAt": "2026-10-14T09:00:00.000Z"
    }
  ],
  "taxCountryLocked": null,
  "taxExempt": null,
  "processorRefs": [],
  "risk": {
    "level": "normal",
    "reasons": [],
    "firstPaymentAt": null,
    "totalPaid": {
      "amount": "0",
      "currency": "EUR"
    }
  },
  "portalLastLoginAt": null,
  "testClockId": null,
  "metadata": {
    "userId": "u_4821"
  },
  "createdAt": "2026-10-14T09:00:00.000Z",
  "updatedAt": "2026-10-14T09:00:00.000Z",
  "deletedAt": null
}

A consumer

Arguments:

JSON
{
  "email": "ana@example.com",
  "name": "Ana Schmidt",
  "type": "individual",
  "billingAddress": {
    "country": "DE"
  },
  "brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz",
  "idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}

Result output:

JSON
{
  "id": "cus_01m4ty3c2b5qx7mhd9k8w6s0aa",
  "object": "customer",
  "livemode": false,
  "entityId": "ent_01m4tx5nj8emwbyf7y9vcf47x2",
  "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
  "email": "ana@example.com",
  "name": "Ana Schmidt",
  "businessName": null,
  "locale": null,
  "type": "individual",
  "declaredType": "individual",
  "billingAddress": {
    "line1": null,
    "line2": null,
    "city": null,
    "postalCode": null,
    "region": null,
    "country": "DE"
  },
  "taxIds": [],
  "taxCountryLocked": null,
  "taxExempt": null,
  "processorRefs": [],
  "risk": {
    "level": "normal",
    "reasons": [],
    "firstPaymentAt": null,
    "totalPaid": {
      "amount": "0",
      "currency": "EUR"
    }
  },
  "portalLastLoginAt": null,
  "testClockId": null,
  "metadata": {},
  "createdAt": "2026-10-14T09:00:00.000Z",
  "updatedAt": "2026-10-14T09:00:00.000Z",
  "deletedAt": null
}

customers_credit_balance_adjustments_create

Adjust a customer's credit balance. Operation customers.credit_balance.adjustments.create · Brand level · permission customers:admin · risk tier financial · since M5

Adds credit to a customer's invoice credit balance (a goodwill credit), or takes unused credit back, with a reason. A positive amount adds, a negative one removes; the balance never goes below zero (credit_balance_insufficient). The credit is applied automatically to the customer's next invoices in that currency, after tax.

In the ledger, credit granted without payment is a cost (promo_expense). Financial tier: owners and admins (customers:admin) with a sign-in in the last 15 minutes; an approval policy may require a second person above an amount. Dry-run it first. Emits customer.credit_balance.updated.

Annotations: readOnlyHint: false · destructiveHint: false · idempotentHint: true · openWorldHint: false

Arguments

ArgumentTypeRequiredDescription
idID (cus_…)yesThe customer (cus_…).
amountobjectyesSigned: a positive amount adds credit (goodwill), a negative one takes unused credit back.
reasonstringyesWhy (required): shown in the ledger, the audit log and to approvers. (1–500 characters)
entity_idID (ent_…)noOptional: the brand's legal entity (ent_…); brand_id alone is enough.
brand_idID (brd_…)noThe brand to act on (brd_…), inside your API key's reach. Needed with an organization or entity key; a brand key acts on its own brand.
idempotency_keystringnoA unique string for this change. Retrying with the same key and arguments never acts twice. When left out, the server generates one and returns it in the result's idempotency_key. (1–255 characters)
dry_runbooleannotrue: check permissions and rules and compute the result, then roll everything back. Nothing is saved. (default false)
  • Brand: pass brand_id with an organization or entity key; a brand key acts on its own brand.
  • Idempotency: the result returns the idempotency_key used, yours or one the server generated. Retry with it: a call with the same key and arguments never acts twice (keys are kept for 24 hours).
  • Dry run: supported. dry_run: true checks permissions and rules and computes the result, then rolls everything back.

Errors

Example

A goodwill credit after an outage

Arguments:

JSON
{
  "id": "cus_01m4tx5nj8emwbyf7y9vcf47ym",
  "amount": {
    "amount": "250000000",
    "currency": "EUR"
  },
  "reason": "Goodwill for the September outage",
  "brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz",
  "idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}

Result output:

JSON
{
  "object": "credit_balance_adjustment",
  "customerId": "cus_01m4tx5nj8emwbyf7y9vcf47ym",
  "amount": {
    "amount": "250000000",
    "currency": "EUR"
  },
  "balance": {
    "amount": "250000000",
    "currency": "EUR"
  },
  "reason": "Goodwill for the September outage",
  "ledgerTransactionId": "txn_01m4tx5nj8emwbyf7y9vcf47yq"
}

customers_credit_balance_get

Get a customer's credit balance. Operation customers.credit_balance.get · Brand level · permission customers:read · risk tier read · since M5

Returns a customer's invoice credit balance in every currency it has one: proration credits, goodwill credits and overpayments, applied automatically to the customer's next invoices before they're charged or sent (spec §16.11). It isn't the usage wallet. changes lists the latest movements: operator adjustments, credit used by invoices at finalization and credit returned when such an invoice was voided.

Annotations: readOnlyHint: true · destructiveHint: false · idempotentHint: true · openWorldHint: false

Arguments

ArgumentTypeRequiredDescription
idID (cus_…)yesThe customer (cus_…).
entity_idID (ent_…)noOptional: the brand's legal entity (ent_…); brand_id alone is enough.
brand_idID (brd_…)noThe brand to act on (brd_…), inside your API key's reach. Needed with an organization or entity key; a brand key acts on its own brand.
  • Brand: pass brand_id with an organization or entity key; a brand key acts on its own brand.
  • Read-only: changes nothing; idempotency_key is ignored.

Errors

Example

€50 left after an invoice used €200

Arguments:

JSON
{
  "id": "cus_01m4tx5nj8emwbyf7y9vcf47ym",
  "brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz"
}

Result output:

JSON
{
  "object": "credit_balance",
  "customerId": "cus_01m4tx5nj8emwbyf7y9vcf47ym",
  "livemode": false,
  "balances": [
    {
      "amount": "50000000",
      "currency": "EUR"
    }
  ],
  "changes": [
    {
      "ledgerTransactionId": "txn_01m4tx5nj8emwbyf7y9vcf47yn",
      "change": {
        "amount": "-200000000",
        "currency": "EUR"
      },
      "reason": "invoice_applied",
      "memo": "Invoice GEN-2026-000131",
      "invoiceId": "inv_01m4tx5nj8emwbyf7y9vcf47yk",
      "effectiveAt": "2026-10-20T09:00:00.000Z"
    },
    {
      "ledgerTransactionId": "txn_01m4tx5nj8emwbyf7y9vcf47yq",
      "change": {
        "amount": "250000000",
        "currency": "EUR"
      },
      "reason": "adjustment",
      "memo": "Goodwill for the September outage",
      "invoiceId": null,
      "effectiveAt": "2026-10-20T08:30:00.000Z"
    }
  ]
}

customers_delete

Delete a customer. Operation customers.delete · Brand level · permission customers:admin · risk tier write · since M4

Deletes a customer: a soft delete that sets deletedAt. The customer stays readable, because invoices, payments and evidence belong to it and must be kept (spec §6.6), but it can't be changed any more, and its email address can be used for a new customer. Deleted customers are left out of customers.list unless asked for. Erasing personal data (pseudonymisation) is a separate operator action, still to come.

Give a reason: it goes to the audit log. Needs customers:admin (owners and admins). Emits customer.updated with deletedAt set.

Annotations: readOnlyHint: false · destructiveHint: true · idempotentHint: false · openWorldHint: false

Arguments

ArgumentTypeRequiredDescription
idID (cus_…)yesThe customer's ID (cus_…).
reasonstringnoWhy; recorded in the audit log. (1–500 characters)
entity_idID (ent_…)noOptional: the brand's legal entity (ent_…); brand_id alone is enough.
brand_idID (brd_…)noThe brand to act on (brd_…), inside your API key's reach. Needed with an organization or entity key; a brand key acts on its own brand.
idempotency_keystringnoA unique string for this change. Retrying with the same key and arguments never acts twice. When left out, the server generates one and returns it in the result's idempotency_key. (1–255 characters)
dry_runbooleannotrue: check permissions and rules and compute the result, then roll everything back. Nothing is saved. (default false)
  • Brand: pass brand_id with an organization or entity key; a brand key acts on its own brand.
  • Idempotency: the result returns the idempotency_key used, yours or one the server generated. Retry with it: a call with the same key and arguments never acts twice (keys are kept for 24 hours).
  • Dry run: supported. dry_run: true checks permissions and rules and computes the result, then rolls everything back.

Errors

Example

Delete a duplicate customer

Arguments:

JSON
{
  "id": "cus_01m4ty3c2b5qx7mhd9k8w6s0ab",
  "reason": "Duplicate of cus_01m4ty3c2b5qx7mhd9k8w6s0aa",
  "brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz",
  "idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}

Result output:

JSON
{
  "id": "cus_01m4ty3c2b5qx7mhd9k8w6s0ab",
  "object": "customer",
  "livemode": false,
  "entityId": "ent_01m4tx5nj8emwbyf7y9vcf47x2",
  "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
  "email": "ana@example.com",
  "name": "Ana Schmidt",
  "businessName": null,
  "locale": "de",
  "type": "individual",
  "declaredType": "individual",
  "billingAddress": {
    "line1": null,
    "line2": null,
    "city": null,
    "postalCode": null,
    "region": null,
    "country": "DE"
  },
  "taxIds": [],
  "taxCountryLocked": {
    "country": "DE",
    "subdivision": null,
    "lockedAt": "2026-10-14T09:30:00.000Z",
    "evidenceSetId": "evs_01m4ty3c2b5qx7mhd9k8w6s0ac"
  },
  "taxExempt": null,
  "processorRefs": [
    {
      "processorConnectionId": "pcon_01m4ty3c2b5qx7mhd9k8w6s0af",
      "customerRef": "cus_QxY12AbC"
    }
  ],
  "risk": {
    "level": "normal",
    "reasons": [],
    "firstPaymentAt": "2026-10-14T09:30:00.000Z",
    "totalPaid": {
      "amount": "119000000",
      "currency": "EUR"
    }
  },
  "portalLastLoginAt": null,
  "testClockId": null,
  "metadata": {},
  "createdAt": "2026-10-14T09:00:00.000Z",
  "updatedAt": "2026-10-14T10:00:00.000Z",
  "deletedAt": "2026-10-14T10:00:00.000Z"
}

customers_entitlement_overrides_create

Override an entitlement. Operation customers.entitlement_overrides.create · Brand level · permission customers:write · risk tier write · since M5

Grants a customer a value of one feature, with a reason and an optional expiry, e.g. 20 extra seats while a team migrates or feature.export = true as a goodwill gesture. The override is one more source of the customer's entitlements and merges with the others by the feature's combine rule: with max it raises a limit, with sum it adds to it, with or it can only switch a feature on, and with first it decides (the newest override comes first).

It applies until expiresAt (exclusive), or until deleted; for a customer on a test clock, expiresAt is a time on the clock (#541). The customer's entitlements are recomputed within one job cycle, and customer.entitlements.updated is sent when a value changes. Needs customers:write (owners, admins and support); the reason goes to the override and the audit log.

Annotations: readOnlyHint: false · destructiveHint: false · idempotentHint: false · openWorldHint: false

Arguments

ArgumentTypeRequiredDescription
idID (cus_…)yesThe customer's ID (cus_…).
featureKeystringyesThe feature to grant a value of, e.g. seats.max. (at most 100 characters)
valueboolean or number or stringyesThe value to grant: true/false for a boolean feature, a whole number ≥ 0 for a limit, one of the values of an enum feature. It merges with the customer's other values by the feature's combine rule.
reasonstringyesWhy the customer gets this; stored on the override and in the audit log. (1–500 characters)
expiresAtdate-time (ISO 8601)noWhen the override stops applying (exclusive). Must be in the future. Omit for no expiry.
entity_idID (ent_…)noOptional: the brand's legal entity (ent_…); brand_id alone is enough.
brand_idID (brd_…)noThe brand to act on (brd_…), inside your API key's reach. Needed with an organization or entity key; a brand key acts on its own brand.
idempotency_keystringnoA unique string for this change. Retrying with the same key and arguments never acts twice. When left out, the server generates one and returns it in the result's idempotency_key. (1–255 characters)
dry_runbooleannotrue: check permissions and rules and compute the result, then roll everything back. Nothing is saved. (default false)
  • Brand: pass brand_id with an organization or entity key; a brand key acts on its own brand.
  • Idempotency: the result returns the idempotency_key used, yours or one the server generated. Retry with it: a call with the same key and arguments never acts twice (keys are kept for 24 hours).
  • Dry run: supported. dry_run: true checks permissions and rules and computes the result, then rolls everything back.

Errors

Examples

Extra seats for a month

Arguments:

JSON
{
  "id": "cus_01m4ty3c2b5qx7mhd9k8w6s0aa",
  "featureKey": "seats.max",
  "value": 20,
  "reason": "Goodwill while their team migrates (ticket 4821)",
  "expiresAt": "2026-11-14T00:00:00.000Z",
  "brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz",
  "idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}

Result output:

JSON
{
  "id": "ceo_01m4ty3c2b5qx7mhd9k8w6s0b2",
  "object": "entitlement_override",
  "customerId": "cus_01m4ty3c2b5qx7mhd9k8w6s0aa",
  "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
  "livemode": false,
  "featureKey": "seats.max",
  "value": 20,
  "reason": "Goodwill while their team migrates (ticket 4821)",
  "setBy": {
    "type": "user",
    "id": "usr_01m4ty3c2b5qx7mhd9k8w6s0b4"
  },
  "expiresAt": "2026-11-14T00:00:00.000Z",
  "active": true,
  "createdAt": "2026-10-14T10:00:00.000Z"
}

Switch a feature on for good

Arguments:

JSON
{
  "id": "cus_01m4ty3c2b5qx7mhd9k8w6s0aa",
  "featureKey": "feature.export",
  "value": true,
  "reason": "Beta tester",
  "brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz",
  "idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}

Result output:

JSON
{
  "id": "ceo_01m4ty3c2b5qx7mhd9k8w6s0b3",
  "object": "entitlement_override",
  "customerId": "cus_01m4ty3c2b5qx7mhd9k8w6s0aa",
  "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
  "livemode": false,
  "featureKey": "feature.export",
  "value": true,
  "reason": "Beta tester",
  "setBy": {
    "type": "user",
    "id": "usr_01m4ty3c2b5qx7mhd9k8w6s0b4"
  },
  "expiresAt": null,
  "active": true,
  "createdAt": "2026-10-14T10:00:00.000Z"
}

customers_entitlement_overrides_delete

Delete an entitlement override. Operation customers.entitlement_overrides.delete · Brand level · permission customers:write · risk tier write · since M5

Removes an override from a customer; the response is the override as it was. The customer's entitlements are recomputed within one job cycle, and customer.entitlements.updated is sent when a value changes. An expired override no longer applies anyway; deleting it only tidies the list.

Give a reason: it goes to the audit log with the removed override. Needs customers:write (owners, admins and support).

Annotations: readOnlyHint: false · destructiveHint: true · idempotentHint: false · openWorldHint: false

Arguments

ArgumentTypeRequiredDescription
idID (cus_…)yesThe customer's ID (cus_…).
overrideIdID (ceo_…)yesThe override's ID (ceo_…).
reasonstringyesWhy the override is removed; recorded in the audit log. (1–500 characters)
entity_idID (ent_…)noOptional: the brand's legal entity (ent_…); brand_id alone is enough.
brand_idID (brd_…)noThe brand to act on (brd_…), inside your API key's reach. Needed with an organization or entity key; a brand key acts on its own brand.
idempotency_keystringnoA unique string for this change. Retrying with the same key and arguments never acts twice. When left out, the server generates one and returns it in the result's idempotency_key. (1–255 characters)
dry_runbooleannotrue: check permissions and rules and compute the result, then roll everything back. Nothing is saved. (default false)
  • Brand: pass brand_id with an organization or entity key; a brand key acts on its own brand.
  • Idempotency: the result returns the idempotency_key used, yours or one the server generated. Retry with it: a call with the same key and arguments never acts twice (keys are kept for 24 hours).
  • Dry run: supported. dry_run: true checks permissions and rules and computes the result, then rolls everything back.

Errors

  • validation_failed: An ID is malformed, or the reason is missing or too long.
  • resource_not_found: This brand has no such customer in this mode, or the customer has no override with this overrideId.
  • version_conflict: The override changed at the same moment; retry.
  • scope_required: The request names no brand (an org or entity key without Ownrecord-Brand).
  • livemode_not_allowed: You have no live-mode access, so you can't act on live customers.
  • permission_denied: You can't change this brand's customers' entitlements (customers:write: owners, admins and support).

Example

End a goodwill grant early

Arguments:

JSON
{
  "id": "cus_01m4ty3c2b5qx7mhd9k8w6s0aa",
  "overrideId": "ceo_01m4ty3c2b5qx7mhd9k8w6s0b2",
  "reason": "Migration finished",
  "brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz",
  "idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}

Result output:

JSON
{
  "id": "ceo_01m4ty3c2b5qx7mhd9k8w6s0b2",
  "object": "entitlement_override",
  "customerId": "cus_01m4ty3c2b5qx7mhd9k8w6s0aa",
  "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
  "livemode": false,
  "featureKey": "seats.max",
  "value": 20,
  "reason": "Goodwill while their team migrates (ticket 4821)",
  "setBy": {
    "type": "user",
    "id": "usr_01m4ty3c2b5qx7mhd9k8w6s0b4"
  },
  "expiresAt": "2026-11-14T00:00:00.000Z",
  "active": true,
  "createdAt": "2026-10-14T10:00:00.000Z"
}

customers_entitlement_overrides_list

List a customer's entitlement overrides. Operation customers.entitlement_overrides.list · Brand level · permission customers:read · risk tier read · since M5

Lists the overrides granted to a customer, newest first, including expired ones (active: false) unless active=true. Each has its feature, value, reason, who set it and its expiry.

Paginate with limit (1–100, default 10) and starting_after (the next_cursor of the previous page).

Annotations: readOnlyHint: true · destructiveHint: false · idempotentHint: true · openWorldHint: false

Arguments

ArgumentTypeRequiredDescription
idID (cus_…)yesThe customer's ID (cus_…).
activeboolean or stringnotrue: only overrides that apply now (not expired).
limitintegerno(1–100)
starting_afterID (ceo_…)noThe override's ID (ceo_…).
entity_idID (ent_…)noOptional: the brand's legal entity (ent_…); brand_id alone is enough.
brand_idID (brd_…)noThe brand to act on (brd_…), inside your API key's reach. Needed with an organization or entity key; a brand key acts on its own brand.
  • Brand: pass brand_id with an organization or entity key; a brand key acts on its own brand.
  • Read-only: changes nothing; idempotency_key is ignored.

Errors

  • validation_failed: id isn't a customer ID, or a filter or pagination value is invalid.
  • resource_not_found: This brand has no such customer in this mode (customers belong to one brand and one mode).
  • scope_required: The request names no brand (an org or entity key without Ownrecord-Brand).
  • livemode_not_allowed: You have no live-mode access, so you can't act on live customers.
  • permission_denied: You can't read this brand's customers (customers:read).

Example

Overrides that apply now

Arguments:

JSON
{
  "id": "cus_01m4ty3c2b5qx7mhd9k8w6s0aa",
  "active": true,
  "brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz"
}

Result output:

JSON
{
  "object": "list",
  "data": [
    {
      "id": "ceo_01m4ty3c2b5qx7mhd9k8w6s0b2",
      "object": "entitlement_override",
      "customerId": "cus_01m4ty3c2b5qx7mhd9k8w6s0aa",
      "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
      "livemode": false,
      "featureKey": "seats.max",
      "value": 20,
      "reason": "Goodwill while their team migrates (ticket 4821)",
      "setBy": {
        "type": "user",
        "id": "usr_01m4ty3c2b5qx7mhd9k8w6s0b4"
      },
      "expiresAt": "2026-11-14T00:00:00.000Z",
      "active": true,
      "createdAt": "2026-10-14T10:00:00.000Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}

customers_entitlements_get

Get a customer's entitlements. Operation customers.entitlements.get · Brand level · permission customers:read · risk tier read · since M5

Returns what a customer of the brand may use, in the mode of the request: one value per feature of the brand (values), where each value comes from (sources) and when it was resolved (computedAt).

Values are resolved from the customer's subscriptions (active, trialing, past_due during the grace period, paused when the brand keeps entitlements during a pause), one-time purchases of products with lifetimeEntitlements, overrides set by your team, and feature defaults, merged with each feature's combine rule. A perUnit limit is multiplied by the quantity.

Ownrecord stores the result and recomputes it within one job cycle of every change; the customer.entitlements.updated webhook says when it changed. A read never returns a set known to be out of date: while a recompute is pending it resolves the values from the sources. Enforcing them is up to your product. For one feature, entitlements.check is lighter.

Annotations: readOnlyHint: true · destructiveHint: false · idempotentHint: true · openWorldHint: false

Arguments

ArgumentTypeRequiredDescription
idID (cus_…)yesThe customer's ID (cus_…).
entity_idID (ent_…)noOptional: the brand's legal entity (ent_…); brand_id alone is enough.
brand_idID (brd_…)noThe brand to act on (brd_…), inside your API key's reach. Needed with an organization or entity key; a brand key acts on its own brand.
  • Brand: pass brand_id with an organization or entity key; a brand key acts on its own brand.
  • Read-only: changes nothing; idempotency_key is ignored.

Errors

Examples

A subscriber with an override

Three seats of a plan granting 5 seats per unit (15), raised to 20 by an override (seats.max combines with max); support.level has its default.

Arguments:

JSON
{
  "id": "cus_01m4ty3c2b5qx7mhd9k8w6s0aa",
  "brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz"
}

Result output:

JSON
{
  "object": "customer_entitlements",
  "customerId": "cus_01m4ty3c2b5qx7mhd9k8w6s0aa",
  "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
  "livemode": false,
  "values": {
    "feature.export": true,
    "seats.max": 20,
    "support.level": "community"
  },
  "sources": [
    {
      "type": "subscription",
      "ref": "sub_01m4ty3c2b5qx7mhd9k8w6s0b0",
      "featureKey": "feature.export",
      "value": true
    },
    {
      "type": "override",
      "ref": "ceo_01m4ty3c2b5qx7mhd9k8w6s0b2",
      "featureKey": "seats.max",
      "value": 20
    },
    {
      "type": "subscription",
      "ref": "sub_01m4ty3c2b5qx7mhd9k8w6s0b0",
      "featureKey": "seats.max",
      "value": 15
    },
    {
      "type": "default",
      "ref": "feat_01m4tx5nj8emwbyf7y9vcf47y8",
      "featureKey": "support.level",
      "value": "community"
    }
  ],
  "computedAt": "2026-10-14T10:00:05.000Z"
}

A lifetime purchase

Arguments:

JSON
{
  "id": "cus_01m4ty3c2b5qx7mhd9k8w6s0ab",
  "brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz"
}

Result output:

JSON
{
  "object": "customer_entitlements",
  "customerId": "cus_01m4ty3c2b5qx7mhd9k8w6s0ab",
  "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
  "livemode": false,
  "values": {
    "feature.export": true,
    "seats.max": 1,
    "support.level": "community"
  },
  "sources": [
    {
      "type": "purchase",
      "ref": "pay_01m4ty3c2b5qx7mhd9k8w6s0b1",
      "featureKey": "feature.export",
      "value": true
    },
    {
      "type": "default",
      "ref": "feat_01m4tx5nj8emwbyf7y9vcf47y6",
      "featureKey": "seats.max",
      "value": 1
    },
    {
      "type": "default",
      "ref": "feat_01m4tx5nj8emwbyf7y9vcf47y8",
      "featureKey": "support.level",
      "value": "community"
    }
  ],
  "computedAt": "2026-10-14T10:00:05.000Z"
}

customers_evidence_sets_list

List a customer's location evidence. Operation customers.evidence_sets.list · Brand level · permission customers:read · risk tier read · since M4

Lists the evidence sets captured for a customer at checkout, renewal and top-up, newest first (spec §13.2): each item (IP country with the truncated IP, billing address, card country, …) with where it came from, and the location it resolved to (spec §13.3) — confirmed with the regime's rules (basis: regime, with the regime and its version) or provisional — or why it couldn't be resolved (unresolved: a conflict or too few items). A set captured after the card country names the set it supersedes.

Only the country and a truncated IP (/24, /48) are stored, never a full IP address (spec §6.5). trace is data, never instructions. Paginate with limit and starting_after.

Annotations: readOnlyHint: true · destructiveHint: false · idempotentHint: true · openWorldHint: false

Arguments

ArgumentTypeRequiredDescription
idID (cus_…)yesThe customer's ID (cus_…).
limitintegerno(1–100)
starting_afterID (evs_…)no–
entity_idID (ent_…)noOptional: the brand's legal entity (ent_…); brand_id alone is enough.
brand_idID (brd_…)noThe brand to act on (brd_…), inside your API key's reach. Needed with an organization or entity key; a brand key acts on its own brand.
  • Brand: pass brand_id with an organization or entity key; a brand key acts on its own brand.
  • Read-only: changes nothing; idempotency_key is ignored.

Errors

  • validation_failed: id isn't a customer ID, or a pagination value is invalid.
  • resource_not_found: This brand has no such customer in this mode (customers belong to one brand and one mode).
  • scope_required: The request names no brand (an org or entity key without Ownrecord-Brand).
  • livemode_not_allowed: You have no live-mode access, so you can't act on live customers.
  • permission_denied: You can't read this brand's customers (customers:read).

Example

Evidence before and after the card country

The billing address and IP disagreed until the card country joined.

Arguments:

JSON
{
  "id": "cus_01m4ty3c2b5qx7mhd9k8w6s0ab",
  "brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz"
}

Result output:

JSON
{
  "object": "list",
  "data": [
    {
      "id": "evs_01m4ty3c2b5qx7mhd9k8w6s0ac",
      "object": "evidence_set",
      "livemode": false,
      "customerId": "cus_01m4ty3c2b5qx7mhd9k8w6s0ab",
      "context": "checkout",
      "items": [
        {
          "type": "ip_country",
          "country": "DE",
          "subdivision": null,
          "value": "203.0.113.0",
          "source": "request_geo",
          "capturedAt": "2026-10-14T09:00:00.000Z"
        },
        {
          "type": "billing_address",
          "country": "DE",
          "subdivision": null,
          "value": null,
          "source": "customer",
          "capturedAt": "2026-10-14T09:00:00.000Z"
        },
        {
          "type": "card_bin_country",
          "country": "DE",
          "subdivision": null,
          "value": null,
          "source": "processor",
          "capturedAt": "2026-10-14T09:30:00.000Z"
        }
      ],
      "status": "resolved",
      "resolved": {
        "country": "DE",
        "subdivision": null,
        "confidence": "conclusive",
        "basis": "regime",
        "regimeId": "EU_OSS_UNION",
        "regimeVersion": "10fc4013168eb593"
      },
      "unresolved": null,
      "rule": {
        "requiredNonConflicting": 2,
        "acceptedTypes": [
          "billing_address",
          "ip_country",
          "card_bin_country",
          "bank_country",
          "phone_country",
          "self_declared"
        ],
        "conflictPolicy": "majority",
        "brandPolicy": null
      },
      "trace": "DE confirmed [DE ×3 (ip_country, billing_address, card_bin_country)] (2 item(s) of billing_address/ip_country/card_bin_country/bank_country/phone_country/self_declared, policy majority)",
      "supersedes": "evs_01m4ty3c2b5qx7mhd9k8w6s0ad",
      "checkoutSessionId": "cs_01m4ty3c2b5qx7mhd9k8w6s0ae",
      "subscriptionId": null,
      "createdAt": "2026-10-14T09:30:00.000Z"
    },
    {
      "id": "evs_01m4ty3c2b5qx7mhd9k8w6s0ad",
      "object": "evidence_set",
      "livemode": false,
      "customerId": "cus_01m4ty3c2b5qx7mhd9k8w6s0ab",
      "context": "checkout",
      "items": [
        {
          "type": "ip_country",
          "country": "DE",
          "subdivision": null,
          "value": "203.0.113.0",
          "source": "request_geo",
          "capturedAt": "2026-10-14T09:00:00.000Z"
        },
        {
          "type": "billing_address",
          "country": "DE",
          "subdivision": null,
          "value": null,
          "source": "customer",
          "capturedAt": "2026-10-14T09:00:00.000Z"
        }
      ],
      "status": "resolved",
      "resolved": {
        "country": "DE",
        "subdivision": null,
        "confidence": "conclusive",
        "basis": "regime",
        "regimeId": "EU_OSS_UNION",
        "regimeVersion": "10fc4013168eb593"
      },
      "unresolved": null,
      "rule": {
        "requiredNonConflicting": 2,
        "acceptedTypes": [
          "billing_address",
          "ip_country",
          "card_bin_country",
          "bank_country",
          "phone_country",
          "self_declared"
        ],
        "conflictPolicy": "majority",
        "brandPolicy": null
      },
      "trace": "DE confirmed [DE ×2 (ip_country, billing_address)] (2 item(s) of billing_address/ip_country/card_bin_country/bank_country/phone_country/self_declared, policy majority)",
      "supersedes": null,
      "checkoutSessionId": "cs_01m4ty3c2b5qx7mhd9k8w6s0ae",
      "subscriptionId": null,
      "createdAt": "2026-10-14T09:00:00.000Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}

customers_get

Get a customer. Operation customers.get · Brand level · permission customers:read · risk tier read · since M4

Returns a customer of the brand in the mode of the request: profile, inferred and declared type, billing address, tax IDs with their latest check and earlier checks, the locked tax country (set at the first successful payment, spec §9.3), processor references and risk. Deleted customers are returned too, with deletedAt. The customer's location evidence is listed by customers.evidence_sets.list.

Annotations: readOnlyHint: true · destructiveHint: false · idempotentHint: true · openWorldHint: false

Arguments

ArgumentTypeRequiredDescription
idID (cus_…)yesThe customer's ID (cus_…).
entity_idID (ent_…)noOptional: the brand's legal entity (ent_…); brand_id alone is enough.
brand_idID (brd_…)noThe brand to act on (brd_…), inside your API key's reach. Needed with an organization or entity key; a brand key acts on its own brand.
  • Brand: pass brand_id with an organization or entity key; a brand key acts on its own brand.
  • Read-only: changes nothing; idempotency_key is ignored.

Errors

Examples

A business customer

Arguments:

JSON
{
  "id": "cus_01m4ty3c2b5qx7mhd9k8w6s0aa",
  "brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz"
}

Result output:

JSON
{
  "id": "cus_01m4ty3c2b5qx7mhd9k8w6s0aa",
  "object": "customer",
  "livemode": false,
  "entityId": "ent_01m4tx5nj8emwbyf7y9vcf47x2",
  "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
  "email": "billing@alpenapps.example",
  "name": "Lena Huber",
  "businessName": "Alpen Apps GmbH",
  "locale": "de-AT",
  "type": "business",
  "declaredType": "business",
  "billingAddress": {
    "line1": "Mariahilfer Straße 1",
    "line2": null,
    "city": "Wien",
    "postalCode": "1060",
    "region": null,
    "country": "AT"
  },
  "taxIds": [
    {
      "id": "ATU00000000",
      "type": "eu_vat",
      "value": "ATU 0000 0000",
      "country": "AT",
      "number": "ATU00000000",
      "verification": {
        "status": "valid",
        "source": "VIES",
        "reason": null,
        "checkedAt": "2026-10-14T09:00:00.000Z",
        "consultationNumber": "WAPIAAAAZ1x2y3",
        "simulated": false
      },
      "history": [],
      "addedAt": "2026-10-14T09:00:00.000Z"
    }
  ],
  "taxCountryLocked": null,
  "taxExempt": null,
  "processorRefs": [],
  "risk": {
    "level": "normal",
    "reasons": [],
    "firstPaymentAt": null,
    "totalPaid": {
      "amount": "0",
      "currency": "EUR"
    }
  },
  "portalLastLoginAt": null,
  "testClockId": null,
  "metadata": {
    "userId": "u_4821"
  },
  "createdAt": "2026-10-14T09:00:00.000Z",
  "updatedAt": "2026-10-14T09:00:00.000Z",
  "deletedAt": null
}

A consumer after the first payment

The first payment locked the tax country to Germany.

Arguments:

JSON
{
  "id": "cus_01m4ty3c2b5qx7mhd9k8w6s0ab",
  "brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz"
}

Result output:

JSON
{
  "id": "cus_01m4ty3c2b5qx7mhd9k8w6s0ab",
  "object": "customer",
  "livemode": false,
  "entityId": "ent_01m4tx5nj8emwbyf7y9vcf47x2",
  "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
  "email": "ana@example.com",
  "name": "Ana Schmidt",
  "businessName": null,
  "locale": "de",
  "type": "individual",
  "declaredType": "individual",
  "billingAddress": {
    "line1": null,
    "line2": null,
    "city": null,
    "postalCode": null,
    "region": null,
    "country": "DE"
  },
  "taxIds": [],
  "taxCountryLocked": {
    "country": "DE",
    "subdivision": null,
    "lockedAt": "2026-10-14T09:30:00.000Z",
    "evidenceSetId": "evs_01m4ty3c2b5qx7mhd9k8w6s0ac"
  },
  "taxExempt": null,
  "processorRefs": [
    {
      "processorConnectionId": "pcon_01m4ty3c2b5qx7mhd9k8w6s0af",
      "customerRef": "cus_QxY12AbC"
    }
  ],
  "risk": {
    "level": "normal",
    "reasons": [],
    "firstPaymentAt": "2026-10-14T09:30:00.000Z",
    "totalPaid": {
      "amount": "119000000",
      "currency": "EUR"
    }
  },
  "portalLastLoginAt": null,
  "testClockId": null,
  "metadata": {},
  "createdAt": "2026-10-14T09:00:00.000Z",
  "updatedAt": "2026-10-14T09:30:00.000Z",
  "deletedAt": null
}

customers_list

List customers. Operation customers.list · Brand level · permission customers:read · risk tier read · since M4

Lists the brand's customers in the mode of the request, newest first: only this organization's customers, never another organization's. Deleted customers are left out unless includeDeleted=true.

  • email: the customer with exactly this address (addresses are compared in lower case);
  • emailPrefix: customers whose address starts with this text (search);
  • type: individual, business or unknown.

Paginate with limit (1–100, default 10) and starting_after (the next_cursor of the previous page).

Annotations: readOnlyHint: true · destructiveHint: false · idempotentHint: true · openWorldHint: false

Arguments

ArgumentTypeRequiredDescription
limitintegerno(1–100)
starting_afterID (cus_…)noThe customer's ID (cus_…).
emailstringnoOnly the customer with exactly this email address. (at most 254 characters)
emailPrefixstringnoCustomers whose email starts with this text (search). (1–254 characters)
typeone of individual, business, unknownno–
includeDeletedboolean or stringnoInclude deleted customers (default false). true/false, also as a query string.
entity_idID (ent_…)noOptional: the brand's legal entity (ent_…); brand_id alone is enough.
brand_idID (brd_…)noThe brand to act on (brd_…), inside your API key's reach. Needed with an organization or entity key; a brand key acts on its own brand.
  • Brand: pass brand_id with an organization or entity key; a brand key acts on its own brand.
  • Read-only: changes nothing; idempotency_key is ignored.

Errors

Examples

Find a customer by email

Arguments:

JSON
{
  "email": "ana@example.com",
  "brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz"
}

Result output:

JSON
{
  "object": "list",
  "data": [
    {
      "id": "cus_01m4ty3c2b5qx7mhd9k8w6s0ab",
      "object": "customer",
      "livemode": false,
      "entityId": "ent_01m4tx5nj8emwbyf7y9vcf47x2",
      "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
      "email": "ana@example.com",
      "name": "Ana Schmidt",
      "businessName": null,
      "locale": "de",
      "type": "individual",
      "declaredType": "individual",
      "billingAddress": {
        "line1": null,
        "line2": null,
        "city": null,
        "postalCode": null,
        "region": null,
        "country": "DE"
      },
      "taxIds": [],
      "taxCountryLocked": {
        "country": "DE",
        "subdivision": null,
        "lockedAt": "2026-10-14T09:30:00.000Z",
        "evidenceSetId": "evs_01m4ty3c2b5qx7mhd9k8w6s0ac"
      },
      "taxExempt": null,
      "processorRefs": [
        {
          "processorConnectionId": "pcon_01m4ty3c2b5qx7mhd9k8w6s0af",
          "customerRef": "cus_QxY12AbC"
        }
      ],
      "risk": {
        "level": "normal",
        "reasons": [],
        "firstPaymentAt": "2026-10-14T09:30:00.000Z",
        "totalPaid": {
          "amount": "119000000",
          "currency": "EUR"
        }
      },
      "portalLastLoginAt": null,
      "testClockId": null,
      "metadata": {},
      "createdAt": "2026-10-14T09:00:00.000Z",
      "updatedAt": "2026-10-14T09:30:00.000Z",
      "deletedAt": null
    }
  ],
  "has_more": false,
  "next_cursor": null
}

Business customers, two per page

Arguments:

JSON
{
  "type": "business",
  "limit": 2,
  "brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz"
}

Result output:

JSON
{
  "object": "list",
  "data": [
    {
      "id": "cus_01m4ty3c2b5qx7mhd9k8w6s0aa",
      "object": "customer",
      "livemode": false,
      "entityId": "ent_01m4tx5nj8emwbyf7y9vcf47x2",
      "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
      "email": "billing@alpenapps.example",
      "name": "Lena Huber",
      "businessName": "Alpen Apps GmbH",
      "locale": "de-AT",
      "type": "business",
      "declaredType": "business",
      "billingAddress": {
        "line1": "Mariahilfer Straße 1",
        "line2": null,
        "city": "Wien",
        "postalCode": "1060",
        "region": null,
        "country": "AT"
      },
      "taxIds": [
        {
          "id": "ATU00000000",
          "type": "eu_vat",
          "value": "ATU 0000 0000",
          "country": "AT",
          "number": "ATU00000000",
          "verification": {
            "status": "valid",
            "source": "VIES",
            "reason": null,
            "checkedAt": "2026-10-14T09:00:00.000Z",
            "consultationNumber": "WAPIAAAAZ1x2y3",
            "simulated": false
          },
          "history": [],
          "addedAt": "2026-10-14T09:00:00.000Z"
        }
      ],
      "taxCountryLocked": null,
      "taxExempt": null,
      "processorRefs": [],
      "risk": {
        "level": "normal",
        "reasons": [],
        "firstPaymentAt": null,
        "totalPaid": {
          "amount": "0",
          "currency": "EUR"
        }
      },
      "portalLastLoginAt": null,
      "testClockId": null,
      "metadata": {
        "userId": "u_4821"
      },
      "createdAt": "2026-10-14T09:00:00.000Z",
      "updatedAt": "2026-10-14T09:00:00.000Z",
      "deletedAt": null
    },
    {
      "id": "cus_01m4ty3c2b5qx7mhd9k8w6s0a9",
      "object": "customer",
      "livemode": false,
      "entityId": "ent_01m4tx5nj8emwbyf7y9vcf47x2",
      "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
      "email": "billing@alpenapps.example",
      "name": "Lena Huber",
      "businessName": "Alpen Apps GmbH",
      "locale": "de-AT",
      "type": "business",
      "declaredType": "business",
      "billingAddress": {
        "line1": "Mariahilfer Straße 1",
        "line2": null,
        "city": "Wien",
        "postalCode": "1060",
        "region": null,
        "country": "AT"
      },
      "taxIds": [
        {
          "id": "ATU00000000",
          "type": "eu_vat",
          "value": "ATU 0000 0000",
          "country": "AT",
          "number": "ATU00000000",
          "verification": {
            "status": "valid",
            "source": "VIES",
            "reason": null,
            "checkedAt": "2026-10-14T09:00:00.000Z",
            "consultationNumber": "WAPIAAAAZ1x2y3",
            "simulated": false
          },
          "history": [],
          "addedAt": "2026-10-14T09:00:00.000Z"
        }
      ],
      "taxCountryLocked": null,
      "taxExempt": null,
      "processorRefs": [],
      "risk": {
        "level": "normal",
        "reasons": [],
        "firstPaymentAt": null,
        "totalPaid": {
          "amount": "0",
          "currency": "EUR"
        }
      },
      "portalLastLoginAt": null,
      "testClockId": null,
      "metadata": {
        "userId": "u_4821"
      },
      "createdAt": "2026-10-14T09:00:00.000Z",
      "updatedAt": "2026-10-14T09:00:00.000Z",
      "deletedAt": null
    }
  ],
  "has_more": true,
  "next_cursor": "cus_01m4ty3c2b5qx7mhd9k8w6s0a9"
}

customers_tax_ids_add

Add a tax ID to a customer. Operation customers.tax_ids.add · Brand level · permission customers:write · risk tier write · since M4

Adds a tax ID to a customer after checking it with its register (VIES for EU VAT IDs, HMRC for UK VAT numbers, the Swiss UID register; Norwegian and US numbers by format; other types are kept unverified). The answer is stored with the ID: status, source, reason, consultation number and time (spec §9.4). A malformed number is refused (tax_id_invalid); one the register doesn't know is stored as invalid and doesn't make the customer a business. Dry runs simulate the check.

At most 5 tax IDs per customer; the same number twice is refused (customer_tax_id_exists). The type is inferred again (spec §13.1). Emits customer.updated.

Annotations: readOnlyHint: false · destructiveHint: false · idempotentHint: false · openWorldHint: true

Arguments

ArgumentTypeRequiredDescription
idID (cus_…)yesThe customer's ID (cus_…).
typestringyesThe tax ID's type: eu_vat, gb_vat, ch_uid/ch_vat, no_org/no_vat or us_ein. Other types are kept but can't be checked (unverified).
valuestringyesThe number as the customer gave it, with or without the country prefix and separators. (1–50 characters)
countrystringyesThe country that issued the tax ID (ISO 3166-1 alpha-2; EL = Greece).
entity_idID (ent_…)noOptional: the brand's legal entity (ent_…); brand_id alone is enough.
brand_idID (brd_…)noThe brand to act on (brd_…), inside your API key's reach. Needed with an organization or entity key; a brand key acts on its own brand.
idempotency_keystringnoA unique string for this change. Retrying with the same key and arguments never acts twice. When left out, the server generates one and returns it in the result's idempotency_key. (1–255 characters)
dry_runbooleannotrue: check permissions and rules and compute the result, then roll everything back. Nothing is saved. (default false)
  • Brand: pass brand_id with an organization or entity key; a brand key acts on its own brand.
  • Idempotency: the result returns the idempotency_key used, yours or one the server generated. Retry with it: a call with the same key and arguments never acts twice (keys are kept for 24 hours).
  • Dry run: supported. dry_run: true checks permissions and rules and computes the result, then rolls everything back.

Errors

  • validation_failed: A field is missing or malformed.
  • tax_id_invalid: A tax ID's number isn't valid for its type and country (format, checksum, another country's prefix, a Northern Ireland XI number); details.reason says which. Nothing is stored. Types Ownrecord can't check (e.g. au_abn) are stored as unverified instead.
  • resource_not_found: This brand has no such customer in this mode (customers belong to one brand and one mode).
  • customer_deleted: The customer was deleted.
  • customer_tax_id_exists: The customer already has this tax ID (details.tax_id_id).
  • customer_tax_id_limit: The customer already has 5 tax IDs.
  • version_conflict: The customer changed at the same moment; retry.
  • scope_required: The request names no brand (an org or entity key without Ownrecord-Brand).
  • livemode_not_allowed: You have no live-mode access, so you can't act on live customers.
  • permission_denied: You can't change this brand's customers (customers:write: owners, admins and support).

Example

Add an Austrian VAT ID

Arguments:

JSON
{
  "id": "cus_01m4ty3c2b5qx7mhd9k8w6s0aa",
  "type": "eu_vat",
  "value": "ATU 0000 0000",
  "country": "AT",
  "brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz",
  "idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}

Result output:

JSON
{
  "id": "cus_01m4ty3c2b5qx7mhd9k8w6s0aa",
  "object": "customer",
  "livemode": false,
  "entityId": "ent_01m4tx5nj8emwbyf7y9vcf47x2",
  "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
  "email": "billing@alpenapps.example",
  "name": "Lena Huber",
  "businessName": "Alpen Apps GmbH",
  "locale": "de-AT",
  "type": "business",
  "declaredType": "business",
  "billingAddress": {
    "line1": "Mariahilfer Straße 1",
    "line2": null,
    "city": "Wien",
    "postalCode": "1060",
    "region": null,
    "country": "AT"
  },
  "taxIds": [
    {
      "id": "ATU00000000",
      "type": "eu_vat",
      "value": "ATU 0000 0000",
      "country": "AT",
      "number": "ATU00000000",
      "verification": {
        "status": "valid",
        "source": "VIES",
        "reason": null,
        "checkedAt": "2026-10-14T09:00:00.000Z",
        "consultationNumber": "WAPIAAAAZ1x2y3",
        "simulated": false
      },
      "history": [],
      "addedAt": "2026-10-14T09:00:00.000Z"
    }
  ],
  "taxCountryLocked": null,
  "taxExempt": null,
  "processorRefs": [],
  "risk": {
    "level": "normal",
    "reasons": [],
    "firstPaymentAt": null,
    "totalPaid": {
      "amount": "0",
      "currency": "EUR"
    }
  },
  "portalLastLoginAt": null,
  "testClockId": null,
  "metadata": {
    "userId": "u_4821"
  },
  "createdAt": "2026-10-14T09:00:00.000Z",
  "updatedAt": "2026-10-14T09:00:00.000Z",
  "deletedAt": null
}

customers_tax_ids_delete

Remove a tax ID from a customer. Operation customers.tax_ids.delete · Brand level · permission customers:write · risk tier write · since M4

Removes a tax ID from a customer. taxIdId is the tax ID's id on the customer: its canonical number, e.g. ATU12345678. Past sales keep the check they were quoted with; future sales no longer use the ID. The type is inferred again (spec §13.1): without a tax ID, a customer is a business only when declared one with a business name. Emits customer.updated.

Annotations: readOnlyHint: false · destructiveHint: true · idempotentHint: false · openWorldHint: false

Arguments

ArgumentTypeRequiredDescription
idID (cus_…)yesThe customer's ID (cus_…).
taxIdIdstringyesThe tax ID's id on the customer: its canonical number, e.g. ATU12345678.
entity_idID (ent_…)noOptional: the brand's legal entity (ent_…); brand_id alone is enough.
brand_idID (brd_…)noThe brand to act on (brd_…), inside your API key's reach. Needed with an organization or entity key; a brand key acts on its own brand.
idempotency_keystringnoA unique string for this change. Retrying with the same key and arguments never acts twice. When left out, the server generates one and returns it in the result's idempotency_key. (1–255 characters)
dry_runbooleannotrue: check permissions and rules and compute the result, then roll everything back. Nothing is saved. (default false)
  • Brand: pass brand_id with an organization or entity key; a brand key acts on its own brand.
  • Idempotency: the result returns the idempotency_key used, yours or one the server generated. Retry with it: a call with the same key and arguments never acts twice (keys are kept for 24 hours).
  • Dry run: supported. dry_run: true checks permissions and rules and computes the result, then rolls everything back.

Errors

Example

Remove the Austrian VAT ID

The customer keeps its business name, so it stays a business.

Arguments:

JSON
{
  "id": "cus_01m4ty3c2b5qx7mhd9k8w6s0aa",
  "taxIdId": "ATU00000000",
  "brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz",
  "idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}

Result output:

JSON
{
  "id": "cus_01m4ty3c2b5qx7mhd9k8w6s0aa",
  "object": "customer",
  "livemode": false,
  "entityId": "ent_01m4tx5nj8emwbyf7y9vcf47x2",
  "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
  "email": "billing@alpenapps.example",
  "name": "Lena Huber",
  "businessName": "Alpen Apps GmbH",
  "locale": "de-AT",
  "type": "business",
  "declaredType": "business",
  "billingAddress": {
    "line1": "Mariahilfer Straße 1",
    "line2": null,
    "city": "Wien",
    "postalCode": "1060",
    "region": null,
    "country": "AT"
  },
  "taxIds": [],
  "taxCountryLocked": null,
  "taxExempt": null,
  "processorRefs": [],
  "risk": {
    "level": "normal",
    "reasons": [],
    "firstPaymentAt": null,
    "totalPaid": {
      "amount": "0",
      "currency": "EUR"
    }
  },
  "portalLastLoginAt": null,
  "testClockId": null,
  "metadata": {
    "userId": "u_4821"
  },
  "createdAt": "2026-10-14T09:00:00.000Z",
  "updatedAt": "2026-10-14T09:30:00.000Z",
  "deletedAt": null
}

customers_update

Update a customer. Operation customers.update · Brand level · permission customers:write · risk tier write · since M4

Changes a customer's email, name, business name, declared type, language, billing address or metadata. Send only the fields to change; null removes an optional one. billingAddress and metadata are replaced as a whole.

The type is inferred again (spec §13.1). Tax IDs have their own operations (customers.tax_ids.add, customers.tax_ids.delete), and the locked tax country changes only through payments (spec §9.3). A changed billing address is used as evidence at the next checkout; it doesn't change where past sales were taxed.

Emits customer.updated with the old values in previous_attributes (nothing when nothing changed).

Annotations: readOnlyHint: false · destructiveHint: false · idempotentHint: true · openWorldHint: false

Arguments

ArgumentTypeRequiredDescription
idID (cus_…)yesThe customer's ID (cus_…).
emailstringno(at most 254 characters)
namestring or nullnonull removes it.
businessNamestring or nullnonull removes it.
typeone of individual, business, unknownnoWhat you say the customer is: individual, business (needs businessName or a tax ID) or unknown. The stored type is inferred: a tax ID that isn't rejected makes the customer a business (spec §13.1).
localestring or nullnonull removes it.
billingAddressobject or nullnoReplaces the address; null removes it.
metadataobjectnoReplaces the metadata (send {} to clear it).
entity_idID (ent_…)noOptional: the brand's legal entity (ent_…); brand_id alone is enough.
brand_idID (brd_…)noThe brand to act on (brd_…), inside your API key's reach. Needed with an organization or entity key; a brand key acts on its own brand.
idempotency_keystringnoA unique string for this change. Retrying with the same key and arguments never acts twice. When left out, the server generates one and returns it in the result's idempotency_key. (1–255 characters)
dry_runbooleannotrue: check permissions and rules and compute the result, then roll everything back. Nothing is saved. (default false)
  • Brand: pass brand_id with an organization or entity key; a brand key acts on its own brand.
  • Idempotency: the result returns the idempotency_key used, yours or one the server generated. Retry with it: a call with the same key and arguments never acts twice (keys are kept for 24 hours).
  • Dry run: supported. dry_run: true checks permissions and rules and computes the result, then rolls everything back.

Errors

  • validation_failed: Nothing to change, a field is malformed, or the customer would be a declared business without a business name or a tax ID.
  • resource_not_found: This brand has no such customer in this mode (customers belong to one brand and one mode).
  • customer_deleted: The customer was deleted.
  • customer_email_taken: Another active customer of the brand has the new email address in this mode.
  • version_conflict: The customer changed at the same moment; retry.
  • scope_required: The request names no brand (an org or entity key without Ownrecord-Brand).
  • livemode_not_allowed: You have no live-mode access, so you can't act on live customers.
  • permission_denied: You can't change this brand's customers (customers:write: owners, admins and support).

Example

Set the language and the full address

Arguments:

JSON
{
  "id": "cus_01m4ty3c2b5qx7mhd9k8w6s0ab",
  "locale": "de-DE",
  "billingAddress": {
    "line1": "Torstraße 5",
    "city": "Berlin",
    "postalCode": "10119",
    "country": "DE"
  },
  "brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz",
  "idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}

Result output:

JSON
{
  "id": "cus_01m4ty3c2b5qx7mhd9k8w6s0ab",
  "object": "customer",
  "livemode": false,
  "entityId": "ent_01m4tx5nj8emwbyf7y9vcf47x2",
  "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
  "email": "ana@example.com",
  "name": "Ana Schmidt",
  "businessName": null,
  "locale": "de-DE",
  "type": "individual",
  "declaredType": "individual",
  "billingAddress": {
    "line1": "Torstraße 5",
    "line2": null,
    "city": "Berlin",
    "postalCode": "10119",
    "region": null,
    "country": "DE"
  },
  "taxIds": [],
  "taxCountryLocked": {
    "country": "DE",
    "subdivision": null,
    "lockedAt": "2026-10-14T09:30:00.000Z",
    "evidenceSetId": "evs_01m4ty3c2b5qx7mhd9k8w6s0ac"
  },
  "taxExempt": null,
  "processorRefs": [
    {
      "processorConnectionId": "pcon_01m4ty3c2b5qx7mhd9k8w6s0af",
      "customerRef": "cus_QxY12AbC"
    }
  ],
  "risk": {
    "level": "normal",
    "reasons": [],
    "firstPaymentAt": "2026-10-14T09:30:00.000Z",
    "totalPaid": {
      "amount": "119000000",
      "currency": "EUR"
    }
  },
  "portalLastLoginAt": null,
  "testClockId": null,
  "metadata": {},
  "createdAt": "2026-10-14T09:00:00.000Z",
  "updatedAt": "2026-10-14T09:30:00.000Z",
  "deletedAt": null
}