Sign up a Hyperscale user and create their team
user.signup
Creates the Hyperscale user, their team, the team's tenant business truth (tenant, entity, tenant ledger accounts), the owner membership, and an authenticated session in one idempotent operation. With an inviteToken the user instead joins the inviting team with the invited role: the pending invitation is verified and marked accepted, no new team or tenant is created, and teamName is ignored. Hyperscale owns this identity end to end; no third-party identity provider is involved. The session token is a one-time secret surfaced only in the first API response, never in receipts or replays. The email address is taken on trust: signup checks its shape, mails a verification link to it, and reports emailVerified false until that link is opened. An invite redemption starts verified, because the invite token only reached that address through Hyperscale's own mail. On a deployment that checks Turnstile, a request with no x-turnstile-token header and a teamName but no inviteToken runs user.signup.request instead: it answers 202 verification_sent and mails a six-digit code, and user.signup.verify finishes the sign-up.
POST /v1/identity/signup
Principal public. Idempotency required. Environment sandbox.
Input
| Field | In | Type | Description |
|---|---|---|---|
X-Hyperscale-Environment | header | sandbox | live | |
Idempotency-Key required | header | string | |
X-Hyperscale-Rehearsal | header | "true" | `true` runs the request through admission and execution, keeps nothing, and answers OperationRehearsal with 200 in place of the operation's own output. Needs a signed-in caller. Identity operations, such as sign-in, sessions, team members and agent grants, refuse it with invalid_request. |
email required | body | string | |
password required | body | string | |
displayName required | body | string | |
mobile | body | string | E.164 mobile number registered with Absher. The console always collects it; when omitted (test harnesses), a valid sandbox placeholder is derived from the email so every user carries a mobile. |
teamName | body | string | Name for the new team. Required unless inviteToken is set, in which case the user joins the inviting team and teamName is ignored. |
country | body | string | ISO 3166-1 alpha-2 country code |
inviteToken | body | string | Hyperscale one-time team invite token |
termsAccepted required | body | true | Affirmative click-wrap acceptance of the Terms of Service, Privacy Policy, and Security terms. Signup refuses without it; the acceptance timestamp is recorded on the user. |
Request sample
curl --request POST 'https://hyperscale0.ai/v1/identity/signup' \
--header "Authorization: Bearer $HYPERSCALE_API_KEY" \
--header 'X-Hyperscale-Environment: sandbox' \
--header "Idempotency-Key: $(uuidgen)" \
--header 'Content-Type: application/json' \
--data-raw '{"email":"[email protected]","password":"correct-horse-battery","displayName":"Founder Example","mobile":"+966555123456","teamName":"Example Escrow","country":"SA","termsAccepted":true}'Errors
| Code | HTTP | Cause |
|---|---|---|
idempotency_conflict | 409 | The request reused an Idempotency-Key for a different logical mutation. |
idempotency_required | 400 | The operation is a mutation and Hyperscale requires a replay key before executing it. |
internal_error | 500 | Hyperscale hit an unexpected server-side condition and hid internal implementation details from this audience. |
invalid_request | 400 | The request does not match the API reference. |
not_found | 404 | No Hyperscale route matched the requested path and method. |
rate_limited | 429 | The credential sent more than its limit in the current 60-second window: 600 requests per API key or session, 1,200 per IP address. Every response carries `x-ratelimit-limit`, `x-ratelimit-remaining` and `x-ratelimit-reset` (Unix seconds). |
request_body_too_large | 413 | The JSON request body exceeded Hyperscale's accepted payload size. |
resource_not_found | 404 | The requested resource does not exist in the credential's visible scope. |
state_conflict | 409 | The operation conflicts with the current durable state of the resource. |
state_constraint_failed | 422 | The request is syntactically valid but violates a business-state constraint. |
tenant_not_found | 404 | The credential resolved to a tenant Hyperscale cannot find. |
unauthorized | 403 | The request did not include a valid Hyperscale bearer credential for this environment. |
capability_not_configured | 400 | This deployment lacks something the request depends on. The requested capability is not in the commercial catalog, identity email delivery is off (`details.capability` is `identity_email`), the deployment names no organization verification provider (`details.capability` is `organization_verification` and `details.configKey` names the setting), or a named provider has no live adapter (`details.provider` names it). |
cross_tenant_transfer_forbidden | 409 | An account on this transfer belongs to another tenant, or it has no tenant and is not a platform account. `details.accountId` names it. No intent or ledger effect was created. |
currency_mismatch | 400 | The currency on the request does not match the settlement currency of the account or transfer it targets. Hyperscale never converts between currencies, so the two must be identical. |
identity_rate_limited | 429 | The mailed-code signup refused: this address or client address asked for three codes in the past hour, or the code took five wrong guesses and was retired. |
instrument_instance_not_found | 404 | No record of this instrument matches the `instanceId` in this Product, company and environment. `details.instrumentId` and `details.instrumentInstanceId` name what was looked up. |
insufficient_balance | 409 | The source (debit) account's available balance is below the transfer amount, so the ledger refused the transfer. No money moved. The transfer was not created and its charge/transfer rows are recorded as failed. |
invalid_credentials | 401 | Hyperscale could not accept the account or credential request. Signup, login, and bearer authentication use one 401 for every case they reject, so the response exposes no credential-specific reason or registered-email verdict. The single exception is a key that is real but homed in the other environment: because the presented secret already matched a stored key, the message names the mismatch instead of leaving a working credential looking unknown. A bearer that matched nothing gets text that fits its prefix (an agent token, a refresh token, a personal access token, a session or no Hyperscale token at all), which says only what the caller sent, never whether a credential like it exists. |
invite_already_used | 409 | The invitation was already accepted, so it can be neither redeemed nor revoked again. |
invite_expired | 409 | The invitation's expiry has passed, so it admits no one. |
invite_not_found | 404 | No pending invitation matches this token and email address. An unknown, revoked or mistyped token gets the same answer. |
ledger_transfer_rejected | 409 | The ledger refused the transfer for a reason other than insufficient balance. No money moved. `details` carries `transferId`, the debit-side `accountId`, `amount` and `currency`. The ledger's own reason stays in the server log. |
ledger_unavailable | 503 | The ledger could not be reached, did not answer in time, or returned incomplete evidence for the accounts this request reads. `details.reason` is `request_timeout` when the call timed out. |
operation_not_finalized | 409 | The operation in `details.operationId` has started but has no final receipt. It is still running, or its outcome is unknown after a failure past the point where it may have committed. `details.error` carries the underlying failure when there is one. |
sandbox_environment_required | 400 | This operation runs only in sandbox. That covers Product creation and composition, enabling capabilities, composition-scoped API keys, rehearsal Products and provider webhook simulation. |
tenant_code_exhausted | 503 | The per-environment tenant code space (49,999 five-digit codes) is fully allocated, so no new company can be created. |