Saltar al contenido
Esc
↑↓navegar↵abrir⌘Jvista previa

Create or update a user by membership code

Collection-level create-or-update keyed by membership code in the body (v4 addresses resources by id in the path). Field semantics match PATCH (absent = unchanged, null = clear). Not a full replace. Never writes activity, roles, or cohorts. Created memberships follow POST /users defaults (inactive).

Adopt: if the code is unused but email matches a member of this institution whose code is null, the code is set and the API returns 200. The stored email casing is kept; the body’s casing is not written onto the global User.email.

Conflict: same email with a different non-null code (including an auto-generated code) → 409 application/problem+json with existingUserId when that user is a member of this institution.

Attach: email exists only in another institution → new membership on the existing user, like POST. The stored email casing is kept.

Email on update: email is match/create-only. On the update path a differing email is ignored. Change the email via PATCH /users/{id}.

dataFields: applied on both create and update, in the same transaction as the profile/membership write.

No-op: if every requested field matches the stored values (code compared case-insensitively), the API returns 200 without bumping updatedAt and without an UPDATED audit row. Unchanged codes skip user_code_format validation so a nightly full PUT does not 422 on legacy codes and leaves the next updatedSince empty.

A provided code on create is persisted and is not overwritten by later user_code_format auto-assign. Idempotency-Key is accepted but not required and is scoped to PUT /users (separate from POST /users). On any unique-key error (P2002), the API re-reads by (institutionId, code) then by email inside the caller institution and decides from those rows. The adapter index (meta.driverAdapterError.cause.constraint.index; meta.target is unset on Prisma 7.9 + PlanetScale) is only a hint. If the winner’s email differs from the loser’s body, the retry returns 409 instead of applying the loser’s body. Invite mail is sent only after a winning create commits; a mail failure still returns 201. code: "" on PUT is 422 because code is required.

PUT/users
Authorization
AuthorizationBasic auth · headerrequired

Basic Auth with clientId as username and clientSecret as password

Header parameters
Idempotency-Keystring

Optional. Accepted for replay, not required — PUT is idempotent.

Request body
requiredapplication/json
emailstring<email>
firstNamestring
lastNamestring
imagestring<uri> | null

URL as stored; no transcoding. null or an empty string clears the stored image.

dataFieldsUserDataFieldEntry[]
Show properties
Array of UserDataFieldEntry
fieldNamestringrequired
valuestring | nullrequired

Field value. null or an empty string clears the stored value.

sendInvitationboolean

Honoured only on a winning create. When false, skip only the mail. The Invite row, default role, SSO auto-sync, and alias pre-attach still run.

default: true
codestringrequired

Lookup and write key. Required. Trimmed, non-empty, max 191. Must match user_code_format when configured.

max length 191
preferredNamestring | null
dateOfBirthstring<date> | null
genderstring | null
Allowed:MALEFEMALEDIVERSE
nationalitiesstring[] | null
birthNamestring | null
countryOfBirthstring | null
placeOfBirthCitystring | null
Responses
200

Existing member updated (including adopt of a null code)

dataUserrequired
Show properties
idstringrequired
namestringrequired
emailstring<email>required
imagestring | nullrequired

URL as stored; no transcoding, resolution, or format conversion.

codestring | nullrequired

Institution membership code. One namespace per institution across students, staff, lecturers, and badge numbers. Unique per institution. Trimmed on write; empty becomes none. Case-insensitive under the database collation (FHM-1 equals fhm-1). When the institution has user_code_format, writes must match that format.

activityStatusUserActivityStatusrequired
Show properties
isActivebooleanrequired
isActiveFromstring<date-time> | nullrequired
isActiveUntilstring<date-time> | nullrequired
metaResponseMetarequired
Show properties
requestIdstringrequired
timestampstring<date-time>required
versionstringrequired
Allowed:v4
watermarkstring<date-time>

Present on GET /users?updatedSince= pages. Taken at the first page minus a 60s overlap. Bound into pagination.next_cursor. Use it as the next updatedSince after deduping by user id. Delivery is inclusive >= and at-least-once.

201

User or membership created

dataUserrequired
Show properties
idstringrequired
namestringrequired
emailstring<email>required
imagestring | nullrequired

URL as stored; no transcoding, resolution, or format conversion.

codestring | nullrequired

Institution membership code. One namespace per institution across students, staff, lecturers, and badge numbers. Unique per institution. Trimmed on write; empty becomes none. Case-insensitive under the database collation (FHM-1 equals fhm-1). When the institution has user_code_format, writes must match that format.

activityStatusUserActivityStatusrequired
Show properties
isActivebooleanrequired
isActiveFromstring<date-time> | nullrequired
isActiveUntilstring<date-time> | nullrequired
metaResponseMetarequired
Show properties
requestIdstringrequired
timestampstring<date-time>required
versionstringrequired
Allowed:v4
watermarkstring<date-time>

Present on GET /users?updatedSince= pages. Taken at the first page minus a 60s overlap. Bound into pagination.next_cursor. Use it as the next updatedSince after deduping by user id. Delivery is inclusive >= and at-least-once.

400

Bad Request

typestringrequired
Allowed:error
codestringrequired
Allowed:bad_requestunauthorizedforbiddenresource_not_foundconflictvalidation_failedidempotency_key_reusedidempotency_key_in_progressservice_unavailableretryablerate_limit_exceededinternal_error
titlestringrequired
statusintegerrequired
detailstringrequired
instancestring
errorsobject[]
Show properties
Array of object
fieldstring
messagestring
existingUserIdstring

Present on 409 email or membership-code conflicts. The user id that already holds the email or code.

activeSessionobject

Present on time-tracking start 409 when a session is already running. Stop this session, then retry start.

Show properties
idstringrequired
startTimestring<date-time>required
conflictingLogobject

Present on time-tracking 409 when the interval being written overlaps an existing log or open session. Start uses [punch, ∞). Stop uses [sessionStart, stop). endTime is null while that session is still open.

Show properties
idstringrequired
startTimestring<date-time>required
endTimestring<date-time> | nullrequired
401

Unauthorized

typestringrequired
Allowed:error
codestringrequired
Allowed:bad_requestunauthorizedforbiddenresource_not_foundconflictvalidation_failedidempotency_key_reusedidempotency_key_in_progressservice_unavailableretryablerate_limit_exceededinternal_error
titlestringrequired
statusintegerrequired
detailstringrequired
instancestring
errorsobject[]
Show properties
Array of object
fieldstring
messagestring
existingUserIdstring

Present on 409 email or membership-code conflicts. The user id that already holds the email or code.

activeSessionobject

Present on time-tracking start 409 when a session is already running. Stop this session, then retry start.

Show properties
idstringrequired
startTimestring<date-time>required
conflictingLogobject

Present on time-tracking 409 when the interval being written overlaps an existing log or open session. Start uses [punch, ∞). Stop uses [sessionStart, stop). endTime is null while that session is still open.

Show properties
idstringrequired
startTimestring<date-time>required
endTimestring<date-time> | nullrequired
409

Conflict — duplicate email or membership code (body includes existingUserId when known), a time-tracking session that is already running (activeSession), a time-tracking interval that overlaps an existing log (conflictingLog), idempotency key reused with a different body (idempotency_key_reused), or concurrent request with the same key still in progress (idempotency_key_in_progress)

typestringrequired
Allowed:error
codestringrequired
Allowed:bad_requestunauthorizedforbiddenresource_not_foundconflictvalidation_failedidempotency_key_reusedidempotency_key_in_progressservice_unavailableretryablerate_limit_exceededinternal_error
titlestringrequired
statusintegerrequired
detailstringrequired
instancestring
errorsobject[]
Show properties
Array of object
fieldstring
messagestring
existingUserIdstring

Present on 409 email or membership-code conflicts. The user id that already holds the email or code.

activeSessionobject

Present on time-tracking start 409 when a session is already running. Stop this session, then retry start.

Show properties
idstringrequired
startTimestring<date-time>required
conflictingLogobject

Present on time-tracking 409 when the interval being written overlaps an existing log or open session. Start uses [punch, ∞). Stop uses [sessionStart, stop). endTime is null while that session is still open.

Show properties
idstringrequired
startTimestring<date-time>required
endTimestring<date-time> | nullrequired
422

Unprocessable Entity — validation or business rule error

typestringrequired
Allowed:error
codestringrequired
Allowed:bad_requestunauthorizedforbiddenresource_not_foundconflictvalidation_failedidempotency_key_reusedidempotency_key_in_progressservice_unavailableretryablerate_limit_exceededinternal_error
titlestringrequired
statusintegerrequired
detailstringrequired
instancestring
errorsobject[]
Show properties
Array of object
fieldstring
messagestring
existingUserIdstring

Present on 409 email or membership-code conflicts. The user id that already holds the email or code.

activeSessionobject

Present on time-tracking start 409 when a session is already running. Stop this session, then retry start.

Show properties
idstringrequired
startTimestring<date-time>required
conflictingLogobject

Present on time-tracking 409 when the interval being written overlaps an existing log or open session. Start uses [punch, ∞). Stop uses [sessionStart, stop). endTime is null while that session is still open.

Show properties
idstringrequired
startTimestring<date-time>required
endTimestring<date-time> | nullrequired
429

Too Many Requests — 1000 requests per minute per institution. Includes X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset (ISO-8601), and Retry-After (seconds).

typestringrequired
Allowed:error
codestringrequired
Allowed:bad_requestunauthorizedforbiddenresource_not_foundconflictvalidation_failedidempotency_key_reusedidempotency_key_in_progressservice_unavailableretryablerate_limit_exceededinternal_error
titlestringrequired
statusintegerrequired
detailstringrequired
instancestring
errorsobject[]
Show properties
Array of object
fieldstring
messagestring
existingUserIdstring

Present on 409 email or membership-code conflicts. The user id that already holds the email or code.

activeSessionobject

Present on time-tracking start 409 when a session is already running. Stop this session, then retry start.

Show properties
idstringrequired
startTimestring<date-time>required
conflictingLogobject

Present on time-tracking 409 when the interval being written overlaps an existing log or open session. Start uses [punch, ∞). Stop uses [sessionStart, stop). endTime is null while that session is still open.

Show properties
idstringrequired
startTimestring<date-time>required
endTimestring<date-time> | nullrequired
500

Internal Server Error

typestringrequired
Allowed:error
codestringrequired
Allowed:bad_requestunauthorizedforbiddenresource_not_foundconflictvalidation_failedidempotency_key_reusedidempotency_key_in_progressservice_unavailableretryablerate_limit_exceededinternal_error
titlestringrequired
statusintegerrequired
detailstringrequired
instancestring
errorsobject[]
Show properties
Array of object
fieldstring
messagestring
existingUserIdstring

Present on 409 email or membership-code conflicts. The user id that already holds the email or code.

activeSessionobject

Present on time-tracking start 409 when a session is already running. Stop this session, then retry start.

Show properties
idstringrequired
startTimestring<date-time>required
conflictingLogobject

Present on time-tracking 409 when the interval being written overlaps an existing log or open session. Start uses [punch, ∞). Stop uses [sessionStart, stop). endTime is null while that session is still open.

Show properties
idstringrequired
startTimestring<date-time>required
endTimestring<date-time> | nullrequired
Try it
Server
Authorization
Parameters
Bodyapplication/json
Request
curl -X PUT 'https://fuxam.app/api/v4/users' \
  -H 'Authorization: Basic YOUR_CREDENTIALS' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
  "code": "STU-001",
  "email": "jane@example.com",
  "firstName": "Jane",
  "lastName": "Doe",
  "sendInvitation": true
}'
Response
{
  "data": {
    "id": "clx1234567890",
    "name": "Jane Doe",
    "email": "jane@example.com",
    "image": "string",
    "code": "STU-001",
    "activityStatus": {
      "isActive": true,
      "isActiveFrom": "2026-01-01T00:00:00.000Z",
      "isActiveUntil": "2019-08-24T14:15:22Z"
    }
  },
  "meta": {
    "requestId": "req_1234567890_abc",
    "timestamp": "2026-06-02T07:00:00.000Z",
    "version": "v4",
    "watermark": "2019-08-24T14:15:22Z"
  }
}

¿Te ha resultado útil esta página?