Returning.AIDocs
v1

API reference / Legacy / Bulk Operations

.md

Bulk import users from CSV

Upload a CSV that creates many new traders in one background job, with their custom field values.

Last updated 28 Oct 2026API v1

Method
POST
Path
https://api.returning.ai/v1/users/bulk-import
Permission
bulkImportUser
Retries
Not idempotent, but uploading the same file again rejects traders who already exist

When to use this

  • You are moving your existing customers onto Returning.AI and need to create them all at once.
  • You want each new trader's custom fields, such as funded dates or revenue, filled in on day one.
  • A batch of new sign-ups arrives as a file rather than one by one.

Authentication#

Header
Authorization: Bearer <API_KEY>
Permission
bulkImportUserShown in the dashboard as “Bulk Import Users”. Keys with “Bulk Update User” are also accepted.

Uploading needs bulkImportUser, shown in the dashboard as Bulk Import Users. Keys with bulkUpdateUser (Bulk Update User) are also accepted, but give new keys the import permission. Reading the custom field job back needs getBulkUpdate as well. The traders are always created in the API key's community. Keep the key on your server.

Behaviour#

The upload only queues the import. It then runs in the background, in two steps:

  1. Create the traders. Every row is checked first. Valid rows become traders; invalid rows are skipped with a reason, and the rest of the file still imports.
  2. Write the custom fields. If the file has custom field columns, one bulk update job is queued for the traders just created once step 1 finishes. It appears in List bulk update jobs as Bulk import custom fields (...), and you can follow it like any other bulk update.

The import itself is shown in your community's API Logs, with a file of every row and its error. It does not appear in List bulk update jobs. To check it from the API, look the traders up with Get User Data, or read logType=api records in Retrieve and export community logs from the time of your upload: the import is named Bulk Import Users, with its status and progress.

  • The import fails (Error in community logs) only when the whole file cannot be processed, for example when a required column is missing or the file cannot be read. The reason is shown on the job, such as Missing required headers - Email.
  • A completed import (Complete) can still include skipped rows, for example 3 users failed validation.
  • Custom field values go through a normal bulk update, so milestones, tiers and other rewards that use those fields react exactly as they would to a bulk update. Roles given in the file apply their role rewards.
  • If your community has an active set-up-password email template, each new trader is emailed a link to set their password. Without one, no email is sent.

Request#

Headers#

Authorization#stringREQUIRED
Community API key with bulkImportUser or bulkUpdateUser. The traders are created in this key's community.

RuleBearer <API_KEY>

Body#

Send multipart/form-data with the file in field data. The first line must be a header row. Column names are not case-sensitive.

CSV
Username,Email,First Name,Last Name,Country,Join Server,Customer ID,Funded At,Challenge Revenue
sample_trader,trader@example.com,Sample,Trader,Singapore,true,<brokerCustomerId>,2026-09-18T15:50:45.414Z,1250.50

Required columns:

  • Username and Email.
  • Your community's broker customer ID field, if it has one, by its display name or key. It must be filled in and unique.
  • Any profile field your community makes compulsory: First Name, Last Name, Phone or Country.

Optional columns: First Name, Last Name, Phone, Country, Language, Role, Tag and Join Server. A missing column is read as empty.

  • Username: 2 to 49 characters, letters, numbers, . and _, not starting or ending with . or _.
  • First Name and Last Name: up to 49 characters.
  • Phone: digits, optionally with a leading + and country code; spaces and dashes are allowed, letters are not.
  • Country: the country's full name, such as Singapore. Language: the language name, such as English.
  • Role and Tag: comma-separated. Each role must already exist in your community.
  • Join Server: true makes the trader a member of your community straight away. Any other value, or no column, adds them as invited; they become a member when they set their password or join.

Custom field columns:

  • Add a column for each custom field you want to fill, named by its display name or its key.
  • Values follow the bulk update rules: numbers such as 1250.50, true or false for yes/no fields, and ISO 8601 for date-time fields, such as 2026-09-18T15:50:45Z. A date-time can include milliseconds or an offset such as +08:00; without an offset it is read as UTC.
  • Number fields are written with overwrite. Add a <column>_op column with add or subtract to change that.
  • An empty cell is skipped. A row with any invalid custom value skips all of that trader's custom values, but the trader is still created.
  • Columns that are not a standard column or one of your custom fields are ignored.

Duplicates:

  • A row is skipped if its email, username or customer ID already belongs to a trader, or appears earlier in the same file. Emails are compared without case, so Trader@Example.com in your file matches an existing trader@example.com.
  • There is no row limit; the file can be up to 30 MB. Split a larger file and upload the parts one after another.
data#fileREQUIRED
The CSV file, with a header row and one row per new trader. The form field must be named data.

Rule.csv, max 30 MB

Eg"traders.csv"

Send the body as multipart/form-data.

curl --request POST \
  --url https://api.returning.ai/v1/users/bulk-import \
  --header 'Authorization: Bearer <API_KEY>' \
  --form 'data=@traders.csv'

Response#

A 200 returns only a confirmation that the import is queued. It has no job ID. Check a few traders with Get User Data, and follow the Bulk import custom fields job if your file had custom field columns.

status#stringALWAYS
Result of the request.

Rulesuccess

message#stringALWAYS
Human-readable summary. Do not branch on it.

Eg"Bulk import user process is queued"

data#objectALWAYS
A short confirmation.

Eg{ ... }

message#stringALWAYS
Human-readable confirmation that the import is queued.

Eg"Bulk import user process is queued. You can check in Api Log ( community settings )"

{
  "status": "success",
  "message": "Bulk import user process is queued",
  "data": {
    "message": "Bulk import user process is queued. You can check in Api Log ( community settings )"
  }
}

Errors#

Errors from the API key check, such as 401 and 403, carry the code in meta.code. Other errors from this endpoint have no code, so branch on the HTTP status. Problems inside the file never cause an error here; they show up on the import in API Logs and in its row file.

Fix the request03

400Fix the request
No file arrived, or it is not a CSV. Send the file as multipart form field data, with a .csv name or a text/csv type.
401AUTHENTICATION_REQUIREDFix the request
The key is missing, invalid or expired, or you sent a login token. Send Authorization: Bearer <API_KEY> with a current community API key.
403API_KEY_PERMISSION_DENIEDFix the request
The key is valid but has neither bulkImportUser nor bulkUpdateUser. Add Bulk Import Users in Settings > Integration > API Keys.

Fix the data01

404COMMUNITY_NOT_FOUNDFix the data
The key's community no longer exists. Use a key from an active community.

Retry with backoff02

500Retry with backoff
A JSON 500 means the import was not queued; retry with backoff. A 500 error page without JSON means the file is over 30 MB or was sent under a form field other than data; split the file or fix the upload instead.
500AUTHENTICATION_FAILEDRetry with backoff
The key could not be checked. Retry the same request with backoff.

Retries

This endpoint is not idempotent, and it ignores an Idempotency-Key header, but uploading the same file again is safe: traders created the first time are rejected as already existing, and their custom fields are not written again. Rows that failed the first time are imported if you fix them. Over the rate limit, requests return 429; wait for the window to reset, then retry.

{
  "status": "fail",
  "message": "Uploaded file must be a CSV"
}

Next step#

Get User DataPOST/v1/users/infoLook up a few of the traders by email to confirm they were created.