Customers & B2B
Customers
Customer profiles, addresses, segments, GDPR redaction, and B2B VAT support.
Lifecycle states
guest created at checkout from email — no password
invited staff sent an invite, not yet accepted
enabled full account, can log in
disabled staff blocked
declined invite refused
redacted GDPR right-to-be-forgotten applied
A guest customer can be upgraded to enabled later (when they set
a password). Orders made as a guest stay attributed via email.
Create a customer
curl -X POST "$API/customers.json" \
-H "Authorization: Bearer $NEVIOS_KEY" -H "Content-Type: application/json" \
-d '{
"email": "[email protected]",
"first_name": "Anna",
"last_name": "Nováková",
"phone": "+420...",
"accepts_marketing": true,
"marketing_opt_in_level": "confirmed_opt_in",
"tags": ["vip", "wholesale"]
}'
Per (account, email) is unique — duplicate emails return 409.
Addresses
1:N per customer. Pickup-point fields (pickup_point_carrier,
pickup_point_id, pickup_point_name) are an all-or-nothing
group: either the address is a pickup point with all three set, or it
isn't (regular street address).
is_default is exclusive within a customer — promoting a new
default automatically demotes the previous one. The customer's
default_address_id always points at the active default.
B2B VAT
Customers carry vat_number, vat_country_code, vat_valid,
vat_validated_at. Validation happens via VIES at
checkout time.
The combination (vat_valid=true AND non-domestic shipping country AND commerce.tax.b2b_reverse_charge=true) triggers reverse charge
on the order: zero VAT, prices presented net, invoice notes added.
Segments (DSL)
Customer segments are dynamic groups defined by a JSONB rule:
{
"name": "VIP",
"definition": {
"all": [
{ "field": "customer.total_spent_cents", "op": "gt", "value": 100000 },
{ "field": "customer.tags", "op": "contains", "value": "wholesale" }
]
}
}
Operators include eq | neq | gt | gte | lt | lte | in | not_in | contains | starts_with | within_days | before | after. Field
allow-list prevents arbitrary SQL. Members are materialized via
POST /{handle}/customer_segments/{id}/evaluate.json and stored in
customer_segment_members.
GDPR redaction
POST /admin/2026-01/{handle}/customers/{id}/redact.json triggers a
full PII anonymization: email becomes REDACTED-{id}@redacted.local,
names become REDACTED, addresses are deleted, marketing flags are
cleared, state='redacted', archived_at set. Order history
preserved with customer_id still attached for audit.
A redacted customer cannot be updated (409) and cannot receive new
orders or messages.
Customer order spend tracking
When a payment hits paid, the orders service auto-bumps the
customer's total_spent_cents, orders_count, last_order_at,
last_order_id, last_order_name. first_order_at is set on
the very first conversion.
Endpoints
| Verb | Path |
|---|---|
| POST | /{handle}/customers.json |
| GET | /{handle}/customers.json (filter: state, tag, email, marketing) |
| GET | /{handle}/customers/{id_or_email}.json |
| PUT | /{handle}/customers/{id}.json (optimistic version) |
| POST | /{handle}/customers/{id}/redact.json |
| POST | /{handle}/customers/{id}/addresses.json |
| DELETE | /{handle}/customers/{id}/addresses/{addr_id}.json |
| POST | /{handle}/customer_segments.json |
| POST | /{handle}/customer_segments/{id}/evaluate.json |
| GET | /{handle}/customer_segments/{id}/members.json |
Next: Discounts & vouchers.