Contacts
Registration and sessions
Register a contact account, log in for a session token, and log out.
View as MarkdownThese three endpoints manage contact accounts and session tokens. register and login return a token alongside the contact; send it as X-Customer-Token on contact-authenticated endpoints. All three require the contacts:write scope on your API key (customers:write accepted).
These three endpoints manage contact accounts and session tokens. register and login return a token alongside the contact; send it as X-Customer-Token on contact-authenticated endpoints. All three require the contacts:write scope on your API key (customers:write accepted).
POST /v1/api/contacts/register
Also served at /v1/api/customers/register for existing integrations; identical request and response.
Register a storefront contact account. Returns the created contact 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/contacts/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/contacts/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: contact, token } = await res.json();{
"data": {
"id": "9d4e2f1a-6b3c-4f8e-9a1d-2c5b7e8f0a3d",
"name": "Jane Doe",
"email": "jane@example.com",
"phone": null,
"kind": "person",
"company_name": null,
"registration_number": null,
"vat_id": null,
"external_id": null,
"display_name": "Jane Doe",
"created_at": "2026-08-14T10:32:11+00:00"
},
"token": "12|Fq8sT3vY6wZx9aBcDeFgHiJkLmNoPqRsTuVwXyZ0"
}POST /v1/api/contacts/register
Also served at /v1/api/customers/register for existing integrations; identical request and response.
Register a storefront contact account. Returns the created contact 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/contacts/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/contacts/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: contact, token } = await res.json();Status: 201 Created.
{
"data": {
"id": "9d4e2f1a-6b3c-4f8e-9a1d-2c5b7e8f0a3d",
"name": "Jane Doe",
"email": "jane@example.com",
"phone": null,
"kind": "person",
"company_name": null,
"registration_number": null,
"vat_id": null,
"external_id": null,
"display_name": "Jane Doe",
"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/contacts/login
Also served at /v1/api/customers/login for existing integrations; identical request and response.
Authenticate a contact with email and password. Returns the contact 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/contacts/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",
"kind": "person",
"company_name": null,
"registration_number": null,
"vat_id": null,
"external_id": null,
"display_name": "Jane Doe",
"created_at": "2026-08-14T10:32:11+00:00"
},
"token": "13|Gh7rS2uX5vWy8zAbCdEfGhIjKlMnOpQrStUvWxYz"
}POST /v1/api/contacts/login
Also served at /v1/api/customers/login for existing integrations; identical request and response.
Authenticate a contact with email and password. Returns the contact 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/contacts/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",
"kind": "person",
"company_name": null,
"registration_number": null,
"vat_id": null,
"external_id": null,
"display_name": "Jane Doe",
"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/contacts/logout
Also served at /v1/api/customers/logout for existing integrations; identical request and response.
Revoke the contact session token given in X-Customer-Token. The header must be present and valid to pass contact 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/contacts/logout \
-H "Authorization: Bearer {api_key}" \
-H "X-Customer-Token: 13|Gh7rS2uX5vWy8zAbCdEfGhIjKlMnOpQrStUvWxYz"POST /v1/api/contacts/logout
Also served at /v1/api/customers/logout for existing integrations; identical request and response.
Revoke the contact session token given in X-Customer-Token. The header must be present and valid to pass contact 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/contacts/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.