Skip to main content
Fetch or Create User by Foreign ID
Returns the user with this foreignId — the external identifier from your own system — or creates them when there is none. Service key only: this endpoint creates users, so only your backend may call it. To read a user without creating one, use Fetch User by Foreign ID (GET). Everything goes in the JSON request body, so the profile, secureMetadata included, never appears in a URL. The whole request body can be at most 100 KB, metadata and secureMetadata included.
  • Existing user: 200 with the user, unchanged. The profile fields are used only to create a user; they never update one.
  • No user: the user is created with the body’s profile, 201.
  • Two concurrent calls for the same new foreignId: one user is created. The call that loses the race answers 200 with that user.
If the user exists and has blocked the viewer — the user named in actingUserId — this returns 404, the same response as the read. Nothing is created. Requires the moderation bundle.

Body Parameters

string
required
The external identifier from your system. It is stored and matched exactly as sent. A blank or whitespace-only value ("", " ") returns 400 user/invalid-body (foreignId: Foreign ID is required).
string
Display name. Used only when the user is created.
string
Username, unique within the project. Used only when the user is created. The same rules as on sign-up and Update User: 3 to 30 characters after trimming, only letters, numbers, underscores (_) and hyphens (-). Anything else returns 400 user/invalid-body. A username another user holds returns 409.
string | null
Avatar URL, or null for none. Used only when the user is created.
string
Bio text. Used only when the user is created.
object
Public custom data, a JSON object. Used only when the user is created. A JSON string is refused (400 user/invalid-body).
object
Private custom data, a JSON object. Never returned by the API. Used only when the user is created.
string | string[]
Associations to include, as a comma-separated string or an array. The only value is:
  • files — the processed avatarFile and bannerFile objects
Matching ignores case. An unknown value returns 400 user/invalid-body.
string
The user the response is read as: a user who has blocked them comes back as 404, as on the read. It never changes who creates: a user this request creates is always created by your app. Leave it out for the anonymous view.

Space-scoped reputation

This endpoint has no space in context, so the opt-in spaceReputation object accepts a spaceId of a space <uuid> or none only — context is rejected (400). It adds a spaceReputation field to the returned user, alongside the always-present reputation total. Send it in the body: spaceReputationId as a string, spaceReputationDescendants as a boolean ("true" and "false" are accepted too). Requires the reputation bundle. See the Reputation data model.
Every field goes in the body. Any of them sent in the query string returns 400 user/wrong-location.

Response

Returns HTTP 200 (an existing user) or 201 (a user this request created), with the same user object as the read:
string
Unique user ID (UUID).
string | null
The foreign ID you provided.
string
Project this user belongs to.
string | null
Display name.
string | null
Unique username within the project.
string | null
Avatar image URL.
string | null
Short bio text.
object | null
Public custom key-value data.
number
Reputation score.
object | null
Processed avatar image with variants. Only present when include=files is requested.
object | null
Processed banner image with variants. Only present when include=files is requested.
string
ISO timestamp of account creation.
Monthly active users: a request naming actingUserId counts that user, as on the read. Creating a user counts no one.

Error Responses

A user token, even one naming an actingUserId, or a request with no credentials. Nothing is created.
Returned for an invalid body: a missing or blank foreignId, a username that breaks the rules above, a metadata or secureMetadata that isn’t an object, or an unknown include value. The error names the field, for example:
  • foreignId: Foreign ID is required
  • username: Username must be at least 3 characters
  • username: Username cannot exceed 30 characters
  • username: Username can only contain letters, numbers, underscores, and hyphens
A body field was sent in the query string (foreignId, name, include, spaceReputationId, actingUserId, …).
The user exists and has blocked the actingUserId viewer. Nothing is created.
actingUserId names a user that isn’t in this project.
No user has this foreignId, and another user already holds the username (or another unique field) in this project. Nothing is created.

See Also