Skip to content

Delete a customer

The customers.delete operation: DELETE /api/v1/customers/{id} in the REST API and the customers_delete tool in the MCP server.

DELETE/api/v1/customers/{id}

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.

At a glance

  • REST: DELETE /api/v1/customers/{id}
  • MCP tool: customers_delete
  • Operation ID: customers.delete
  • Scope: Brand
  • Permission: customers:admin
  • Risk tier: write
  • Dry run: Supported (send Ownrecord-Dry-Run: true)
  • Idempotency: Idempotency-Key optional
  • Modes: Test and live
  • Authentication: API key with the customers:admin scope
  • Since: M4

Request

Path parameters

FieldTypeDescription
idcus_… IDThe customer's ID (cus_…).

Body

A JSON object (Content-Type: application/json):

FieldTypeRequiredDescription
reasonstringNoWhy; recorded in the audit log.

Response

200 OK with a JSON object:

FieldTypeDescription
idcus_… ID
object"customer"
livemodeboolean
entityIdent_… ID
brandIdbrd_… ID
emailstring
namestring or null
businessNamestring or null
localestring or null
typeone of individual, business, unknownInferred (spec §13.1): business with a tax ID that isn't rejected, or with a business name when declared a business. Tax is decided per sale: only a valid tax ID makes a sale business-to-business.
declaredTypeone of individual, business, unknownWhat you declared.
billingAddressobject or null
taxIdsarray of object
taxIds[].idstringIdentifies the tax ID on the customer: its canonical number, e.g. ATU12345678.
taxIds[].typestringeu_vat, gb_vat, ch_uid/ch_vat, no_org/no_vat, us_ein, or another type (unverified).
taxIds[].valuestringThe number as given.
taxIds[].countrystring
taxIds[].numberstring or nullThe canonical number (null for types Ownrecord can't check).
taxIds[].verificationobjectThe latest check (spec §9.4).
taxIds[].verification.statusone of valid, invalid, unavailable, format_only, unverifiedvalid, invalid, unavailable (the register couldn't answer), format_only (no register: format and checksum) or unverified (a type Ownrecord can't check).
taxIds[].verification.sourcestringWho decided: VIES, HMRC, CH_UID, FORMAT (format and checksum only) or NONE.
taxIds[].verification.reasonstring or nullWhy, e.g. not_registered or service_unavailable.
taxIds[].verification.checkedAtdate-time
taxIds[].verification.consultationNumberstring or nullThe register's proof of the check (VIES request identifier, HMRC consultation number).
taxIds[].verification.simulatedbooleanA fixture answer (development and test environments), not a register's.
taxIds[].historyarray of objectEarlier checks, newest first (at most 10).
taxIds[].history[].statusone of valid, invalid, unavailable, format_only, unverifiedvalid, invalid, unavailable (the register couldn't answer), format_only (no register: format and checksum) or unverified (a type Ownrecord can't check).
taxIds[].history[].sourcestringWho decided: VIES, HMRC, CH_UID, FORMAT (format and checksum only) or NONE.
taxIds[].history[].reasonstring or nullWhy, e.g. not_registered or service_unavailable.
taxIds[].history[].checkedAtdate-time
taxIds[].history[].consultationNumberstring or nullThe register's proof of the check (VIES request identifier, HMRC consultation number).
taxIds[].history[].simulatedbooleanA fixture answer (development and test environments), not a register's.
taxIds[].addedAtdate-time
taxCountryLockedobject or nullWhere the customer's purchases are taxed (spec §9.3): set at the first successful payment, moved only when a top-up's evidence resolves to another country.
taxExemptobject or nullTax exemption (spec §9.5). Not applied yet: exemption certificates come in a later release.
processorRefsarray of objectThe customer at each payment processor used (set by checkout).
processorRefs[].processorConnectionIdpcon_… ID
processorRefs[].customerRefstring
riskobject
risk.levelone of normal, elevated, blocked
risk.reasonsarray of string
risk.firstPaymentAtdate-time or null
risk.totalPaidmoney
portalLastLoginAtdate-time or null
testClockIdclk_… ID or nullTest mode: the test clock the customer was created on (spec §16.13).
metadataobject
createdAtdate-time
updatedAtdate-time
deletedAtdate-time or nullWhen the customer was deleted (soft delete); null while active.

Examples

Delete a duplicate customer

HTTP
DELETE /api/v1/customers/cus_01m4ty3c2b5qx7mhd9k8w6s0ab
Authorization: Bearer or_test_…
Content-Type: application/json

{
  "reason": "Duplicate of cus_01m4ty3c2b5qx7mhd9k8w6s0aa"
}

Response (200):

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"
}

Errors

CodeHTTP statusWhenWhat to do
validation_failed400id isn't a customer ID, or the reason is too long.Fix the fields listed in details.issues and send the request again.
resource_not_found404This brand has no such customer in this mode (customers belong to one brand and one mode).Check the ID and that your credentials are scoped to the right organization, entity, brand and mode.
customer_deleted400The customer was already deleted.Create a new customer for this buyer. Deleted customers stay readable for the records they belong to, but can't be changed.
version_conflict409The customer changed at the same moment; retry.Fetch the object again and retry the change.
scope_required400The request names no brand (an org or entity key without Ownrecord-Brand).Call the operation with credentials or a target at its level: an organization, a legal entity, a brand or the platform (details.required_scope).
livemode_not_allowed403You have no live-mode access, so you can't act on live customers.Use test mode, or credentials for the target's mode. Developers need live access granted by an organization owner or admin.
permission_denied403You can't delete this brand's customers (customers:admin: owners and admins).Ask an organization owner or admin for a role or scope that allows this action.

It can also return these common errors: api_version_unsupported, invalid_json, unsupported_media_type, authentication_required, api_key_invalid, idempotency_key_reused, idempotency_in_progress, approval_required, approval_rejected, approval_expired, stale_approval, approval_policy_denied, rate_limited, internal_error.