Customers
Registration and sessions
Register a customer account, log in for a session token, and log out.
View as MarkdownThese three endpoints manage customer accounts and session tokens. register and login return a token alongside the customer; send it as X-Customer-Token on customer-authenticated endpoints. All three require the customers:write scope on your API key.
These three endpoints manage customer accounts and session tokens. register and login return a token alongside the customer; send it as X-Customer-Token on customer-authenticated endpoints. All three require the customers:write scope on your API key.
POST /v1/api/customers/register
Register a storefront customer account. Returns the created customer plus a session token. If the email already belongs to a guest row (created by cart email capture in the Commerce module), the guest is upgraded in place: same id, order history preserved, name and password set from this request. Only an email that belongs to a real (non-guest) account is rejected. Extra rate limit: 10 requests per minute per IP.
Body parameters
| Name | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Full name. Maximum 150 characters. |
email | string | Yes | Valid email address, maximum 255 characters. Lowercased server-side. Must not belong to an existing non-guest account. |
password | string | Yes | Minimum 8 characters. |
Status: 201 Created.
Errors
422witherrors.email["Email already registered."]when a non-guest account already uses the email.422for field validation failures (missing name, invalid email, password shorter than 8 characters).429when the 10 requests per minute per IP limit is exceeded.
curl -X POST https://api.borkol.com/v1/api/customers/register \
-H "Authorization: Bearer {api_key}" \
-H "Content-Type: application/json" \
-d '{"name":"Jane Doe","email":"jane@example.com","password":"s3cret-pass"}'const res = await fetch("https://api.borkol.com/v1/api/customers/register", {
method: "POST",
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
name: "Jane Doe",
email: "jane@example.com",
password: "s3cret-pass",
}),
});
const { data: customer, token } = await res.json();{
"data": {
"id": "9d4e2f1a-6b3c-4f8e-9a1d-2c5b7e8f0a3d",
"name": "Jane Doe",
"email": "jane@example.com",
"phone": null,
"created_at": "2026-08-14T10:32:11+00:00"
},
"token": "12|Fq8sT3vY6wZx9aBcDeFgHiJkLmNoPqRsTuVwXyZ0"
}POST /v1/api/customers/register
Register a storefront customer account. Returns the created customer plus a session token. If the email already belongs to a guest row (created by cart email capture in the Commerce module), the guest is upgraded in place: same id, order history preserved, name and password set from this request. Only an email that belongs to a real (non-guest) account is rejected. Extra rate limit: 10 requests per minute per IP.
Body parameters
| Name | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Full name. Maximum 150 characters. |
email | string | Yes | Valid email address, maximum 255 characters. Lowercased server-side. Must not belong to an existing non-guest account. |
password | string | Yes | Minimum 8 characters. |
curl -X POST https://api.borkol.com/v1/api/customers/register \
-H "Authorization: Bearer {api_key}" \
-H "Content-Type: application/json" \
-d '{"name":"Jane Doe","email":"jane@example.com","password":"s3cret-pass"}'const res = await fetch("https://api.borkol.com/v1/api/customers/register", {
method: "POST",
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
name: "Jane Doe",
email: "jane@example.com",
password: "s3cret-pass",
}),
});
const { data: customer, token } = await res.json();Status: 201 Created.
{
"data": {
"id": "9d4e2f1a-6b3c-4f8e-9a1d-2c5b7e8f0a3d",
"name": "Jane Doe",
"email": "jane@example.com",
"phone": null,
"created_at": "2026-08-14T10:32:11+00:00"
},
"token": "12|Fq8sT3vY6wZx9aBcDeFgHiJkLmNoPqRsTuVwXyZ0"
}Errors
422witherrors.email["Email already registered."]when a non-guest account already uses the email.422for field validation failures (missing name, invalid email, password shorter than 8 characters).429when the 10 requests per minute per IP limit is exceeded.
POST /v1/api/customers/login
Authenticate a customer with email and password. Returns the customer and a fresh session token, and updates the account's last_login_at. The check is timing-safe and never reveals whether the email exists: a wrong password, an unknown email, and a guest account (which has no password) all fail with the same 422. Extra rate limit: 10 requests per minute per IP.
Body parameters
| Name | Type | Required | Description |
|---|---|---|---|
email | string | Yes | Valid email address. Lowercased server-side before lookup. |
password | string | Yes | The account password. |
Status: 200 OK.
Errors
422witherrors.email["Invalid credentials."]for a wrong email or a wrong password. The error is always on theemailkey.429when the 10 requests per minute per IP limit is exceeded.
curl -X POST https://api.borkol.com/v1/api/customers/login \
-H "Authorization: Bearer {api_key}" \
-H "Content-Type: application/json" \
-d '{"email":"jane@example.com","password":"s3cret-pass"}'{
"data": {
"id": "9d4e2f1a-6b3c-4f8e-9a1d-2c5b7e8f0a3d",
"name": "Jane Doe",
"email": "jane@example.com",
"phone": "+31612345678",
"created_at": "2026-08-14T10:32:11+00:00"
},
"token": "13|Gh7rS2uX5vWy8zAbCdEfGhIjKlMnOpQrStUvWxYz"
}POST /v1/api/customers/login
Authenticate a customer with email and password. Returns the customer and a fresh session token, and updates the account's last_login_at. The check is timing-safe and never reveals whether the email exists: a wrong password, an unknown email, and a guest account (which has no password) all fail with the same 422. Extra rate limit: 10 requests per minute per IP.
Body parameters
| Name | Type | Required | Description |
|---|---|---|---|
email | string | Yes | Valid email address. Lowercased server-side before lookup. |
password | string | Yes | The account password. |
curl -X POST https://api.borkol.com/v1/api/customers/login \
-H "Authorization: Bearer {api_key}" \
-H "Content-Type: application/json" \
-d '{"email":"jane@example.com","password":"s3cret-pass"}'Status: 200 OK.
{
"data": {
"id": "9d4e2f1a-6b3c-4f8e-9a1d-2c5b7e8f0a3d",
"name": "Jane Doe",
"email": "jane@example.com",
"phone": "+31612345678",
"created_at": "2026-08-14T10:32:11+00:00"
},
"token": "13|Gh7rS2uX5vWy8zAbCdEfGhIjKlMnOpQrStUvWxYz"
}Errors
422witherrors.email["Invalid credentials."]for a wrong email or a wrong password. The error is always on theemailkey.429when the 10 requests per minute per IP limit is exceeded.
POST /v1/api/customers/logout
Revoke the customer session token given in X-Customer-Token. The header must be present and valid to pass customer authentication: a currently valid token is revoked and the request returns 204, while an already-revoked or unknown token fails authentication with 401 {"message": "Invalid customer token."}.
Headers
| Name | Type | Required | Description |
|---|---|---|---|
X-Customer-Token | string | Yes | The session token to revoke. |
No body.
Status: 204 No Content. The response has no body.
Errors
401{"message":"Invalid customer token."}whenX-Customer-Tokenis missing or invalid.
curl -X POST https://api.borkol.com/v1/api/customers/logout \
-H "Authorization: Bearer {api_key}" \
-H "X-Customer-Token: 13|Gh7rS2uX5vWy8zAbCdEfGhIjKlMnOpQrStUvWxYz"POST /v1/api/customers/logout
Revoke the customer session token given in X-Customer-Token. The header must be present and valid to pass customer authentication: a currently valid token is revoked and the request returns 204, while an already-revoked or unknown token fails authentication with 401 {"message": "Invalid customer token."}.
Headers
| Name | Type | Required | Description |
|---|---|---|---|
X-Customer-Token | string | Yes | The session token to revoke. |
No body.
curl -X POST https://api.borkol.com/v1/api/customers/logout \
-H "Authorization: Bearer {api_key}" \
-H "X-Customer-Token: 13|Gh7rS2uX5vWy8zAbCdEfGhIjKlMnOpQrStUvWxYz"Status: 204 No Content. The response has no body.
Errors
401{"message":"Invalid customer token."}whenX-Customer-Tokenis missing or invalid.