Docs

API reference / Users

Update a user’s profile

PATCH/v1/users/{id}

API key required

Partially updates the extended profile of a user. Only the fields you send are validated and changed; send null to clear a field (not allowed for a required module of your published signup flow). Same validation rules as POST /v1/users. The phone number and external_id cannot be changed.

Authentication#

Send a secret API key as Authorization: Bearer <key>. Both tp_test_… and tp_live_… keys work; the key decides which environment you read and write. See Authentication.

Parameters#

Path

Path parameters
NameTypeDescription
idrequiredstringIdentifier of the user.Pattern ^\d{1,9}$

Request body#

  • emailstring | null

    Email address. Module email of your signup flow.

    max length: 254

    Example "[email protected]"

  • first_namestring | null

    First name. Module first_name.

    min length: 1 · max length: 100

    Example "Ada"

  • last_namestring | null

    Last name. Module last_name.

    min length: 1 · max length: 100

    Example "Lovelace"

  • birth_datestring | null

    Date of birth, YYYY-MM-DD. Module birth_date; the min_age option of your signup flow is enforced.

    pattern: ^\d{4}-\d{2}-\d{2}$

    Example "1990-12-10"

  • countrystring | null

    Country, ISO 3166-1 alpha-2. Module country; the allowed_countries option of your signup flow is enforced.

    pattern: ^[A-Za-z]{2}$

    Example "FR"

  • referral_codestring | null

    Referral code entered at signup. Stored as given; module referral_code.

    pattern: ^[A-Za-z0-9_-]{3,32}$

    Example "ADA2026"

  • terms_acceptanceobject | null

    Acceptance of your terms. Module terms_acceptance.

    • versionstringrequired

      Version of the terms accepted.

      min length: 1 · max length: 64

      Example "2026-10"

    • accepted_atstringrequired

      When the user accepted them (ISO 8601, not in the future).

      format: date-time

      Example "2026-10-08T09:29:00.000Z"

  • tagnamestring | null

    Username chosen by the user (unique per project and environment, case-insensitive). Module tagname.

    pattern: ^[A-Za-z0-9_.-]{3,30}$

    Example "ada_l"

Example request body
{
  "first_name": "Ada",
  "country": "GB"
}

Responses#

200The updated user.

Headers

  • X-Request-Id Request identifier.
  • X-RateLimit-Limit Quota of the current window.
  • X-RateLimit-Remaining Requests remaining in the window.
  • X-RateLimit-Reset Seconds before the quota renews.

Body

  • idstringrequired

    Opaque identifier.

    Example "4821"

  • objectstringrequired

    always "user"

    Example "user"

  • phonestringrequired

    Phone number in E.164 format.

    Example "+33612345678"

  • external_idstring | nullrequired

    Your own identifier for this user.

    Example "cust_8f2a"

  • verifiedbooleanrequired

    The phone number has been verified.

    Example true

  • kyc_statusstringrequired

    Identity verification (KYC) status.

    One ofnonependingapprovedrejected

    Example "approved"

  • suspendedbooleanrequired

    The user is suspended and can no longer transact.

    Example false

  • livemodebooleanrequired

    true for a live key, false for a sandbox key.

    Example false

  • wallet_statusstringrequired

    State of the user’s wallet. ready: the wallet exists. pending: its creation is in progress or being retried (never blocks the user; poll GET /v1/users/{id}/wallets). failed: creation was abandoned after repeated errors (contact support). none: no wallet is created at this step.

    One ofnonependingreadyfailed

    Example "ready"

  • created_atstringrequired

    Creation date.

    format: date-time

    Example "2026-10-08T09:30:00.000Z"

  • last_login_atstring | nullrequired

    Last sign-in.

    format: date-time

    Example "2026-10-08T09:30:00.000Z"

  • profileobject | nullrequired

    Extended profile of a user, collected by your signup flow. Personal data: returned only by GET /v1/users/{id} and PATCH /v1/users/{id}, never in lists, events or webhooks.

    • objectstringrequired

      always "profile"

      Example "profile"

    • emailstring | nullrequired

      Email address (lowercased).

      Example "[email protected]"

    • first_namestring | nullrequired

      First name.

      Example "Ada"

    • last_namestring | nullrequired

      Last name.

      Example "Lovelace"

    • birth_datestring | nullrequired

      Date of birth (YYYY-MM-DD).

      Example "1990-12-10"

    • countrystring | nullrequired

      Country (ISO 3166-1 alpha-2).

      Example "FR"

    • referral_codestring | nullrequired

      Referral code entered at signup.

      Example "ADA2026"

    • terms_acceptanceobject | nullrequired

      Acceptance of your terms.

      • versionstringrequired

        Version of the terms accepted.

        Example "2026-10"

      • accepted_atstringrequired

        When the user accepted them.

        format: date-time

        Example "2026-10-08T09:30:00.000Z"

    • tagnamestring | nullrequired

      Username chosen by the user.

      Example "ada_l"

    • updated_atstringrequired

      Last update.

      format: date-time

      Example "2026-10-08T09:30:00.000Z"

Example 200 response
{
  "id": "4821",
  "object": "user",
  "phone": "+33612345678",
  "external_id": "cust_8f2a",
  "verified": true,
  "kyc_status": "approved",
  "suspended": false,
  "livemode": false,
  "created_at": "2026-10-08T09:30:00.000Z",
  "wallet_status": "ready",
  "last_login_at": null,
  "profile": {
    "object": "profile",
    "email": "[email protected]",
    "first_name": "Ada",
    "last_name": "Lovelace",
    "birth_date": "1990-12-10",
    "country": "FR",
    "referral_code": "ADA2026",
    "terms_acceptance": {
      "version": "2026-10",
      "accepted_at": "2026-10-08T09:29:00.000Z"
    },
    "tagname": "ada_l",
    "updated_at": "2026-10-08T09:30:00.000Z"
  }
}
400Invalid request (malformed JSON, unknown cursor, invalid Idempotency-Key header).

Example: invalid_cursor

Example 400 response
{
  "error": {
    "type": "invalid_request_error",
    "code": "invalid_cursor",
    "message": "starting_after: unknown cursor",
    "request_id": "0b2c8f6e-41f9-4c0a-8d55-6f6a3c1d9e21"
  }
}
401Missing, invalid or revoked API key.

Example: missing_api_key

Example 401 response
{
  "error": {
    "type": "authentication_error",
    "code": "missing_api_key",
    "message": "Provide your API key as \"Authorization: Bearer <key>\"",
    "request_id": "0b2c8f6e-41f9-4c0a-8d55-6f6a3c1d9e21"
  }
}

Example: invalid_api_key

Example 401 response
{
  "error": {
    "type": "authentication_error",
    "code": "invalid_api_key",
    "message": "The API key is invalid",
    "request_id": "0b2c8f6e-41f9-4c0a-8d55-6f6a3c1d9e21"
  }
}

Example: api_key_revoked

Example 401 response
{
  "error": {
    "type": "authentication_error",
    "code": "api_key_revoked",
    "message": "This API key has been revoked",
    "request_id": "0b2c8f6e-41f9-4c0a-8d55-6f6a3c1d9e21"
  }
}
403Organization suspended, live access not enabled, or sandbox-only route.

Example: organization_suspended

Example 403 response
{
  "error": {
    "type": "permission_error",
    "code": "organization_suspended",
    "message": "Your organization is suspended. Contact Tilt Pay support.",
    "request_id": "0b2c8f6e-41f9-4c0a-8d55-6f6a3c1d9e21"
  }
}

Example: live_not_enabled

Example 403 response
{
  "error": {
    "type": "permission_error",
    "code": "live_not_enabled",
    "message": "Live access has not been enabled for your organization yet",
    "request_id": "0b2c8f6e-41f9-4c0a-8d55-6f6a3c1d9e21"
  }
}

Example: sandbox_only

Example 403 response
{
  "error": {
    "type": "permission_error",
    "code": "sandbox_only",
    "message": "This route is only available with a sandbox API key",
    "request_id": "0b2c8f6e-41f9-4c0a-8d55-6f6a3c1d9e21"
  }
}
404Resource not found (or belonging to another project or environment).

Example: user_not_found

Example 404 response
{
  "error": {
    "type": "invalid_request_error",
    "code": "user_not_found",
    "message": "User not found",
    "request_id": "0b2c8f6e-41f9-4c0a-8d55-6f6a3c1d9e21"
  }
}
409Conflict with the state of the resource, or the original idempotent request is still in progress.

Example: user_already_exists

Example 409 response
{
  "error": {
    "type": "invalid_request_error",
    "code": "user_already_exists",
    "message": "A user with this phone number already exists",
    "request_id": "0b2c8f6e-41f9-4c0a-8d55-6f6a3c1d9e21"
  }
}
422Invalid parameter, or Idempotency-Key reused with a different body.

Example: validation_error

Example 422 response
{
  "error": {
    "type": "invalid_request_error",
    "code": "validation_error",
    "message": "phone: has an invalid format",
    "request_id": "0b2c8f6e-41f9-4c0a-8d55-6f6a3c1d9e21"
  }
}

Example: idempotency_key_reuse

Example 422 response
{
  "error": {
    "type": "idempotency_error",
    "code": "idempotency_key_reuse",
    "message": "This Idempotency-Key was already used with a different request",
    "request_id": "0b2c8f6e-41f9-4c0a-8d55-6f6a3c1d9e21"
  }
}
429Rate limit exceeded. Retry after the Retry-After delay (seconds).

Example: rate_limit_exceeded

Example 429 response
{
  "error": {
    "type": "rate_limit_error",
    "code": "rate_limit_exceeded",
    "message": "Too many requests. Slow down and retry after the delay in Retry-After.",
    "request_id": "0b2c8f6e-41f9-4c0a-8d55-6f6a3c1d9e21"
  }
}
500Internal error. Retry; give request_id to support if it persists.

Example: internal_error

Example 500 response
{
  "error": {
    "type": "api_error",
    "code": "internal_error",
    "message": "Internal server error",
    "request_id": "0b2c8f6e-41f9-4c0a-8d55-6f6a3c1d9e21"
  }
}

Headers on every response

  • X-Request-Id Identifier of the request, also present in error bodies. Give it to support.
  • X-API-Version Version of the API that answered.
  • X-RateLimit-Limit / -Remaining / -Reset Quota of your key for the current window. See Rate limits.

Errors#

Errors share one format, described in Errors. Branch your code on error.code.

Errors this route can return
StatusCodeMeaning
400invalid_cursorInvalid request (malformed JSON, unknown cursor, invalid Idempotency-Key header).
401missing_api_keyMissing, invalid or revoked API key.
401invalid_api_keyMissing, invalid or revoked API key.
401api_key_revokedMissing, invalid or revoked API key.
403organization_suspendedOrganization suspended, live access not enabled, or sandbox-only route.
403live_not_enabledOrganization suspended, live access not enabled, or sandbox-only route.
403sandbox_onlyOrganization suspended, live access not enabled, or sandbox-only route.
404user_not_foundUnknown user (or belonging to another project or environment).
409user_already_existsConflict with the state of the resource, or the original idempotent request is still in progress.
409tagname_already_takenThis tagname is already used by another user of the project.
422validation_errorInvalid field, field not enabled in the published signup flow, or required value cleared (param names the field).
422idempotency_key_reuseInvalid parameter, or Idempotency-Key reused with a different body.
429rate_limit_exceededRate limit exceeded. Retry after the Retry-After delay (seconds).
500internal_errorInternal error. Retry; give request_id to support if it persists.