API ReferenceEndpointsCustomersCustomer registration

Customer registration

Supports Idempotency-Key header for safe retries.

POST
/v1/customers/register
AuthorizationBearer <token>

Admin API key (server-to-server). Issue via the dashboard at Settings → API keys. Plain-text key is shown once — store in a secret manager. Format: Authorization: Bearer brainerce_xxxxxxxxx.

In: header

Header Parameters

Idempotency-Key?string

Client-supplied key (a UUID v4 is the recommended form, max 255 characters) that makes this mutation safe to retry.

  • Replay window: 24 hours. The first response for a key is cached; a retry inside the window with the same request body returns the original status and body without re-running the handler.
  • Reusing a key with a different body returns 409 Conflict with code: "IDEMPOTENCY_KEY_REUSED". The request fingerprint (method + path + body hash) is compared against the stored one; a mismatch is refused rather than served the old response.
  • Keys are scoped to the calling credential and store — two API keys may safely use the same key value.
  • Error responses are cached too, so a retry of a request that failed validation returns the same 400 immediately.
  • Sending this header on a GET returns 400 with code: "IDEMPOTENCY_KEY_NOT_SUPPORTED" — GETs are already idempotent.
  • Support is per-route and this parameter is the authoritative signal: a key sent to a route that does not declare it is accepted and silently ignored.

See /docs/api/idempotency.

Lengthlength <= 255
emailstring

Customer email, unique per store. Becomes the login identifier.

Formatemail
passwordstring

Password (≥ 8 chars, must match PASSWORD_REGEX: at least one uppercase, lowercase, number, and special char).

Match^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^a-zA-Z0-9]).{8,}$
Length8 <= length
firstName?string

First name.

lastName?string

Last name.

phone?string

Phone number (E.164 format recommended).

acceptsMarketing?boolean

Marketing consent flag (gates promo emails / SMS).

birthMonth?integer

Birthday month (1-12) for the loyalty birthday gift. Month and day only, with no year. Send it together with birthDay or not at all. Optional on most channels; a channel with requireBirthday turned on rejects a registration that omits it.

Range1 <= value <= 12
birthDay?integer

Birthday day of month (1-31). Send it together with birthMonth or not at all. The day must exist in that month, so 30 February is rejected.

Range1 <= value <= 31
privacyPolicyAccepted?boolean

Privacy-policy acceptance flag, required by some stores before account creation. The frontend should require this checkbox when the store enables it.

referralCode?string

Loyalty referral share code (REF-XXXXXXXX) from a referrer's link. Validated asynchronously after registration, so an invalid code never fails the registration itself.

Lengthlength <= 40
curl -X POST "https://api.brainerce.com/api/v1/customers/register" \  -H "Idempotency-Key: string" \  -H "Content-Type: application/json" \  -d '{    "email": "[email protected]",    "password": "CorrectHorse-Battery-Staple9"  }'
{
  "customer": {
    "id": "clx1a2b3c4d5e6f7g8h9",
    "email": "[email protected]",
    "firstName": "Dana",
    "lastName": "Cohen",
    "phone": "+972501234567",
    "emailVerified": true
  },
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "expiresAt": "2019-08-24T14:15:22Z",
  "requiresVerification": true
}

{
  "statusCode": 400,
  "code": "VALIDATION_FAILED",
  "message": "name should not be empty, price must be a positive number",
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/customers/register"
}

{
  "statusCode": 401,
  "code": "UNAUTHORIZED",
  "message": "Invalid or expired credential",
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/products/bulk/{jobId}"
}

{
  "statusCode": 403,
  "code": "INSUFFICIENT_SCOPE",
  "message": "API key does not have the required scope: products:write",
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/customers/register"
}

{
  "statusCode": 409,
  "code": "CONFLICT",
  "message": "The request conflicts with the current state of the resource",
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/customers/register"
}

{
  "statusCode": 429,
  "code": "RATE_LIMITED",
  "message": "Too many requests",
  "details": {
    "retryAfterSeconds": 12
  },
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/customers/register"
}