0Bit Documentation

Create a customer

POST /customers - Create a partner-scoped customer (identity) record, idempotently.

0Gate is the primary public integration path for hosted payment, ramp, and swap experiences. Keep secret-key operations on your server and hand only browser-safe values to the widget.

A customer is your own CRM-style reference for an end user: an email plus optional contact fields and free-form metadata. It is a partner-scoped identity record you create and manage, not the KYC-verified 0Bit user identity. Use it to keep a stable handle for a person across sessions, transactions, and support.

Endpoint

FieldValue
MethodPOST
Path/v1/customers
AreaCustomers
Operation idcreateCustomer
Auth boundarySecret key from your server.

Use it for

Create a partner-scoped customer record for an end user and get back its 0Bit id to store against your own user. Send your own reference as external_id so you can look the customer up later without storing the 0Bit id.

This is a standard identity write (CRM-style), not a privacy-minimized KYC view. The fields you send are the contact details you choose to keep — there is no document, screening, or verification payload involved.

Production rules

  • Keep secret keys on your server. This endpoint requires an sk_* key. Never call it from a browser with a publishable pk_* key.
  • Send an Idempotency-Key for the write and reuse the same key when you retry a timeout — a repeat collapses to the original response instead of creating a second customer.
  • email is unique per partner, and external_id is unique per partner when supplied. A duplicate of either is a 409 with code customer_already_exists — branch on it rather than retrying.
  • Validate external_id, phone, and country_code formats before the call to avoid a 400.
  • Store the returned id, your external_id, the request id, and timestamps so support and reconciliation do not depend on browser callbacks alone.
  • Treat examples and placeholder ids as fake data only.

Headers

HeaderRequiredUse it for
AuthorizationYesBearer sk_test_… / Bearer sk_live_…. Secret key from your server.
Idempotency-KeyYesUUID for this logical write. Reuse it on retries so a duplicate request returns the original customer.
Content-TypeYesapplication/json.

Request body

FieldRequiredTypeUse it for
emailYesstringContact email, max 320 chars. Unique per partner — a duplicate returns 409.
external_idNostringYour own reference for this user. Max 256 chars, pattern ^[\w.@:+\-]{1,256}$ (letters, digits, and . _ - + @ :). Unique per partner — a duplicate returns 409.
phoneNostringStrict E.164, pattern ^\+[1-9]\d{6,14}$, for example +447700900000.
first_nameNostringGiven name, max 128 chars.
last_nameNostringFamily name, max 128 chars.
country_codeNostringISO 3166-1 alpha-2, pattern ^[A-Za-z]{2}$, for example GB.
metadataNoobjectFree-form key/value pairs you control. Echoed back on reads.

Server-managed fields are rejected

kyc_status and mode are server-managed and id, partner_id, livemode, created_at, and updated_at are server-set. Sending any field not listed above is a 400 — the body is strictly whitelisted.

Response

Returns 201 with the created customer object.

Customer object

FieldTypeUse it for
idstring0Bit id for this customer. Store it against your user; use it in /v1/customers/{id} calls.
objectstringAlways customer.
partner_idstringThe partner this record belongs to (your account).
modetest/liveWhich key mode created the record.
livemodebooleantrue for live-mode records, false for test.
external_idstring | nullYour reference, or null when not set.
emailstringContact email.
phonestring | nullE.164 phone, or null.
first_namestring | nullGiven name, or null.
last_namestring | nullFamily name, or null.
country_codestring | nullISO 3166-1 alpha-2 region, or null.
kyc_statusstringunverified / processing / verified / rejected / expired. Informational, not partner-settable, and always unverified at launch.
metadataobjectYour free-form key/value pairs.
created_atstring | nullRFC 3339 creation time.
updated_atstring | nullRFC 3339 last-modified time.

Examples

curl -X POST https://gate-api.0bit.app/v1/customers \
  -H "Authorization: Bearer sk_test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Idempotency-Key: 7f9c2b1e-0000-4a00-8000-000000000123" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "jordan@example.com",
    "external_id": "user_42",
    "phone": "+447700900000",
    "first_name": "Jordan",
    "last_name": "Doe",
    "country_code": "GB",
    "metadata": { "plan": "pro" }
  }'
{
  "id": "67a1f3b9e4b0c10001234567",
  "object": "customer",
  "partner_id": "ptnr_test_000000000001",
  "mode": "test",
  "livemode": false,
  "external_id": "user_42",
  "email": "jordan@example.com",
  "phone": "+447700900000",
  "first_name": "Jordan",
  "last_name": "Doe",
  "country_code": "GB",
  "kyc_status": "unverified",
  "metadata": { "plan": "pro" },
  "created_at": "2026-01-01T00:00:00Z",
  "updated_at": "2026-01-01T00:00:00Z"
}
{
  "type": "conflict",
  "code": "customer_already_exists",
  "message": "A customer with email \"jordan@example.com\" already exists",
  "request_id": "req_test_000000000123",
  "doc_url": null,
  "statusCode": 409
}

A 409 with code customer_already_exists means the email or external_id is already taken for your account. Look the existing customer up with GET /v1/customers rather than retrying.

Errors

All errors use the unified envelope and carry an X-Request-Id response header. Branch on code/type/statusCode, not on the free-form message.

{
  "type": "invalid_request",
  "code": "invalid_request",
  "message": "Example validation error using fake data.",
  "request_id": "req_test_000000000123",
  "doc_url": null,
  "statusCode": 400
}
StatustypeWhen it happens
400invalid_requestBad body — missing email, malformed external_id/phone/country_code, or an unknown/server-managed field.
401unauthorizedMissing or invalid secret key.
409conflictCode customer_already_exists — the email or external_id is already in use for this partner.
429rate_limitedRequest throttled. Back off and retry with the same Idempotency-Key.
5xxserver_errorTransient server or upstream failure. Retry with bounded backoff and the same Idempotency-Key.

Public boundary

This reference covers partner-scoped endpoint behavior, authentication, idempotency, webhook verification, and support-safe records. Internal operations, administrative routes, and unsupported availability claims are outside the public API contract.

On this page