Skip to main content

POST Create Member

Create a managed CrossTrade account for a new email address, open its funded seat and issue a private Connect link. Billing starts when the seat opens, even if the member does not finish Connect. An email already attached to a CrossTrade account returns 409 email_in_use.

Endpoint​

POST https://app.crosstrade.io/v1/api/partner/users

Headers​

NameRequiredValue
AuthorizationYesBearer <partner access token> with partner:provision
Content-TypeYesapplication/json (UTF-8)
Idempotency-KeyYesUnique per logical request; 1–200 printable ASCII characters without spaces

No path or query parameters. The JSON body may be at most 64 KiB; unknown fields are rejected.

Body parameters​

NameTypeRequiredDescription
external_idstringYesYour permanent member id: 1–64 ASCII letters, digits, periods, underscores or hyphens
emailstringYesNew CrossTrade email address; trimmed and lowercased
namestringNoDisplay name, 1–120 characters when supplied
environmentsarray of stringNoNonempty, unique demo and/or live values within your partner profile. Defaults to that profile
metadataobjectNoYour metadata, at most 1,024 serialized bytes
authorizationobjectYesConsent request using the fields below

Authorization fields​

NameTypeRequiredDescription
scopestringNoSpace-separated member scopes; defaults to your client's member-scope ceiling
redirect_uristringYesExact registered HTTPS URI, including for pickup delivery
code_challengestringYesSHA-256 PKCE challenge, base64url without padding (43 characters)
code_challenge_methodstringNoS256 only; the default when omitted
statestringFor redirectRandom correlation value; nonempty for redirect delivery, at most 256 characters
deliverystringNoredirect or pickup. Defaults to your API client's code-delivery setting (redirect until changed)
resourcesarray of stringNoExact absolute Trading and/or Management resource URLs to narrow audiences

See Partner Authentication for scopes and audiences. A request for tv:read manage:read, as below, asks for read access to both member APIs.

Code examples​

Set PARTNER_TOKEN, XT_MEMBER_EMAIL, XT_REDIRECT_URI, CODE_CHALLENGE, OAUTH_STATE and IDEMPOTENCY_KEY. Generate a fresh PKCE pair and retain its verifier, the request body and the key before sending. Retries must reuse those values.

import os
import requests

body = {
"external_id": "th_8831",
"email": os.environ["XT_MEMBER_EMAIL"],
"name": "Jamie Rivera",
"environments": ["demo"],
"authorization": {
"scope": "tv:read manage:read",
"redirect_uri": os.environ["XT_REDIRECT_URI"],
"code_challenge": os.environ["CODE_CHALLENGE"],
"code_challenge_method": "S256",
"state": os.environ["OAUTH_STATE"],
"delivery": "pickup",
},
}
response = requests.post(
"https://app.crosstrade.io/v1/api/partner/users",
headers={
"Authorization": f"Bearer {os.environ['PARTNER_TOKEN']}",
"Idempotency-Key": os.environ["IDEMPOTENCY_KEY"],
},
json=body,
timeout=30,
)
response.raise_for_status()
result = response.json()
connect = result["connect"] # May be None for an existing member or an expired replay.
print(response.status_code, result["member"]["status"])
# If connect is present, deliver connect["url"] privately to this member.

Responses​

201 Created​

A new seat and Connect link, with ETag: "v1". The link expires in 10 minutes. Keep flow_id with the PKCE verifier for code pickup and exchange.

{
"success": true,
"member": {
"external_id": "th_8831",
"uid": "k3Qz9pLa",
"email": "member@example.com",
"name": "Jamie Rivera",
"status": "provisioned",
"ownership_verified": false,
"version": 1,
"environments": [
"demo"
],
"metadata": {},
"seat": {
"started": "2026-10-15T14:02:11Z",
"ended": null
},
"created": "2026-10-15T14:02:11Z",
"authorization": {
"status": "pending",
"flow_id": "pcf_a1b2c3d4e5f6",
"purpose": "authorize",
"generation": 1
},
"grant": null
},
"connect": {
"flow_id": "pcf_a1b2c3d4e5f6",
"purpose": "authorize",
"url": "https://app.crosstrade.io/v1/connect/xt_tk_...",
"expires": "2026-10-15T14:12:11Z"
},
"meta": {
"requestId": "preq_7d8f159d49d107bb",
"etag": "\"v1\""
}
}

Existing member and replay​

The same external_id with the same email and name returns 200, the current member and connect: null. Use POST Create Connect Link for fresh consent, or POST Reopen Member if revoked.

Reusing the original idempotency key replays the recorded status and member snapshot with Idempotent-Replayed: true for 24 hours. Once the original link expires, replay returns connect: null; replay does not extend the link lifetime.

Errors​

StatusErrorMeaning
400validation_failedInvalid body, authorization fields or missing idempotency key
401unauthorizedInvalid partner token
403insufficient_scope, partner_not_enabled, partner_past_due, partner_suspended, partner_disabled, partner_not_activeScope or service policy blocks new seats
409email_in_use, email_ambiguousEmail already belongs to a CrossTrade account, or matches multiple accounts
409external_id_conflictThat id has a different email or name
409partner_tag_required, seat_cap_reachedSet your business name, or resolve your seat limit
409idempotency_conflict, idempotency_in_progress, idempotency_key_expiredSee replay rules
413 / 415validation_failedBody too large or unsupported content type/encoding
429rate_limited, too_many_concurrent_requestsHonor Retry-After
503outcome_unknownThe database result could not be confirmed; retain and retry the same request and key

See Partner errors for common availability errors and response shapes.