User accounts
A user is one of your customers, created by your organization through the API. Each user has a user_id and their own wallets. You send the user_id in the TM-On-Behalf-Of header for everything you do on their behalf.
Before you start, you need an organization token and the public half of your signer key. The code uses the post() and get() helpers from Getting started. Decide where that key lives first, because you can't change it after the user exists. Signer keys explains the choice.
Create the user
external_ref_id is your own id for the customer: up to 64 letters, digits, _ or -, matched case-sensitively. signer_public_key is the public half of your signer key: a compressed P-256 key, as 66 hex characters.
Store the user_id we return. Sending the same external_ref_id again returns the existing user with 200, so you can retry safely. The user keeps the signer key it was created with, even if the retry sends a different one.
Each organization can create a limited number of users. Past the limit you get a 422, and support can raise it for you.
Send the same request again. It finishes creating the wallets and returns the user. A user whose wallets array is empty is in this state.
- TypeScript
- Python
- curl
const user = await post(
`/v1/account/organizations/${organizationId}/users`,
{
external_ref_id: "cust_7781",
signer_public_key: signerPublicKey,
},
);
user = post(f"/v1/account/organizations/{organization_id}/users", {
"external_ref_id": "cust_7781",
"signer_public_key": signer_public_key,
})
curl -s -X POST https://api.truemarkets.co/v1/account/organizations/$ORGANIZATION_ID/users \
-H "Authorization: Bearer $ORG_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"external_ref_id": "cust_7781",
"signer_public_key": "'"$SIGNER_PUBLIC_KEY"'"
}'
{
"user_id": "9c1e7a52-4d3b-4f8e-a6b7-1c2d3e4f5a6b",
"external_ref_id": "cust_7781",
"created_at": "2026-09-28T17:02:11Z",
"wallets": [
{ "address": "7Gk2…Qm9p", "chain_family": "solana" },
{ "address": "0x4a8f…c21e", "chain_family": "evm" }
]
}
What to store
| Field | Why |
|---|---|
user_id | goes in TM-On-Behalf-Of on every call for this customer |
wallets[].address | where you fund them. Each wallet has a chain_family: the solana wallet takes Solana tokens, and the evm wallet has one address that works on every EVM chain we support |
Admins are not users
Admins are the people on your team who sign in to the developer console. Users are your customers, and they never sign in to True Markets. If the external_ref_id is already in use in your organization, for example by one of your admins' records, we return 409.
List and read users
List returns your users newest first, 50 per page by default and up to 100 with limit. Page with the cursor from pagination.next_cursor.
Pass external_ref_id to look up a user by your own id. An id that matches nothing returns an empty page. Read one user by user_id to get their wallet addresses again.
- TypeScript
- Python
- curl
const page = await get(
`/v1/account/organizations/${organizationId}/users?external_ref_id=cust_7781`,
);
page = get(
f"/v1/account/organizations/{organization_id}/users?external_ref_id=cust_7781",
)
curl -s -G https://api.truemarkets.co/v1/account/organizations/$ORGANIZATION_ID/users \
-H "Authorization: Bearer $ORG_TOKEN" \
-d external_ref_id=cust_7781
{
"data": [
{
"user_id": "9c1e7a52-4d3b-4f8e-a6b7-1c2d3e4f5a6b",
"external_ref_id": "cust_7781",
"created_at": "2026-09-28T17:02:11Z",
"wallets": ["…"]
}
],
"pagination": { "next_cursor": null, "limit": 50 }
}
- TypeScript
- Python
- curl
const user = await get(
`/v1/account/organizations/${organizationId}/users/${userId}`,
);
user = get(
f"/v1/account/organizations/{organization_id}/users/{user_id}",
)
curl -s https://api.truemarkets.co/v1/account/organizations/$ORGANIZATION_ID/users/$USER_ID \
-H "Authorization: Bearer $ORG_TOKEN"
Next: Funding