BizKitHub
DocsAPI ReferenceCustomer/api/v1/customer/register-account
postCustomerPublic API v1

/api/v1/customer/register-account

Registers a new customer account with email and password. Sends a verification email. Returns error codes on validation failure.

List of error codes:

Code Message
E001 Customer register failed.
E002 Customer has been registered.
E003 Customer account has been banned.
E004 Too many registration attempts.
customerpostApiV1CustomerRegister-account

Parameters

1 query · JSON body

Query parameters

· 1
apiKeystringRequired

Your BizKitHub API key (passed as GET parameter).

Key format: A 32-character string matching: ^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$
Prefixes: PROD (production key), DEV_ (individual developer), ROOT (system key with no limits). Learn more

ExamplePRODPGrFxpGEtrOZfuWhnoJohUYBXuOE

Request body

application/json
emailstringRequired

Contact email address.

The system validates the input as a standard email address and automatically applies normalization and canonicalization.

All API responses return the normalized form, and each email address is unique per organisation within the system.

Phone-only contacts: Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use API_EMAIL_NULLABLE instead, where this field can be null. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.

Examplejan@barasek.com
namestringOptional
ExampleJan Barášek
firstNamestringOptional
ExampleJan
lastNamestringOptional
ExampleBarášek
phonestringOptional

Contact phone number in international (national) format.

Preferred format: +<country_code> <local_number>

  • Leading plus sign (+) is required
  • Followed by the country calling code (e.g. 420)
  • One space after the country code
  • Full local number without spaces

Example: +420 777123456
This format ensures unambiguous storage, validation, and compatibility with SMS, calling, and third-party integrations (e.g. Twilio, WhatsApp, CRM systems).

Example+420 777123456
companyNamestringOptional
ExampleBizKitHub
companyRegistrationNumberstringOptional
Example05103118
taxIdentificationNumberstringOptional
ExampleCZ9609040727
streetAddressstringOptional
ExampleR. Novotného 1505
citystringOptional
ExampleKladno
cityPartstringOptional
ExampleKročehlavy
stateRegionstringOptional
ExampleStředočeský kraj
postalCodestringOptional
Example272 01
countrystringOptional
ExamplesCZČeská republikaCzechiaCzech
newsletterbooleanOptional
Default: false
primaryLocalestringOptional
Examplecs
groupsstring[]Optional
customerRealIpstringOptional

Accepted formats:

  • IPv4 dot-decimal, e.g. 1.1.1.1 (4 octets, 0–255, no leading zeros).
  • IPv6 as defined by RFC 4291 — full 2001:0db8:0000:0000:0000:0000:0000:0001, zero-compressed 2001:db8::1, IPv4-mapped ::ffff:1.2.3.4, or scoped literals. Both upper- and lower-case hex are accepted.

Server-side canonicalization (ipNormalize in core/src/lib/network/ipNormalize.ts):

  • Valid IPv4 is passed through verbatim.
  • Valid IPv6 is lowercased (RFC 5952 §4.3).
  • IPv4-mapped IPv6 ::ffff:X.X.X.X is unwrapped to plain IPv4 (RFC 4291 §2.5.5.2) so 1.2.3.4 and ::ffff:1.2.3.4 share one brj__geo_ip row.
  • Loopback aliases (::1, 0.0.0.0, localhost, empty string) collapse to 127.0.0.1.
  • Junk values that fail both IPv4 and IPv6 validation are silently rejected and replaced with 127.0.0.1 (loopback).

On the wire: every response returns the canonicalized form — clients can safely rely on lowercase IPv6 and the plain-IPv4 unwrap when de-duping or joining. Server-originated writers (activity log, session log, ban list) resolve the visitor IP via resolveClientIp / resolveClientIpOrNull — always native IPv6 on Vercel Edge (there is no auto-mapping to ::ffff:X.X.X.X).

Enrichment: the system resolves reverse DNS, geolocation, ASN, mobile/proxy/hosting/Tor flags via our VikiTron GEO/IP resolver for both address families. Learn more

Examples1.1.1.12001:4860:4860::8888
referralIdstringOptional

cuRefNo = customer reference number.

Length: 16–16
Example1cGIHvFoQDGLAbcA
passwordstringRequired
Length: 1–∞
returnUrlstringOptional
defaultCreditnumberOptional

Initial credit balance granted to the customer after they verify the e-mail. Only positive numbers are honoured — null, 0 and negative values are ignored.

Response schema

1 status code documented

200Success
object | object
One of 2:
Variant 1
success"true"Required
riskScorestring | integerRequired

Server-computed risk score for the current request, on an integer scale 0 – 100 (RISK_SCORE_MIN / RISK_SCORE_MAX in features/security/riskScore/clampScore.ts).

Direction: higher = riskier. 0 is a clean, fully trusted signal; 100 is a hard-block-worthy signal (TOR exit node, active abuse-IP feed hit, login-flood threshold breached, or the caller organisation has explicitly banned the visitor IP).

Recommended integration buckets for the calling application — these are guidance, not a contract, callers are free to pick their own thresholds:

Bucket Range What it means Suggested action
trusted 0 – 19 Green — known device / prior success / same-country / EU IP for an EU org. Proceed silently.
neutral 20 – 49 No strong signal either way (fresh IP, unknown device, no history). Proceed, log the score, optionally show a soft "verify e-mail" nudge.
suspicious 50 – 74 Multiple soft red flags stacked (foreign origin for an EU org, new IP, other-org ban, …). Require a second factor before granting sensitive actions (MFA, magic-link re-verification, CAPTCHA, ID verification).
hostile 75 – 100 Hard-block territory. Above 75 the internal enforceLoginRiskScore throws LoginRiskScoreRejectionError; 100 is reached only via a hard-block signal (TOR / active abuse-IP / own-org ban / login flood). Reject the follow-up action, force password reset / step-up auth.

How it is computed: the score is a weighted average of independent signal families (IP reputation, org-country match, EU/high-risk-country policy, per-user history), clamped to [0, 100]. Any single family may return hardBlock(...) to short-circuit the average to 100. Green signals (prior successful login from this IP, paid orders, active session, mobile carrier) subtract from the total; red signals (new IP, other-org ban, foreign continent for an EU org) add to it. Full rule table lives in features/security/riskScore/calculateIpRiskScore.ts.

Stability: the numeric value is a heuristic — the exact algorithm may evolve between releases as new signals are added. The scale, direction and the four bucket boundaries above are stable; integrate against buckets, not exact numbers.

Order-create note: the endpoint currently returns the best-case score (0) for order creation as a placeholder — the order-side risk model is being built out separately (device fingerprint, cart velocity, geo/billing mismatch, chargeback history). The field is exposed already so downstream integrations can wire their step-up logic once and pick up richer values automatically when the order-side model ships.

One of 2:
Variant 1
stringinteger
Default: 0
Variant 2
integer

Server-computed risk score for the current request, on an integer scale 0 – 100 (RISK_SCORE_MIN / RISK_SCORE_MAX in features/security/riskScore/clampScore.ts).

Direction: higher = riskier. 0 is a clean, fully trusted signal; 100 is a hard-block-worthy signal (TOR exit node, active abuse-IP feed hit, login-flood threshold breached, or the caller organisation has explicitly banned the visitor IP).

Recommended integration buckets for the calling application — these are guidance, not a contract, callers are free to pick their own thresholds:

Bucket Range What it means Suggested action
trusted 0 – 19 Green — known device / prior success / same-country / EU IP for an EU org. Proceed silently.
neutral 20 – 49 No strong signal either way (fresh IP, unknown device, no history). Proceed, log the score, optionally show a soft "verify e-mail" nudge.
suspicious 50 – 74 Multiple soft red flags stacked (foreign origin for an EU org, new IP, other-org ban, …). Require a second factor before granting sensitive actions (MFA, magic-link re-verification, CAPTCHA, ID verification).
hostile 75 – 100 Hard-block territory. Above 75 the internal enforceLoginRiskScore throws LoginRiskScoreRejectionError; 100 is reached only via a hard-block signal (TOR / active abuse-IP / own-org ban / login flood). Reject the follow-up action, force password reset / step-up auth.

How it is computed: the score is a weighted average of independent signal families (IP reputation, org-country match, EU/high-risk-country policy, per-user history), clamped to [0, 100]. Any single family may return hardBlock(...) to short-circuit the average to 100. Green signals (prior successful login from this IP, paid orders, active session, mobile carrier) subtract from the total; red signals (new IP, other-org ban, foreign continent for an EU org) add to it. Full rule table lives in features/security/riskScore/calculateIpRiskScore.ts.

Stability: the numeric value is a heuristic — the exact algorithm may evolve between releases as new signals are added. The scale, direction and the four bucket boundaries above are stable; integrate against buckets, not exact numbers.

Order-create note: the endpoint currently returns the best-case score (0) for order creation as a placeholder — the order-side risk model is being built out separately (device fingerprint, cart velocity, geo/billing mismatch, chargeback history). The field is exposed already so downstream integrations can wire their step-up logic once and pick up richer values automatically when the order-side model ships.

Range: 0–100
Examples02560100
Variant 2
success"false"Required
errorCodestringRequired
ExamplesE001E002E003E004
messagestringRequired
ExamplesCustomer register failed.Customer has been registered.Customer account has been banned.Too many registration attempts.
riskScorestring | integerRequired

Server-computed risk score for the current request, on an integer scale 0 – 100 (RISK_SCORE_MIN / RISK_SCORE_MAX in features/security/riskScore/clampScore.ts).

Direction: higher = riskier. 0 is a clean, fully trusted signal; 100 is a hard-block-worthy signal (TOR exit node, active abuse-IP feed hit, login-flood threshold breached, or the caller organisation has explicitly banned the visitor IP).

Recommended integration buckets for the calling application — these are guidance, not a contract, callers are free to pick their own thresholds:

Bucket Range What it means Suggested action
trusted 0 – 19 Green — known device / prior success / same-country / EU IP for an EU org. Proceed silently.
neutral 20 – 49 No strong signal either way (fresh IP, unknown device, no history). Proceed, log the score, optionally show a soft "verify e-mail" nudge.
suspicious 50 – 74 Multiple soft red flags stacked (foreign origin for an EU org, new IP, other-org ban, …). Require a second factor before granting sensitive actions (MFA, magic-link re-verification, CAPTCHA, ID verification).
hostile 75 – 100 Hard-block territory. Above 75 the internal enforceLoginRiskScore throws LoginRiskScoreRejectionError; 100 is reached only via a hard-block signal (TOR / active abuse-IP / own-org ban / login flood). Reject the follow-up action, force password reset / step-up auth.

How it is computed: the score is a weighted average of independent signal families (IP reputation, org-country match, EU/high-risk-country policy, per-user history), clamped to [0, 100]. Any single family may return hardBlock(...) to short-circuit the average to 100. Green signals (prior successful login from this IP, paid orders, active session, mobile carrier) subtract from the total; red signals (new IP, other-org ban, foreign continent for an EU org) add to it. Full rule table lives in features/security/riskScore/calculateIpRiskScore.ts.

Stability: the numeric value is a heuristic — the exact algorithm may evolve between releases as new signals are added. The scale, direction and the four bucket boundaries above are stable; integrate against buckets, not exact numbers.

Order-create note: the endpoint currently returns the best-case score (0) for order creation as a placeholder — the order-side risk model is being built out separately (device fingerprint, cart velocity, geo/billing mismatch, chargeback history). The field is exposed already so downstream integrations can wire their step-up logic once and pick up richer values automatically when the order-side model ships.

One of 2:
Variant 1
stringinteger
Default: 0
Variant 2
integer

Server-computed risk score for the current request, on an integer scale 0 – 100 (RISK_SCORE_MIN / RISK_SCORE_MAX in features/security/riskScore/clampScore.ts).

Direction: higher = riskier. 0 is a clean, fully trusted signal; 100 is a hard-block-worthy signal (TOR exit node, active abuse-IP feed hit, login-flood threshold breached, or the caller organisation has explicitly banned the visitor IP).

Recommended integration buckets for the calling application — these are guidance, not a contract, callers are free to pick their own thresholds:

Bucket Range What it means Suggested action
trusted 0 – 19 Green — known device / prior success / same-country / EU IP for an EU org. Proceed silently.
neutral 20 – 49 No strong signal either way (fresh IP, unknown device, no history). Proceed, log the score, optionally show a soft "verify e-mail" nudge.
suspicious 50 – 74 Multiple soft red flags stacked (foreign origin for an EU org, new IP, other-org ban, …). Require a second factor before granting sensitive actions (MFA, magic-link re-verification, CAPTCHA, ID verification).
hostile 75 – 100 Hard-block territory. Above 75 the internal enforceLoginRiskScore throws LoginRiskScoreRejectionError; 100 is reached only via a hard-block signal (TOR / active abuse-IP / own-org ban / login flood). Reject the follow-up action, force password reset / step-up auth.

How it is computed: the score is a weighted average of independent signal families (IP reputation, org-country match, EU/high-risk-country policy, per-user history), clamped to [0, 100]. Any single family may return hardBlock(...) to short-circuit the average to 100. Green signals (prior successful login from this IP, paid orders, active session, mobile carrier) subtract from the total; red signals (new IP, other-org ban, foreign continent for an EU org) add to it. Full rule table lives in features/security/riskScore/calculateIpRiskScore.ts.

Stability: the numeric value is a heuristic — the exact algorithm may evolve between releases as new signals are added. The scale, direction and the four bucket boundaries above are stable; integrate against buckets, not exact numbers.

Order-create note: the endpoint currently returns the best-case score (0) for order creation as a placeholder — the order-side risk model is being built out separately (device fingerprint, cart velocity, geo/billing mismatch, chargeback history). The field is exposed already so downstream integrations can wire their step-up logic once and pick up richer values automatically when the order-side model ships.

Range: 0–100
Examples02560100

Response example

application/json
{
  "success": true,
  "riskScore": 0
}

Request example

POST /api/v1/customer/register-account

post
curl -X POST "https://api.bizkithub.com/api/v1/customer/register-account?apiKey=PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
  "email": "jan@barasek.com",
  "name": "Jan Barášek",
  "firstName": "Jan",
  "lastName": "Barášek",
  "phone": "+420 777123456",
  "companyName": "BizKitHub",
  "companyRegistrationNumber": "05103118",
  "taxIdentificationNumber": "CZ9609040727",
  "streetAddress": "R. Novotného 1505",
  "city": "Kladno",
  "cityPart": "Kročehlavy",
  "stateRegion": "Středočeský kraj",
  "postalCode": "272 01",
  "country": "CZ",
  "newsletter": false,
  "primaryLocale": "cs",
  "groups": [
    "string"
  ],
  "customerRealIp": "1.1.1.1",
  "referralId": "1cGIHvFoQDGLAbcA",
  "password": "example_password",
  "returnUrl": "example_returnUrl",
  "defaultCredit": 0
}'

Need an API key?

All BizKitHub public API endpoints require authentication via API key.

Get API Key