1. Onboard a customer and give them a wallet
The most common flow. Create the customer, then open an account naming them.customerId is what makes the account a wallet belonging to that customer. Omit it and the account belongs to your business.
The branch that matters. If the customer was created but the account call failed, you have a customer with no wallet — and retrying the whole flow hits 409 customer_already_exists. Make the create idempotent from your side:
409 customer_already_exists covers externalReference and every identity number, so “already exists” does not always mean “the one I am looking for”.
2. Keep your records and Sakawave in step
Your system is the source of truth for customer details. When something changes there, push it.PATCH:
- Absent leaves alone;
nullclears.{"middleName": null}erases a middle name. OmittingmiddleNamekeeps it. addressreplaces wholesale. It is not merged field by field. Send the complete address, or you will silently clearline2,state, andpostalCode.- Type-specific fields are refused, not ignored. Sending
namefor an individual returns400 customer_fields_do_not_match_typewith the offending names infields. This catches the common bug where one code path patches every customer with the same payload shape.
PATCH emits customer.updated, and a receiver that writes back on every event will chase its own tail.
3. Find customers
Reads are filtered withfield=value, or field:operator=value where the field supports more than equality.
A repeated parameter and a comma-separated one mean the same thing:
jurisdiction:in=NG&jurisdiction:in=GH equals jurisdiction:in=NG,GH.
Unknown filters are rejected by name rather than ignored — ?statuss=active fails with 400 and tells you which parameter it did not recognise. This is deliberate: a silently ignored filter returns a wider result set than you asked for, which is how the wrong customers end up in a report.
Paging a full export. Page size defaults to 25 and caps at 100; a larger value is rejected rather than quietly capped, so your arithmetic stays right. Results are ordered newest first with id as a tiebreaker, so pages are stable unless a customer is created mid-scan — pin createdAt:lte at the start of the job if that matters.
4. Offboard a customer
Archiving is refused while the customer still holds anything live.204 means archived. A 409 customer_has_active_products means there is still an open wallet account or a live card:
- The reference is released. After archiving,
externalReferenceand the identity numbers become reusable by a new customer. If your own records rely on that reference being unique forever, keep your own history — Sakawave will not stop it being reissued. - There is no unarchive. Recreating produces a new
id. Anything you stored against the old one still points at a customer that reads answer404for.
Archiving emits no webhook. A local mirror should detect archives by reconciling against
GET /v1/customers, treating a record that has disappeared as archived.