Returning.AIDevelopers
v1

API reference / User Fields

.md

Create a user field definition

Add a custom user field to your community, such as a KYC status, and get back the key you use to write traders' values.

Last updated 26 Sep 2026API v1

Method
POST
Path
https://api.returning.ai/v1/communities/{communityId}/user-fields
Permission
userFields
Retries
Idempotency-Key makes retries safe

When to use this

  • You want to track a trader attribute from your platform, such as KYC status, account tier or trading volume.
  • You are setting up a new integration and its fields don't exist yet.
  • You want a typed field that milestones and data workflows can react to when a trader's value changes.

Authentication#

Header
Authorization: Bearer <API_KEY>
Permission
userFieldsShown in the dashboard as “User Fields”

Use a Community API key with the userFields permission, and keep it on your server. communityId must be the ID of the community that owns the key.

Behaviour#

The key is cleaned up before it is saved: surrounding spaces are removed, capitals become lowercase and spaces inside become _, so KYC Status is stored as kyc_status. Save data.field from the response, not what you sent. The key can never change; the name, type and default can.

Select-dropdown fields can be created, but their values can't be written with Update a user field value yet.

Request#

Path parameters#

communityId#stringREQUIRED
Your community's ID. It must be the community that owns your API key.

Rule24 hex characters

Eg"66f000000000000000000010"

Headers#

Authorization#stringREQUIRED
Community API key with userFields.

RuleBearer <API_KEY>

Idempotency-Key#stringOPTIONAL
Optional. Send a unique value per new field, and the same value when you retry that request. Kept for 24 hours.

Rule1-200 chars; ^[!-~]{1,200}$

Eg"create-kycstatus"

Content-Type#stringREQUIRED
Request body format.

Ruleapplication/json

Body#

Send only name, field, type and, optionally, defaultValue; any other property is rejected. A non-null defaultValue must match type exactly:

  • single-line-text: a string of 1-255 characters with no line breaks.
  • multi-line-text: any string, including an empty one.
  • numerical: a JSON number, not a string.
  • boolean: true or false.
  • date: a real date as YYYY-MM-DD.
  • time: HH:mm:ss, 24-hour.
  • date-time: YYYY-MM-DDTHH:mm:ss, with optional milliseconds and an optional Z or offset such as +08:00.
  • single-select-dropdown: a string or number. multi-select-dropdown: an array of them.
name#stringREQUIRED
Display name shown in the dashboard. Unique in your community, ignoring case.

RuleASCII letters, numbers, spaces, - and _

Eg"KYC status"

field#stringREQUIRED
The field key. Unique in your community and can never be changed. Spaces become _ and capitals become lowercase.

RuleAfter cleanup: 1-120 chars of a-z, 0-9, _, -

Eg"kycstatus"

type#stringREQUIRED
The field type. It decides which values you can write later.

Rulesingle-line-text, multi-line-text, numerical, date, time, date-time, boolean, single-select-dropdown, multi-select-dropdown

Eg"single-line-text"

defaultValue#anyOPTIONAL
Optional default, in the field's type. Omit it or send null for none.

RuleMatches type; see Request body

curl --request POST \
  --url https://api.returning.ai/v1/communities/66f000000000000000000010/user-fields \
  --header 'Authorization: Bearer <API_KEY>' \
  --header 'Content-Type: application/json' \
  --header 'Idempotency-Key: create-field-<unique-id>' \
  --data '{
    "name": "KYC status",
    "field": "kycstatus",
    "type": "single-line-text"
  }'

Response#

A 201 means the field is saved. Branch on the HTTP status and meta.code, never on message.

meta#objectALWAYS

Eg{ ... }

status#stringALWAYS

Rulesuccess

statusCode#integerALWAYS

Rule201

code#stringALWAYS
Machine-readable result code.

RuleUSER_FIELD_CREATED

compatibilityEvent#stringALWAYS
attempted normally. failed means open dashboards were not refreshed; the field is still saved.
idempotentReplay#booleanON REPLAY
true when this repeats the first response for your Idempotency-Key. Nothing new was created.
idempotencyPersistence#stringWHEN DEGRADED
degraded when the field was saved but a retry with the same key may not replay this response. Treat the field as created.
message#stringALWAYS
Human-readable summary. Do not branch on it.

Eg"Create user field api success."

data#objectALWAYS
The new definition.

Eg{ ... }

_id#stringALWAYS
The definition's ID. Accepted wherever a field key is.

Rule^[0-9a-fA-F]{24}$

Eg"66f000000000000000000510"

name#stringALWAYS
The stored display name, trimmed.

Eg"KYC status"

field#stringALWAYS
The stored key. Save this value; it may differ from what you sent.

Rulea-z, 0-9, _, -

Eg"kycstatus"

type#stringALWAYS
The field type.

Rulesingle-line-text, multi-line-text, numerical, date, time, date-time, boolean, single-select-dropdown, multi-select-dropdown

Eg"single-line-text"

defaultValue#any
The stored default. Left out when you sent none.
isCustom#booleanALWAYS
Always true for fields you create.
createdAt#stringALWAYS
When the definition was created.
updatedAt#stringALWAYS
When the definition last changed.
{
  "meta": {
    "status": "success",
    "statusCode": 201,
    "code": "USER_FIELD_CREATED",
    "compatibilityEvent": "attempted"
  },
  "message": "Create user field api success.",
  "data": {
    "_id": "66f000000000000000000510",
    "name": "KYC status",
    "field": "kycstatus",
    "type": "single-line-text",
    "isCustom": true,
    "createdAt": "2026-09-26T08:30:00.000Z",
    "updatedAt": "2026-09-26T08:30:00.000Z"
  }
}

Errors#

Every JSON error carries its code in meta.code. The exception is a request with no Authorization header and a JSON body: it returns 400 with a non-JSON body instead of 401. A 400 or 409 creates nothing.

Fix the request06

400Fix the request
No Authorization header was sent. With a JSON body this returns 400 with a non-JSON body (Request body must encrypted), not 401. Send Authorization: Bearer <API_KEY>.
400INVALID_FIELD_DEFINITIONFix the request
name, field, type or defaultValue broke a rule, or the body has an extra property. detail names the field when it can. Nothing was created.
400INVALID_IDEMPOTENCY_KEYFix the request
The Idempotency-Key must be 1-200 visible ASCII characters with no spaces.
401AUTHENTICATION_REQUIREDFix the request
The key is invalid or expired, or no key was sent with an empty body. Send Authorization: Bearer <API_KEY> with a current Community API key.
403API_KEY_PERMISSION_DENIEDFix the request
The key lacks userFields. Add the permission in Settings > Integration > API Keys.
403API_KEY_COMMUNITY_MISMATCHFix the request
communityId is not the community that owns your key. Use your own community's ID.

Fix the data04

409USER_FIELD_KEY_CONFLICTFix the data
A field with this key already exists, built-in or custom. Use the existing field, or choose another key.
409USER_FIELD_NAME_CONFLICTFix the data
Another field already has this name, ignoring case. Choose another name.
409IDEMPOTENCY_KEY_CONFLICTFix the data
This Idempotency-Key was already used for a different field. Use a new key for a new field.
404COMMUNITY_NOT_FOUNDFix the data
The community this key belongs to no longer exists. Contact Returning.AI support.

Retry with backoff02

500USER_FIELD_OPERATION_FAILEDRetry with backoff
The outcome is unclear. List your fields and check for the key before you create it again.
503IDEMPOTENCY_STORE_UNAVAILABLERetry with backoff
Nothing was created. Retry the same request, with the same key, after a short wait.

Do not retry01

409IDEMPOTENCY_REQUEST_IN_PROGRESSDo not retry
A request with this key is still running, or its outcome is unclear. List your fields to see whether the key exists before doing anything else.
{
  "meta": {
    "status": "error",
    "statusCode": 400,
    "code": "INVALID_FIELD_DEFINITION"
  },
  "message": "Create user field api error.",
  "detail": {
    "field": [
      "field must use ASCII letters, numbers, \"_\", or \"-\" after normalization."
    ]
  },
  "solution": "Check the request body and try again."
}

Next step#

Update a user field valuePOST/v1/communities/{communityId}/users/{userId}/user-fields/{fieldIdOrName}/historiesWrite a trader's value for the new field, using data.field as the key.