Returning.AIDevelopers
v1

Guides / Broker Integrations

.md

Enroll traders

Enroll a trader after the broker has committed the registration. Keep a stable, broker-owned person key separate from trading account IDs, then read the Returning.AI user and membership back before you mint a widget token.

Enrollment boundary before the widget

The broker owns the registration commit. Returning.AI owns the community user and membership readback.

  1. Commit broker registration

    Broker server

    Persist the customer record and its stable broker key first. Keep ACCOUNT_2001 and other trading accounts as account records, not new loyalty users by accident.

  2. Create the community user

    Broker server

    Call POST /v1/users with the community key, the configured identity, and joinServer: true. The public gateway is api.returning.ai/v1.

  3. Read identity and membership back

    Broker server

    Save a successful joinServer: true create receipt. Read the user with the configured field allowlist. Existing or ambiguous users need a separate confirmed membership/activation readback.

  4. Only after the readback is consistent, mint an Access Key Embed token for the same configured identifier and mount the supplied widget pair.

Choose a stable person key

Use a durable broker customer identity such as CUSTOMER_1001 for the person-level mapping. Keep ACCOUNT_2001 and ACCOUNT_2002 attached to that person in broker data. Trading account IDs are not a reason to create separate Returning.AI users unless your approved business mapping says they are.

ValueOwner and meaningUse in this flow
CUSTOMER_1001Broker stable person identifierTop-level externalId, or the configured custom field fallback. Use the same namespace for the widget only when the widget is configured for it.
ACCOUNT_2001Broker trading account identifierKeep it in broker account and trading records. Do not use it as the user identity by default.
<PLATFORM_USER_ID>Returning.AI numeric platform ID returned by createSave it as an opaque string. It is separate from CUSTOMER_1001 and is a reliable readback selector after create.
customer-1001@example.comKnown email used by the current lookup operationA lookup input, not a guaranteed response field. Matching an email alone is not proof of the configured broker identity or usable membership.

Enroll after the broker commit

The browser should not create a community user from a query parameter or an unverified page event. Your server should receive the broker registration, validate the stable key and email, then make the community request. This keeps retries tied to a broker record that can be reconciled by an owner.

  1. Commit the broker customer and account mapping.
  2. Confirm which community field is the active identifier, or choose the configured custom-field fallback.
  3. Submit the user request with joinServer: true so the create path can return a usable membership result.
  4. Save the returned platform and membership identifiers, then perform the readback below.

Create the user

Use POST https://api.returning.ai/v1/users with a Bearer community API key that hascreateUser. The key selects the community, so do not add communityId to this request body. The example uses the active identifier form; confirm that mapping with the community owner before sending it.

enroll-trader.sh
export RAI_API_BASE="https://api.returning.ai/v1"
export COMMUNITY_API_KEY="<COMMUNITY_API_KEY>" # server-side only

curl --fail-with-body --request POST "$RAI_API_BASE/users" \
  --header "Authorization: Bearer $COMMUNITY_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "firstname": "Ada",
    "lastname": "Lovelace",
    "username": "customer_1001",
    "displayname": "Customer 1001",
    "email": "customer-1001@example.com",
    "accessLevel": 1,
    "joinServer": true,
    "sendEmail": false,
    "emailPassword": false,
    "externalId": "CUSTOMER_1001"
  }'

If the community does not have an active external identifier, replace externalId with the configured stable field in customFields. The endpoint accepts the current spelling fieldIdorName; use one identity path, not two competing values.

custom-field-body.json
{
  "firstname": "Ada",
  "lastname": "Lovelace",
  "username": "customer_1001",
  "displayname": "Customer 1001",
  "email": "customer-1001@example.com",
  "accessLevel": 1,
  "joinServer": true,
  "sendEmail": false,
  "emailPassword": false,
  "customFields": [
    {
      "fieldIdorName": "customer_id",
      "value": "CUSTOMER_1001"
    }
  ]
}

Save the create result

The following is a response-field excerpt, not a full schema. Treat data.userId as an opaque platform identifier even when it is numeric. Treat communityMemberId as a membership checkpoint, not as the broker customer key.

create-response.json
{
  "status": "success",
  "data": {
    "userId": "<PLATFORM_USER_ID>",
    "communityMemberId": "<COMMUNITY_MEMBER_OBJECT_ID>",
    "externalId": "CUSTOMER_1001",
    "created": true
  }
}

Read identity and membership back

Read the user after create, before field writes or widget token minting. The current tested selectors are a known email or the numeric platform ID returned by create. Custom-field lookup and projection are environment-sensitive, so do not make an unverified broker-key lookup your only recovery path. Explicitly request the configured identity field incustomFields; without that allowlist the response can contain an empty field map. The example assumes the configured key iscustomer_id. Replace it with your actual field key.

read-user.sh
export RAI_API_BASE="https://api.returning.ai/v1"
export COMMUNITY_API_KEY="<COMMUNITY_API_KEY>" # server-side only

# Use the known email when it is available.
curl --fail-with-body --request POST "$RAI_API_BASE/users/info" \
  --header "Authorization: Bearer $COMMUNITY_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{"idOrEmail":"customer-1001@example.com","customFields":["customer_id"]}'

# Or use the opaque platform ID returned by create.
curl --fail-with-body --request POST "$RAI_API_BASE/users/info" \
  --header "Authorization: Bearer $COMMUNITY_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{"idOrEmail":"<PLATFORM_USER_ID>","customFields":["customer_id"]}'

Compare data.userId with the saved platform ID anddata.customFields.customer_id with CUSTOMER_1001. Email selects the lookup; it is not a returned-field assertion. If the target cannot expose the configured mapping, keep enrollment unresolved and ask the Returning.AI owner to verify the broker-to-platform mapping. An empty field map or a same-email match does not satisfy that check.

read-user-response.json
{
  "data": {
    "_id": "<MONGO_USER_OBJECT_ID>",
    "userId": "<PLATFORM_USER_ID>",
    "username": "customer_1001",
    "customFields": {
      "customer_id": "CUSTOMER_1001"
    }
  }
}

Confirm usable membership

For a new user, retain the confirmed successful create receipt for yourjoinServer: true request, including its membership identifier, together with the matching identity readback. A membership row alone is insufficient: invitation-pending rows can exist, and ordinary user lookup does not return the activation state.

For an existing user or an ambiguous create without that receipt, require the target's supported membership/activation readback or an explicit Returning.AI-owned confirmation of usable membership in the target community. Record the platform user ID, community, confirmed state, and evidence reference. Recover the missing receipt through this check, never another create request. Do not mint a widget token while it is unresolved.

A successful user lookup is a profile/identity read, not an activation check. Do not treat HTTP 200, a membership identifier or the word “active” in a lookup description as permission to mint. For unattended recovery, obtain the supported state check for your actual environment from the Returning.AI community owner; otherwise use the explicit confirmation above and keep that user blocked until it is recorded. Name the contact and evidence in the handover decision gates.

Handle existing and ambiguous outcomes

An existing user is a reconciliation case. Read it by known email or saved platform ID, compare the configured identity, and continue only after both the mapping and the usable membership check are confirmed. Do not merge unrelated users because an email happens to match, and do not generate a second broker key to avoid a conflict.

  • A 404 or empty read during an ambiguous create is not proof that the original write did not finish.
  • A duplicate result means read and reconcile the existing identity; it is not permission to create another user.
  • If referral association or a later milestone read is delayed, keep the committed user and reconcile that follow-up separately. Never recreate the user for a referral failure.
  • Keep the bounded retry policy endpoint-specific. This create example does not add a retry header that the current public operation does not document or promise an all-or-nothing result.

Open your first widget

Once the platform ID, confirmed usable membership, and configured identity readback agree, continue with the server-side Access Key flow. The community API key used here is not the SDKaccessId/accessKey pair. Mint the token from the trusted portal session and sign the same configured identity value used during enrollment.

Open your first widget with the current custom-widget quickstart, including token refresh and sign-out cleanup. Then choose a data path for lifecycle events and trading facts.

Operation references

Use the operation-specific API pages for the full current request contract: create a user and get user data. Confirm the active identifier mapping and permissions for the target community before moving from these synthetic examples to your server.