Customers are the clients saved on your Customers page. The API lists them, finds one by email, adds them and updates them, with the same rules as the dashboard: one customer per email address, in any letter case. Card buyers are added automatically when they first pay, so look a customer up by email before you create one.
| Topic | Detail |
|---|---|
| Endpoints | `POST /api/v1/customers`, `GET /api/v1/customers`, `GET /api/v1/customers/{id}`, `PATCH /api/v1/customers/{id}` |
| Key permissions | customers:write, customers:read |
| Samples | curl; Node.js 18+ with the built-in fetch (in an ES module); the Node SDK (preview: not on npm yet); Python with requests. |
| Every request can also answer | 401 UNAUTHORIZED, 401 API_KEY_EXPIRED, 403 NOT_ENROLLED, 403 PERMISSION_DENIED, 403 IP_NOT_ALLOWED, 429 RATE_LIMITED, 500 INTERNAL_ERROR. See Error codes. |
The customer object
{
"object": "customer",
"livemode": true,
"id": "cus_1042",
"name": "Jordan Lee",
"email": "jordan@example.com",
"phone": "+1 555 0100",
"company": "Lee Studio",
"notes": null,
"billingAddress": null,
"taxId": null,
"country": "US",
"createdAt": "2026-09-02T11:20:00.000Z"
}| Field | Type | Description |
|---|---|---|
object | string | The type of object. Always customer. |
livemode | boolean | False for test-mode data (an ak_test_ key); true for live data. |
id | string | cus_ followed by digits. |
name | string | Name. |
email | string or null | Email. |
phone | string or null | Phone. |
company | string or null | Company. |
notes | string or null | Your notes; never shown to the customer. |
billingAddress | object or null | A postal address printed on invoices and quotes. |
billingAddress.line1 | string | Street address. Up to 200 characters. |
billingAddress.line2 | string or null | Apartment, suite, unit. Up to 200 characters. |
billingAddress.city | string | City. Up to 100 characters. |
billingAddress.state | string or null | State, province or region. Up to 100 characters. |
billingAddress.postalCode | string | Postal code. Up to 20 characters. |
billingAddress.country | string | ISO 3166-1 alpha-2 country code. |
taxId | string or null | VAT, EIN or other tax number. |
country | string or null | ISO 3166-1 alpha-2, from what you saved or their card's billing address. |
createdAt | string (date-time) | Added. |
Endpoints
Create a customer
/api/v1/customerscustomers:writeSupports Idempotency-Key.One customer per email: 409 DUPLICATE_CUSTOMER otherwise. Card buyers are also added on their own when they first pay, so look up by email before creating.
Headers
Idempotency-Keystring- Recommended. A unique key such as a UUID: a retry with the same key within 24 hours gets the first response back instead of acting twice. See Idempotency.
Body
namestringrequired- The customer's name. Up to 255 characters.
emailstring (email)- One customer per email address. Up to 255 characters.
phonestring- Phone. Up to 50 characters.
companystring- Company. Up to 255 characters.
notesstring- Your notes. Up to 2000 characters.
billingAddressobject or null- A postal address printed on invoices and quotes.
billingAddress.line1stringrequired- Street address. Up to 200 characters.
billingAddress.line2string or null- Apartment, suite, unit. Up to 200 characters.
billingAddress.citystringrequired- City. Up to 100 characters.
billingAddress.statestring or null- State, province or region. Up to 100 characters.
billingAddress.postalCodestringrequired- Postal code. Up to 20 characters.
billingAddress.countrystringrequired- ISO 3166-1 alpha-2 country code.
taxIdstring or null- VAT, EIN or other tax number. Up to 64 characters.
curl -X POST https://anytime-capital.com/api/v1/customers \
-H "Authorization: Bearer $ANYTIME_API_KEY" \
-H "Idempotency-Key: customer-jordan" \
-H "Content-Type: application/json" \
-d '{
"name": "Jordan Lee",
"email": "jordan@example.com",
"company": "Lee Studio"
}'const res = await fetch("https://anytime-capital.com/api/v1/customers", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.ANYTIME_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": "customer-jordan",
},
body: JSON.stringify({
name: "Jordan Lee",
email: "jordan@example.com",
company: "Lee Studio",
}),
});
const customer = await res.json();
if (!res.ok) throw new Error(`${customer.error.code}: ${customer.error.message}`);import { AnytimeCapital } from "@anytimecapital/node";
const client = new AnytimeCapital({ apiKey: process.env.ANYTIME_API_KEY! });
const customer = await client.customers.create(
{
name: "Jordan Lee",
email: "jordan@example.com",
company: "Lee Studio",
},
{ idempotencyKey: "customer-jordan" },
);import os
import requests
res = requests.post(
"https://anytime-capital.com/api/v1/customers",
headers={
"Authorization": f"Bearer {os.environ['ANYTIME_API_KEY']}",
"Idempotency-Key": "customer-jordan",
},
json={
"name": "Jordan Lee",
"email": "jordan@example.com",
"company": "Lee Studio",
},
timeout=30,
)
customer = res.json()
if not res.ok:
raise RuntimeError(f"{customer['error']['code']}: {customer['error']['message']}"){
"object": "customer",
"livemode": true,
"id": "cus_1042",
"name": "Jordan Lee",
"email": "jordan@example.com",
"phone": "+1 555 0100",
"company": "Lee Studio",
"notes": null,
"billingAddress": null,
"taxId": null,
"country": "US",
"createdAt": "2026-09-02T11:20:00.000Z"
}Errors
- 400
INVALID_JSON - The body isn't valid JSON, or couldn't be read. An empty body reads as
{}. SendContent-Type: application/jsonand a JSON object. - 400
INVALID_INPUT - A field, filter,
limitorcursoris missing or invalid. The message starts with the field's name, as inamountCents: …, or readsInvalid cursor.Fix the named field. Don't retry the same request unchanged. - 400
INVALID_IDEMPOTENCY_KEY - The
Idempotency-Keyheader is empty, longer than 255 characters, or has characters other than printable ASCII. Use a UUID. See Idempotency. - 409
DUPLICATE_CUSTOMER - Another saved customer already has this email address, in any letter case. Find them with
GET /api/v1/customers?email=…and update that customer instead. - 422
IDEMPOTENCY_KEY_REUSED - The
Idempotency-Keywas used in the last 24 hours with a different body or endpoint. Use a new key for a new request; reuse a key only to retry the same request.
List customers
/api/v1/customerscustomers:readSaved customers, newest first, or one by email.
Query
emailstring- Only customers with this email, any case. Up to 255 characters.
limitinteger- How many objects per page, 1–100. Default 25. See Pagination.
cursorstring- The previous page's
nextCursor, for the page after it.
curl "https://anytime-capital.com/api/v1/customers?email=jordan%40example.com" \
-H "Authorization: Bearer $ANYTIME_API_KEY"const res = await fetch("https://anytime-capital.com/api/v1/customers?email=jordan%40example.com", {
headers: { Authorization: `Bearer ${process.env.ANYTIME_API_KEY}` },
});
const page = await res.json();
if (!res.ok) throw new Error(`${page.error.code}: ${page.error.message}`);import { AnytimeCapital } from "@anytimecapital/node";
const client = new AnytimeCapital({ apiKey: process.env.ANYTIME_API_KEY! });
const page = await client.customers.list({ email: "jordan@example.com" });import os
import requests
res = requests.get(
"https://anytime-capital.com/api/v1/customers",
headers={"Authorization": f"Bearer {os.environ['ANYTIME_API_KEY']}"},
params={"email": "jordan@example.com"},
timeout=30,
)
page = res.json()
if not res.ok:
raise RuntimeError(f"{page['error']['code']}: {page['error']['message']}"){
"object": "list",
"data": [
{
"object": "customer",
"livemode": true,
"id": "cus_1042",
"name": "Jordan Lee",
"email": "jordan@example.com",
"phone": "+1 555 0100",
"company": "Lee Studio",
"notes": null,
"billingAddress": null,
"taxId": null,
"country": "US",
"createdAt": "2026-09-02T11:20:00.000Z"
}
],
"hasMore": false,
"nextCursor": null
}Errors
- 400
INVALID_INPUT - A field, filter,
limitorcursoris missing or invalid. The message starts with the field's name, as inamountCents: …, or readsInvalid cursor.Fix the named field. Don't retry the same request unchanged.
Get a customer
/api/v1/customers/{id}customers:readOne saved customer. Customers removed in the dashboard answer 404.
Path
idstringrequiredcus_…
curl https://anytime-capital.com/api/v1/customers/cus_1042 \
-H "Authorization: Bearer $ANYTIME_API_KEY"const res = await fetch("https://anytime-capital.com/api/v1/customers/cus_1042", {
headers: { Authorization: `Bearer ${process.env.ANYTIME_API_KEY}` },
});
const customer = await res.json();
if (!res.ok) throw new Error(`${customer.error.code}: ${customer.error.message}`);import { AnytimeCapital } from "@anytimecapital/node";
const client = new AnytimeCapital({ apiKey: process.env.ANYTIME_API_KEY! });
const customer = await client.customers.retrieve("cus_1042");import os
import requests
res = requests.get(
"https://anytime-capital.com/api/v1/customers/cus_1042",
headers={"Authorization": f"Bearer {os.environ['ANYTIME_API_KEY']}"},
timeout=30,
)
customer = res.json()
if not res.ok:
raise RuntimeError(f"{customer['error']['code']}: {customer['error']['message']}"){
"object": "customer",
"livemode": true,
"id": "cus_1042",
"name": "Jordan Lee",
"email": "jordan@example.com",
"phone": "+1 555 0100",
"company": "Lee Studio",
"notes": null,
"billingAddress": null,
"taxId": null,
"country": "US",
"createdAt": "2026-09-02T11:20:00.000Z"
}Errors
- 404
NOT_FOUND - No such object on your business (an id from another business reads the same), or no such endpoint under
/api/v1, which still answers in JSON. Check the id and the path. Ids are case-sensitive.
Update a customer
/api/v1/customers/{id}customers:writeSupports Idempotency-Key.Send only what changes; null clears an optional field.
Path
idstringrequiredcus_…
Headers
Idempotency-Keystring- Recommended. A unique key such as a UUID: a retry with the same key within 24 hours gets the first response back instead of acting twice. See Idempotency.
Body
namestring- The customer's name. Up to 255 characters.
emailstring (email) or null- One customer per email address. Up to 255 characters.
phonestring or null- Phone. Up to 50 characters.
companystring or null- Company. Up to 255 characters.
notesstring or null- Your notes. Up to 2000 characters.
billingAddressobject or null- A postal address printed on invoices and quotes.
billingAddress.line1stringrequired- Street address. Up to 200 characters.
billingAddress.line2string or null- Apartment, suite, unit. Up to 200 characters.
billingAddress.citystringrequired- City. Up to 100 characters.
billingAddress.statestring or null- State, province or region. Up to 100 characters.
billingAddress.postalCodestringrequired- Postal code. Up to 20 characters.
billingAddress.countrystringrequired- ISO 3166-1 alpha-2 country code.
taxIdstring or null- VAT, EIN or other tax number. Up to 64 characters.
curl -X PATCH https://anytime-capital.com/api/v1/customers/cus_1042 \
-H "Authorization: Bearer $ANYTIME_API_KEY" \
-H "Idempotency-Key: customer-jordan-phone" \
-H "Content-Type: application/json" \
-d '{
"phone": "+1 555 0199",
"notes": null
}'const res = await fetch("https://anytime-capital.com/api/v1/customers/cus_1042", {
method: "PATCH",
headers: {
Authorization: `Bearer ${process.env.ANYTIME_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": "customer-jordan-phone",
},
body: JSON.stringify({ phone: "+1 555 0199", notes: null }),
});
const customer = await res.json();
if (!res.ok) throw new Error(`${customer.error.code}: ${customer.error.message}`);import { AnytimeCapital } from "@anytimecapital/node";
const client = new AnytimeCapital({ apiKey: process.env.ANYTIME_API_KEY! });
const customer = await client.customers.update(
"cus_1042",
{ phone: "+1 555 0199", notes: null },
{ idempotencyKey: "customer-jordan-phone" },
);import os
import requests
res = requests.patch(
"https://anytime-capital.com/api/v1/customers/cus_1042",
headers={
"Authorization": f"Bearer {os.environ['ANYTIME_API_KEY']}",
"Idempotency-Key": "customer-jordan-phone",
},
json={"phone": "+1 555 0199", "notes": None},
timeout=30,
)
customer = res.json()
if not res.ok:
raise RuntimeError(f"{customer['error']['code']}: {customer['error']['message']}"){
"object": "customer",
"livemode": true,
"id": "cus_1042",
"name": "Jordan Lee",
"email": "jordan@example.com",
"phone": "+1 555 0199",
"company": "Lee Studio",
"notes": null,
"billingAddress": null,
"taxId": null,
"country": "US",
"createdAt": "2026-09-02T11:20:00.000Z"
}Errors
- 400
INVALID_JSON - The body isn't valid JSON, or couldn't be read. An empty body reads as
{}. SendContent-Type: application/jsonand a JSON object. - 400
INVALID_INPUT - A field, filter,
limitorcursoris missing or invalid. The message starts with the field's name, as inamountCents: …, or readsInvalid cursor.Fix the named field. Don't retry the same request unchanged. - 400
INVALID_IDEMPOTENCY_KEY - The
Idempotency-Keyheader is empty, longer than 255 characters, or has characters other than printable ASCII. Use a UUID. See Idempotency. - 404
NOT_FOUND - No such object on your business (an id from another business reads the same), or no such endpoint under
/api/v1, which still answers in JSON. Check the id and the path. Ids are case-sensitive. - 409
DUPLICATE_CUSTOMER - Another saved customer already has this email address, in any letter case. Find them with
GET /api/v1/customers?email=…and update that customer instead. - 422
IDEMPOTENCY_KEY_REUSED - The
Idempotency-Keywas used in the last 24 hours with a different body or endpoint. Use a new key for a new request; reuse a key only to retry the same request.
Find or create
To keep one record per person, look the email up first and create only when nothing comes back. Two processes doing this at once can race: the second create answers 409 DUPLICATE_CUSTOMER, so treat that as “found” and list by email again.
const API = "https://anytime-capital.com/api/v1";
const headers = { Authorization: `Bearer ${process.env.ANYTIME_API_KEY}` };
export async function findOrCreateCustomer({ name, email }) {
const find = async () => {
const res = await fetch(`${API}/customers?email=${encodeURIComponent(email)}`, { headers });
const page = await res.json();
if (!res.ok) throw new Error(`${page.error.code}: ${page.error.message}`);
return page.data[0] ?? null;
};
const existing = await find();
if (existing) return existing;
const res = await fetch(`${API}/customers`, {
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({ name, email }),
});
const customer = await res.json();
// Someone else created them first, or our earlier attempt went through:
// one customer per email makes the retry safe without an Idempotency-Key.
if (res.status === 409 && customer.error.code === "DUPLICATE_CUSTOMER") return find();
if (!res.ok) throw new Error(`${customer.error.code}: ${customer.error.message}`);
return customer;
}customer.created and customer.updated webhooks carry this object whenever a customer is added or changed, by hand, by the API or when they first pay.