Update a trading account
Update an existing trading account. This is the endpoint for reflecting anything that happens on your side — payouts, manual passes, balance corrections, risk decisions — onto the account. Only organization admins (or API keys with write/admin permission) can update accounts.
Allowed fields:
| Field | Description |
|---|---|
status | Account status: not_started, in_progress, passed, failed, expired |
initialBalance | Starting balance |
currentBalance | Current balance |
highWaterMark | Highest balance achieved |
customerId | Reassign the account to a different customer of yours (resale, correction). Look accounts up later with GET /trading-accounts?customerId=.... Cannot be cleared, and on linked accounts the new customer must not be soulbound to a different Hyperprop login (409 CUSTOMER_ALREADY_BOUND) |
metadata | Custom JSON — notes, tags, payout records, anything you need (see merge semantics below) |
mergeMetadata | true = merge the provided keys into existing metadata. Omitted/false = replace metadata wholesale |
reason | Why you made the change — stored in the audit trail and included in webhook events |
Metadata: replace vs merge
By default, metadata replaces the stored object entirely. Send "mergeMetadata": true to update only the keys you pass and preserve the rest:
// Stored: { "tier": "gold", "notes": "VIP" }
// Request: { "metadata": { "notes": "VIP - churned" }, "mergeMetadata": true }
// Result: { "tier": "gold", "notes": "VIP - churned" }
The merge is shallow (top-level keys only). Nested objects and arrays are replaced as a whole — so to append to an array (e.g. a payouts list), first read the current metadata via GET /trading-accounts/{accountId}, append your entry, and send the full array back with mergeMetadata: true. Metadata is opaque to Hyperprop: we store and return it verbatim, but never compute on it.
Recipe — record a payout / balance withdrawal:
Hyperprop has no built-in payout ledger — payouts stay in your system. The pattern below reflects the withdrawal on the balance and keeps an auditable record on the account:
curl -X PATCH "https://api.example.com/platform/v1/organization/trading-accounts/{accountId}" \
-H "X-API-Key: hp_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"currentBalance": 48000,
"reason": "Payout PO-1042 - 2000 USD withdrawal",
"mergeMetadata": true,
"metadata": {
"payouts": [
{ "id": "PO-1042", "type": "balance_withdrawal", "amount": 2000, "currency": "USD", "date": "2026-07-08", "status": "paid" }
],
"totalPaidOut": 2000
}
}'
The same pattern works for any custom workflow (e.g. recording a drawdown-lock decision under a metadata.mll key): make the risk decision in your system, then persist the resulting balance/status here plus a metadata record of why.
Example — manually pass an account:
curl -X PATCH "https://api.example.com/platform/v1/organization/trading-accounts/{accountId}" \
-H "X-API-Key: hp_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"status": "passed", "reason": "Trader hit target during feed outage", "mergeMetadata": true, "metadata": {"manualPass": true}}'
Example — balance correction:
curl -X PATCH "https://api.example.com/platform/v1/organization/trading-accounts/{accountId}" \
-H "X-API-Key: hp_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"currentBalance": 52500, "highWaterMark": 52500, "reason": "Balance adjustment for data feed error"}'
Status change side effects:
passed,failed, orexpiredautomatically setscompletedAt(and may end the trader’s market-data entitlement)not_startedclearsstartedAt,completedAt, andviolationReason(full reset)
Audit trail & webhooks:
Every change is logged with before/after values and who made it — inspect via GET /trading-accounts/{accountId}/changes or the org-wide GET /audit-log. Changes made with an API key are attributed to that key (adminEmail: "api-key", with the key’s ID recorded); session changes are attributed to the admin’s email. Changes also emit webhook events to your configured endpoints: account.status_changed (plus account.passed/account.failed convenience events) for status changes, and account.updated for balance/metadata changes — each carrying your reason and the previous values.
Error responses:
Every error returns { statusCode, error, message, code } — switch on code:
| Status | code | When |
|---|---|---|
| 400 | VALIDATION_ERROR | Payload failed validation (empty payload, invalid status value, wrong types) |
| 400 | NO_FIELDS_TO_UPDATE | No updatable field was provided |
| 401 | UNAUTHORIZED | Missing/invalid API key or session |
| 403 | INSUFFICIENT_PERMISSIONS / NOT_ADMIN | Key or user lacks admin/write permission |
| 403 | ACCOUNT_NOT_IN_ORG | The account belongs to a different organization |
| 404 | ACCOUNT_NOT_FOUND | No account with this ID |
| 500 | UPDATE_ACCOUNT_ERROR | Unexpected server error |
Authorizations
JWT Bearer token for user session auth. Format: "Bearer {token}". Used by User and Organization endpoints.
Path Parameters
The trading account ID
Body
Custom metadata. Replaces existing metadata wholesale unless mergeMetadata is true.
When true, the provided metadata keys are merged into the existing metadata instead of replacing it entirely
true
Account status
not_started, in_progress, passed, failed, expired "passed"
Initial account balance
100000
Current account balance
105000
Highest balance achieved
107500
Reassign the account to a different customer of yours (resale, correction). Cannot be cleared — every account always has a customerId. On linked accounts the new customerId must not be bound to a different Hyperprop login (409 CUSTOMER_ALREADY_BOUND).
255"mffu-cust-4471"
DEPRECATED alias for customerId — use customerId instead. Null is ignored (customerId cannot be cleared).
255"mffu-cust-4471"
Reason for the change (logged in audit trail)
"Balance adjustment for data feed error"
Related topics
Bulk update trading accountsMCP connector (AI agents)Update a trading ruleUpdate a trading planCreate or update a copy trading config