Skip to content

Manage customers (sub-accounts)

A customer is an optional sub-account: a first-class, queryable handle for one of your own end-users, to which you attach wallets. It solves attribution, not accounting: balances always stay at the workspace level.

Skip it entirely if you do not need per-user segregation; wallets then belong to the workspace itself and external_ref on each wallet is enough. Reach for customers when your product has users who each accumulate deposits over time, and “everything this user ever received” is a question you will ask.

POST /v2/customers (scope customers:write), with your own opaque id:

{ "external_ref": "user_8f3a2c", "label": "Premium tier" }

Then create wallets carrying customer_id, and the attribution is queryable both ways: GET /v2/wallets?customer_id=... lists a customer’s addresses, and each wallet response carries its customer_id.

Three rules worth internalising:

  • external_ref is yours and opaque: never PII. No emails, no phone numbers, no names. It is unique per workspace and mode, and it is immutable; creating the same external_ref twice answers 409 and points you at the lookup instead (GET /v2/customers?external_ref=...).
  • label and metadata are yours too, editable via PATCH /v2/customers/{id}, and equally not a place for personal data. metadata is a free-form object, opaque to CowriePay.
  • A customer is per mode, like every resource: the same external_ref can exist once in Sandbox and once in Live, and they are unrelated.

Archiving retires the label, not the monitoring

Section titled “Archiving retires the label, not the monitoring”

PATCH /v2/customers/{id} with status: "ARCHIVED" retires the sub-account from your active set. It does not stop monitoring its addresses: a late deposit to an archived customer’s wallet is still detected, credited and swept, exactly as before. Archiving is bookkeeping, never a way to turn an address off, because on a public blockchain nothing stops the sender from sending.