Skip to content

Traders

Profiles Rubi matches to interviews. id is your stable customer id. Rubi never invents a second id for the same person.

Paths are relative to your base URL
Rubi joins the base URL saved under Integrations with the path on this page. Save https://risk.example-firm.com/rubi/v1 with no trailing slash. GET /traders is then requested as https://risk.example-firm.com/rubi/v1/traders.

Shared rules for authentication, pagination, errors and the live check are on the Own tech overview.

Every call, including GET /health, sends Authorization: Bearer <api key> and Accept: application/json. The key is the secret you paste in the dashboard. Rubi never sends a body: every endpoint is GET.

GET/traders

Returns { data, next_cursor }

Paginated list. Rubi calls this with limit=5 during the live check and limit=200 during sync.

QueryRequiredRules
updated_sincenoRFC 3339. Return rows with updated_at greater than or equal to this instant. Omitted on the first backfill.
cursornoThe next_cursor from the previous page. Ignore it when absent.
limitno1 to 500. Rubi sends 200 in production syncs.

Each object in data:

FieldTypeDescription
idstringRequired, stable, unique. Numbers are accepted and stored as strings. The live check fails if this is missing or null.
updated_attimestampRequired. RFC 3339 UTC. Drives incremental sync and cursor order.
emailstring | nullUsed to match an interview created with the same email.
first_name, last_namestring | nullPreferred name fields.
full_namestring | nullAccepted instead of first and last name. Rubi splits on the first space.
countrystring | nullISO 3166-1 alpha-2, for example GB.
phonestring | nullE.164 when you have it.
registered_attimestamp | nullWhen the trader opened an account with you. created_at is accepted as an alias.
kyc_statusenum | nullOne of not_started, pending, verified, failed.
tagsstring[]Free labels. Omit or send an empty array when you have none.
metadataobject | nullStored as-is on the trader. Do not put secrets here.
200 response
{
  "data": [
    {
      "id": "cus_18422",
      "email": "jane@example.com",
      "first_name": "Jane",
      "last_name": "Doe",
      "country": "GB",
      "phone": "+447700900123",
      "registered_at": "2026-03-02T09:12:44Z",
      "kyc_status": "verified",
      "tags": ["vip"],
      "metadata": { "plan": "funded" },
      "updated_at": "2026-09-20T08:00:00Z"
    }
  ],
  "next_cursor": "eyJpZCI6ImN1c18xODQyMiJ9"
}
incremental page
curl "https://risk.example-firm.com/rubi/v1/traders?updated_since=2026-09-23T09:50:00Z&limit=200" \
  -H "Authorization: Bearer $PROVIDER_KEY" \
  -H "Accept: application/json"

GET/traders/{id}

Returns Trader

One trader, the same object as a list item, without the data envelope. Answer 404 with the error body when the id is unknown. Rubi uses the list endpoint for sync. Implement the detail endpoint so support and your own tools can fetch one customer the same way.

404
{ "error": { "code": "not_found", "message": "Unknown trader cus_18422" } }

What the live check asserts#

GET /traders?limit=1 without the bearer token must not return 200. Then GET /traders?limit=5 must return a list where every object has id and updated_at. If next_cursor is a non-empty string, the following request with that cursor must succeed.