Skip to main content

POST Revoke Member

End a member's funded seat and revoke your app's grant, member tokens and unfinished Connect flows. The account is released to the member, with its broker links and settings retained. Revocation does not flatten positions or cancel protective orders. App-owned copiers lose execution authority; protective monitors continue enforcing limits.

Endpoint​

POST https://app.crosstrade.io/v1/api/partner/users/{external_id}/revoke

Headers​

NameRequiredValue
AuthorizationYesBearer <partner access token> with partner:provision
Content-TypeYesapplication/json (UTF-8)

Neither Idempotency-Key nor If-Match is required. Repeated calls against a revoked member return the current state without ending another seat or incrementing the version again.

Path parameters​

NameTypeRequiredDescription
external_idstringYesMember id used at creation; 1–64 ASCII letters, digits, periods, underscores or hyphens

Body parameters​

NameTypeRequiredDescription
reasonstringYessubscription_canceled, payment_failed, member_request, partner_terminated, abuse or other

No query parameters. Unknown body fields are rejected; the maximum body size is 64 KiB.

Code examples​

Set PARTNER_TOKEN and replace th_8831 with your member id.

import json
import os
import requests

response = requests.post(
"https://app.crosstrade.io/v1/api/partner/users/th_8831/revoke",
headers={"Authorization": f"Bearer {os.environ['PARTNER_TOKEN']}"},
json={"reason": "subscription_canceled"},
timeout=30,
)
response.raise_for_status()
print("ETag:", response.headers.get("ETag"))
print(json.dumps(response.json(), indent=2))

Response​

200 OK, with ETag: "v2" in this example. already_revoked is false for the request that ends the seat, then true on repeats. An already exchanged authorization stays exchanged in the summary, while its grant becomes inactive.

{
"success": true,
"member": {
"external_id": "th_8831",
"uid": "k3Qz9pLa",
"email": "member@example.com",
"name": "Jamie Rivera",
"status": "revoked",
"ownership_verified": true,
"version": 2,
"environments": [
"demo"
],
"metadata": {},
"seat": {
"started": "2026-10-15T14:02:11Z",
"ended": "2026-11-02T09:30:00Z"
},
"created": "2026-10-15T14:02:11Z",
"authorization": {
"status": "exchanged",
"flow_id": "pcf_a1b2c3d4e5f6",
"purpose": "authorize",
"generation": 1
},
"grant": {
"version": 2,
"active": false
}
},
"already_revoked": false,
"meta": {
"requestId": "preq_6b5a4938271605f4",
"etag": "\"v2\""
}
}

The seat's final billable UTC day still counts if it had any positive billable overlap. See Billing and usage. To fund the member again, use POST Reopen Member with the current ETag and a fresh authorization request.

Errors​

StatusErrorMeaning
400validation_failedMissing or invalid reason, malformed path or unsupported query parameter
401unauthorizedInvalid partner token
403insufficient_scope, partner_not_enabled, partner_not_activeScope, platform enablement or provisioning state blocks the request
404member_not_foundUnknown member
413 / 415validation_failedBody too large or unsupported content type/encoding
429rate_limited, too_many_concurrent_requestsHonor Retry-After
503outcome_unknownThe commit result is uncertain; read the member state and retry revoke if needed

The service policy permits revoke while past due, suspended or disabled, provided authentication and platform enablement still allow the request. See Partner errors for common availability errors and response shapes.