Create, retrieve, and list customers. A customer represents the end shopper for whom you make payments.
The Customer object
{
"id": "cus_01HCUSXYZ...",
"email": "jane@example.com",
"name": "Jane Doe",
"phone": "+41 79 555 12 34",
"locale": "de-CH",
"external_id": "user_42",
"billing_address": {
"line1": "Bahnhofstrasse 1",
"city": "Zürich",
"postal_code": "8001",
"country": "CH"
},
"delivery_address": null,
"date_of_birth": null,
"metadata": { "plan": "pro" },
"created_at": "2026-05-20T12:00:00Z"
}
| Field | Type | Notes |
|---|---|---|
id |
string | Stable, prefixed with cus_. |
email |
string | Unique per merchant, case-insensitive. |
name |
string | Free text. |
phone |
string | Free text. International format recommended. |
locale |
string | xx-XX (e.g. de-CH, en-US). |
external_id |
string | Your own ID for this customer. Unique per merchant if provided. |
billing_address |
object | Free-text address fields; country is ISO 3166-1 alpha-2. |
delivery_address |
object | Same shape as billing_address. |
date_of_birth |
string | ISO 8601 date (1990-04-25). |
metadata |
object | ≤ 20 keys, values ≤ 500 chars. |
created_at |
string | ISO 8601 UTC. |
Create a customer
POST /api/v1/customers
Required headers
Authorization: Bearer sk_test_...
Content-Type: application/json
Idempotency-Key: <recommended>
Required body fields
| Field | Type |
|---|---|
email |
string |
That's it. Everything else is optional.
Example — minimal
curl -X POST https://app.swisspay.ai/api/v1/customers \
-H "Authorization: Bearer sk_test_..." \
-H "Content-Type: application/json" \
-d '{
"email": "jane@example.com",
"name": "Jane Doe"
}'
Example — full
{
"email": "jane@example.com",
"name": "Jane Doe",
"phone": "+41 79 555 12 34",
"locale": "de-CH",
"external_id": "user_42",
"billing_address": {
"line1": "Bahnhofstrasse 1",
"city": "Zürich",
"postal_code": "8001",
"country": "CH"
},
"metadata": { "plan": "pro" }
}
Example — with delivery address and date of birth
A mismatch between billing_address and delivery_address is a well-known fraud signal; passing both lets the risk engine reason about it. date_of_birth is required by some payment methods.
{
"email": "jane@example.com",
"name": "Jane Doe",
"billing_address": {
"line1": "Bahnhofstrasse 1",
"city": "Zürich",
"postal_code": "8001",
"country": "CH"
},
"delivery_address": {
"line1": "Rue du Mont-Blanc 4",
"city": "Genève",
"postal_code": "1201",
"country": "CH"
},
"date_of_birth": "1990-04-25"
}
Both fields are persisted, echoed back on read, and forwarded automatically whenever this customer is attached to a payment.
Validation errors
| Error | Cause |
|---|---|
422 customer_email_taken |
Email already on file for this account. |
422 customer_external_id_taken |
external_id already on file for this account. |
422 invalid_params: locale |
locale not in xx-XX form. |
422 invalid_params: country |
billing_address.country or delivery_address.country isn't a valid ISO 3166-1 alpha-2 code. |
Retrieve a customer
GET /api/v1/customers/{id}
curl https://app.swisspay.ai/api/v1/customers/cus_01HCUSXYZ \
-H "Authorization: Bearer sk_test_..."
Unknown IDs return 404 Not Found.
List customers
GET /api/v1/customers?page=1&per_page=20
Query parameters
| Param | Default | Notes |
|---|---|---|
page |
1 |
|
per_page |
20 |
Max 100. |
email |
— | Exact match, case-insensitive. URL-encode the @. |
Example — filter by email
curl 'https://app.swisspay.ai/api/v1/customers?email=jane%40example.com' \
-H "Authorization: Bearer sk_test_..."
Response
{
"data": [ /* customer objects */ ],
"page": 1,
"per_page": 20,
"total_count": 7,
"has_more": false
}
Attaching customers to payments
Two ways:
- Reference an existing customer — pass
customer: "cus_01HCUSXYZ..."onPOST /payments. - Create inline — pass an inline
customerobject onPOST /payments. We create the customer if it doesn't already exist (matched byemail) and attach it.
Either way, the customer's delivery_address and date_of_birth (when present) are automatically forwarded to the upstream risk engine.
Was this article helpful?
That’s Great!
Thank you for your feedback
Sorry! We couldn't be helpful
Thank you for your feedback
Feedback sent
We appreciate your effort and will try to fix the article