users_users_create
Create an end user of this product with at least one email identifier.
Create an end user of this product with at least one email identifier. Supply password to store a password hash; omit it to create the user without a password identity. Supply only hashes in password fields; do not send plaintext passwords. Only one verified copy of an email is allowed per product; unverified duplicates are allowed. Pass `kind: "contact"` to record somebody the Product knows who cannot sign in: a contact may not carry `password`, `waitlisted` or `requiresReset` (refused with `contact_cannot_hold_credentials`), is hidden from the default users_users_list view, and is never counted as a retained user. `stage` and `tags` set the relationship state; tags are stored trimmed, lowercased and de-duplicated. Besides `email`, an identifier may be a CONTACT CHANNEL — `phone`, `telegram`, `linkedin` or `x`. A channel is how to REACH somebody, not how they sign in: it is always stored `unverified` (a `verified: true` on one is ignored), it can never start a sign-in, carry a one-time code or be verified, and it is canonicalised by its own rule — `phone` to E.164 (`+7 (999) 123-45-67` is stored `+79991234567`), `telegram` and `x` lowercased without a leading `@`, `linkedin` to the public-profile slug, so a full `linkedin.com/in/<slug>` URL and the bare slug are one value. A value that does not fit its type is refused with `invalid_identifier`. One record may not carry the same channel twice (`duplicate_identifier`), but two different people MAY share one — a company phone is not a conflict. A contact may carry a channel and no address at all.
Behavior
- HTTP
POST /users/users
Arguments
Name | Type | Required | Description |
|---|---|---|---|
kind | string | — | What kind of person to create. 'account' (the default) can sign in. 'contact' is somebody the Product knows who has NO credential — a contact may not carry `password`, `waitlisted` or `requiresReset` (`contact_cannot_hold_credentials`), is hidden from the default users_users_list view, and is never counted as a retained user. A contact becomes an account only by proving an address, never by an operator setting this. |
name | string | — | The user's display name. |
tags | string | — | Free labels for this person. Trimmed, lowercased and de-duplicated on write; at most 32 of at most 64 characters each. |
stage | string | — | The relationship stage to start them at, in funnel order: new, contacted, replied, engaged, converted, lost. Default 'new'. |
imageUrl | string | — | URL of the user's avatar image. |
password | object | — | Credential to store for this user. Supply hashes only; omit password to create no password identity. |
testUser | boolean | — | Create this user as a TEST FIXTURE: excluded from metering (it never counts toward retained-users), hidden from the default users_users_list view, never really emailed, and — when the deployment configures one — able to sign in with the fixed magic OTP. REFUSED unless this product has test mode enabled, which a production deployment cannot do. There is no way to set or clear this later. Default false. |
waitlisted | boolean | — | Create the user as a waitlist signup: no way in until promoted. Default false. |
identifiers | array | • | How this user is reached: their email addresses, plus any contact channels (`phone`, `telegram`, `linkedin`, `x`). At least one is required. |
requiresReset | boolean | — | Force a password reset before the user can sign in (use for unverifiable imported hashes). Default false. |
publicMetadata | object | — | Metadata the end user may READ and that may flow into the JWT. Management-plane write only. |
unsafeMetadata | object | — | Metadata the end user may WRITE in a later phase. Never trust it for authorization. |
privateMetadata | object | — | Metadata visible to the management plane only. Never exposed to the end user. |
Response
Field | Type | Always | Description |
|---|---|---|---|
id | string | • | Id of this end user. Pass it to any users_users_* tool. |
kind | string | • | What kind of person this row is: 'account' (can sign in) or 'contact' (known to the Product, no credential, never signed in). A contact is hidden from the default users_users_list view and is never counted as a retained user. |
name | string | • | The user's display name. Null when nobody set one. |
tags | array | • | Free labels on this person, stored trimmed, lowercased and de-duplicated. |
stage | string | • | The relationship stage, in funnel order: new, contacted, replied, engaged, converted, lost. A real change publishes `users/user.stage-changed`. |
bannedAt | string | • | When the user was banned (ISO 8601). Null while they are not banned. |
erasedAt | string | • | When this user's personal data was purged for good (ISO 8601). Null while it is intact. |
imageUrl | string | • | URL of the user's avatar. Null when there is none. |
testUser | boolean | • | Whether this is a test fixture — excluded from metering and from the default listing. |
createdAt | string | • | When the user was created (ISO 8601). |
deletedAt | string | • | When the user was soft-deleted (ISO 8601). Null while the account is live. |
productId | string | • | Product this user belongs to. Never an input — it comes from the calling identity. |
updatedAt | string | • | When the user was last changed (ISO 8601). |
mergedFrom | string | • | Set when you asked for an id that was merged into this account — it is the id you asked for, and this is the row it now lives in. Null on every ordinary read. |
waitlisted | boolean | • | Whether this user is still on the waitlist and cannot sign in yet. |
identifiers | array | • | Every identifier of this user, the primary one flagged. To bind the primary address itself, use `primaryEmail` — `identifiers.0` means "the first", not "the primary". |
lastTouchAt | string | • | When this person was last touched — the most recent logged interaction (ISO 8601). Null when nobody has logged one. This is when the interaction HAPPENED, not when it was logged. |
lockedUntil | string | • | When a failed-attempt lockout expires (ISO 8601). Null when the user is not locked out. |
lastSignInAt | string | • | When the user last signed in (ISO 8601). Null if they never have. |
primaryEmail | string | • | The user's primary email address, as typed. Null when they have no primary identifier. Bind this rather than `identifiers.0.value`. |
requiresReset | boolean | • | Whether the user must set a new password at their next sign-in. |
publicMetadata | object | • | Metadata the end user may read; the only bag projected into their access token. Capped at 1.2 KB. |
unsafeMetadata | object | • | Metadata the end user may write themselves. Treat it as untrusted. |
privateMetadata | object | • | Metadata for the management plane only. Never reaches the end user or a token. |
mergedIntoUserId | string | • | The user this person was merged INTO, when they were merged. Null for everybody else — follow it to find where their records went. |
primaryIdentifierId | string | • | Id of the primary identifier row. Null when there is no primary identifier. |
emailChangeLockedUntil | string | • | Until this instant the user may not start another email change, because somebody reverted one (ISO 8601). Null for a user who never reverted one. |
Try it
Create an end user of this product with at least one email identifier.