Usa una clave API con permisos limitados para una cuenta autorizada. Las órdenes son sintéticas y los pagos elegibles se rigen por el acuerdo.
Ir al quickstartREST / v1curl https://api.tryferm.com/v1/agent/accounts \
-H "Authorization: Bearer $FERM_AGENT_KEY"
https://api.tryferm.comAprobar permite solicitar una cuenta financiada simulada, sujeta a revisión, verificación y acuerdo. No es una cuenta de corretaje.
From any page, abrir tu profile menu y choose API keys. Pick read-only o trading scopes y grant the key exactly the cuentas it may touch.
Point tu bot at our REST API a read state y place órdenes, then reconcile con the ordered event feed. Revoke access anytime.
Six steps desde a fresh cuenta a a bot placing órdenes. Every sample es copy-paste ready en curl, Python, o JavaScript. Pick a language once y the whole page follows.
Agente keys attach a real Ferm cuentas, so tú need at least one cuenta primer. Any cuenta en an evaluación (active), o already financiado (funded / live), puede operar through the API. Tú puede develop tu bot against an evaluación cuenta y let it earn the financiado one.
Log en en the web, abrir tu profile menu (top right) y choose API keys, then Mint a key. Tú va a pick four things:
account:read a read, order:write a operar. Empezar read-only if tú son still testing.The completo key es displayed once. Store it en an environment variable o a secrets manager, never en código o version control. Lost keys cannot be recovered, only replaced.
# The full key is shown exactly once, at creation. Copy it then.
# Anatomy: frm_agent_<key id: 16 hex>_<secret: 64 hex>
export FERM_AGENT_KEY="frm_agent_1a2b3c4d5e6f7a8b_<64-hex-secret>"
List the cuentas tu key fue granted. If this returns tu cuenta, auth, scopes, y grants son all wired up correctly.
curl https://api.tryferm.com/v1/agent/accounts \
-H "Authorization: Bearer $FERM_AGENT_KEY"
{
"status": true,
"data": {
"accounts": [
{
"id": "1f0c9c7e-8f4b-4c6e-9d2a-7b1e3a5c9d10",
"status": "funded",
"balanceCents": 10000000,
"profitShareBps": 9000,
"createdAt": "2026-06-02T15:04:05.000Z"
}
]
}
}
import os, requests
API = "https://api.tryferm.com"
HEADERS = {"Authorization": f"Bearer {os.environ['FERM_AGENT_KEY']}"}
res = requests.get(f"{API}/v1/agent/accounts", headers=HEADERS)
print(res.json())
{
"status": true,
"data": {
"accounts": [
{
"id": "1f0c9c7e-8f4b-4c6e-9d2a-7b1e3a5c9d10",
"status": "funded",
"balanceCents": 10000000,
"profitShareBps": 9000,
"createdAt": "2026-06-02T15:04:05.000Z"
}
]
}
}
const API = "https://api.tryferm.com";
const HEADERS = { Authorization: `Bearer ${process.env.FERM_AGENT_KEY}` };
const res = await fetch(`${API}/v1/agent/accounts`, { headers: HEADERS });
console.log(await res.json());
{
"status": true,
"data": {
"accounts": [
{
"id": "1f0c9c7e-8f4b-4c6e-9d2a-7b1e3a5c9d10",
"status": "funded",
"balanceCents": 10000000,
"profitShareBps": 9000,
"createdAt": "2026-06-02T15:04:05.000Z"
}
]
}
}
10000000 es $100,000.00.401? Check the Authorization header made it through tu HTTP client. Getting an empty list? The key has sin cuenta grants yet.One call returns everything tu strategy needs a make a decision: equity, buying power, abrir posiciones con live mark prices, working límite órdenes, y how far the cuenta es desde each riesgo límite.
export ACCOUNT_ID="1f0c9c7e-8f4b-4c6e-9d2a-7b1e3a5c9d10"
curl https://api.tryferm.com/v1/agent/accounts/$ACCOUNT_ID/state \
-H "Authorization: Bearer $FERM_AGENT_KEY"
{
"status": true,
"data": {
"tradingState": {
"account": { "id": "1f0c9c7e-…", "status": "funded", "balanceCents": 10000000 },
"currentEquityCents": 10038200,
"buyingPowerCents": 9820000,
"positions": [
{
"id": "6c1d1b2e-4a3f-4f7e-8a9b-2c3d4e5f6a7b",
"symbol": "BTC",
"side": "buy",
"quantity": "0.05",
"entryPrice": 67210.5,
"markPrice": 67480.0,
"unrealizedPnlCents": 1348
}
],
"pendingOrders": [],
"riskThresholds": { "maxDrawdownCents": 800000, "dailyLossCents": 400000 },
"breached": false,
"progress": { "profitBps": 382, "targetBps": 1000 }
}
}
}
ACCOUNT_ID = "1f0c9c7e-8f4b-4c6e-9d2a-7b1e3a5c9d10"
res = requests.get(f"{API}/v1/agent/accounts/{ACCOUNT_ID}/state", headers=HEADERS)
print(res.json())
{
"status": true,
"data": {
"tradingState": {
"account": { "id": "1f0c9c7e-…", "status": "funded", "balanceCents": 10000000 },
"currentEquityCents": 10038200,
"buyingPowerCents": 9820000,
"positions": [
{
"id": "6c1d1b2e-4a3f-4f7e-8a9b-2c3d4e5f6a7b",
"symbol": "BTC",
"side": "buy",
"quantity": "0.05",
"entryPrice": 67210.5,
"markPrice": 67480.0,
"unrealizedPnlCents": 1348
}
],
"pendingOrders": [],
"riskThresholds": { "maxDrawdownCents": 800000, "dailyLossCents": 400000 },
"breached": false,
"progress": { "profitBps": 382, "targetBps": 1000 }
}
}
}
const ACCOUNT_ID = "1f0c9c7e-8f4b-4c6e-9d2a-7b1e3a5c9d10";
const res = await fetch(`${API}/v1/agent/accounts/${ACCOUNT_ID}/state`, { headers: HEADERS });
console.log(await res.json());
{
"status": true,
"data": {
"tradingState": {
"account": { "id": "1f0c9c7e-…", "status": "funded", "balanceCents": 10000000 },
"currentEquityCents": 10038200,
"buyingPowerCents": 9820000,
"positions": [
{
"id": "6c1d1b2e-4a3f-4f7e-8a9b-2c3d4e5f6a7b",
"symbol": "BTC",
"side": "buy",
"quantity": "0.05",
"entryPrice": 67210.5,
"markPrice": 67480.0,
"unrealizedPnlCents": 1348
}
],
"pendingOrders": [],
"riskThresholds": { "maxDrawdownCents": 800000, "dailyLossCents": 400000 },
"breached": false,
"progress": { "profitBps": 382, "targetBps": 1000 }
}
}
}
positions[].id es the id tú use a cerrar a posición o update its brackets; pendingOrders[].id es the id tú use a cancelar a working orden.riskThresholds and progress modalidad the same numbers that score tu evaluación. Use them a tamaño posiciones defensively.Generate a fresh UUID as clientOrderId, then send the orden. If tu connection drops mid-request, retry con the same UUID. Tú va a obtener the original result atrás, never a segundo fill.
curl -X POST https://api.tryferm.com/v1/agent/accounts/$ACCOUNT_ID/orders \
-H "Authorization: Bearer $FERM_AGENT_KEY" \
-H "Content-Type: application/json" \
-d '{
"clientOrderId": "8f2b7c1e-0d4a-4c9b-9a1e-1c2d3e4f5a6b",
"symbol": "BTC",
"side": "buy",
"volume": "0.05",
"orderType": "market",
"takeProfitPercent": 5,
"stopLossPercent": 3
}'
{
"status": true,
"data": {
"order": {
"status": "filled",
"fillPrice": 67480.0,
"position": {
"id": "6c1d1b2e-4a3f-4f7e-8a9b-2c3d4e5f6a7b",
"symbol": "BTC",
"side": "buy",
"quantity": "0.05"
}
}
}
}
import uuid
order = {
"clientOrderId": str(uuid.uuid4()), # retry with the same id - never double-fills
"symbol": "BTC",
"side": "buy",
"volume": "0.05",
"orderType": "market",
"takeProfitPercent": 5,
"stopLossPercent": 3,
}
res = requests.post(f"{API}/v1/agent/accounts/{ACCOUNT_ID}/orders",
headers=HEADERS, json=order)
print(res.json())
{
"status": true,
"data": {
"order": {
"status": "filled",
"fillPrice": 67480.0,
"position": {
"id": "6c1d1b2e-4a3f-4f7e-8a9b-2c3d4e5f6a7b",
"symbol": "BTC",
"side": "buy",
"quantity": "0.05"
}
}
}
}
const order = {
clientOrderId: crypto.randomUUID(), // retry with the same id - never double-fills
symbol: "BTC",
side: "buy",
volume: "0.05",
orderType: "market",
takeProfitPercent: 5,
stopLossPercent: 3,
};
const res = await fetch(`${API}/v1/agent/accounts/${ACCOUNT_ID}/orders`, {
method: "POST",
headers: { ...HEADERS, "Content-Type": "application/json" },
body: JSON.stringify(order),
});
console.log(await res.json());
{
"status": true,
"data": {
"order": {
"status": "filled",
"fillPrice": 67480.0,
"position": {
"id": "6c1d1b2e-4a3f-4f7e-8a9b-2c3d4e5f6a7b",
"symbol": "BTC",
"side": "buy",
"quantity": "0.05"
}
}
}
}
status: "filled" con the nuevo posición; límite órdenes return status: "pending" con the working orden.Fills, cancels, bracket hits, y breaches all land en an ordered event feed. Persist the last sequence tú processed y poll con sinceSequence. After a crash o disconnect tú replay exactly what tú missed.
# Fetch everything after the last sequence you processed
curl "https://api.tryferm.com/v1/agent/events?accountId=$ACCOUNT_ID&sinceSequence=10431&limit=100" \
-H "Authorization: Bearer $FERM_AGENT_KEY"
{
"status": true,
"data": {
"events": [
{
"eventId": "b1c2d3e4-5f6a-4b7c-8d9e-0f1a2b3c4d5e",
"sequence": 10432,
"type": "order_filled",
"occurredAt": "2026-07-12T08:14:22.101Z",
"accountId": "1f0c9c7e-8f4b-4c6e-9d2a-7b1e3a5c9d10",
"clientOrderId": "8f2b7c1e-0d4a-4c9b-9a1e-1c2d3e4f5a6b",
"data": { }
}
]
}
}
# Fetch everything after the last sequence you processed
params = {"accountId": ACCOUNT_ID, "sinceSequence": 10431, "limit": 100}
res = requests.get(f"{API}/v1/agent/events", headers=HEADERS, params=params)
print(res.json())
{
"status": true,
"data": {
"events": [
{
"eventId": "b1c2d3e4-5f6a-4b7c-8d9e-0f1a2b3c4d5e",
"sequence": 10432,
"type": "order_filled",
"occurredAt": "2026-07-12T08:14:22.101Z",
"accountId": "1f0c9c7e-8f4b-4c6e-9d2a-7b1e3a5c9d10",
"clientOrderId": "8f2b7c1e-0d4a-4c9b-9a1e-1c2d3e4f5a6b",
"data": { }
}
]
}
}
// Fetch everything after the last sequence you processed
const params = new URLSearchParams({
accountId: ACCOUNT_ID,
sinceSequence: "10431",
limit: "100",
});
const res = await fetch(`${API}/v1/agent/events?${params}`, { headers: HEADERS });
console.log(await res.json());
{
"status": true,
"data": {
"events": [
{
"eventId": "b1c2d3e4-5f6a-4b7c-8d9e-0f1a2b3c4d5e",
"sequence": 10432,
"type": "order_filled",
"occurredAt": "2026-07-12T08:14:22.101Z",
"accountId": "1f0c9c7e-8f4b-4c6e-9d2a-7b1e3a5c9d10",
"clientOrderId": "8f2b7c1e-0d4a-4c9b-9a1e-1c2d3e4f5a6b",
"data": { }
}
]
}
}
eventId before acting.One small Python file that proves the whole loop: it finds a granted cuenta, checks it es healthy, places one bracketed orden idempotently, then tails the event feed. Copiar it, export tu key, run it.
#!/usr/bin/env python3
"""Ferm starter bot: reads state, places one bracketed order, tails events.
Run it: export FERM_AGENT_KEY="frm_agent_..." && python3 bot.py
Needs: pip install requests
"""
import os, time, uuid, requests
API = "https://api.tryferm.com"
HEADERS = {"Authorization": f"Bearer {os.environ['FERM_AGENT_KEY']}"}
def get(path, **params):
res = requests.get(f"{API}{path}", headers=HEADERS, params=params, timeout=10)
res.raise_for_status()
return res.json()["data"]
# 1. Find an account this key can trade
account = get("/v1/agent/accounts")["accounts"][0]
account_id = account["id"]
print(f"trading account {account_id} ({account['status']})")
# 2. Look before you leap: never trade a breached account
state = get(f"/v1/agent/accounts/{account_id}/state")["tradingState"]
if state["breached"]:
raise SystemExit("account is breached - read-only until further notice")
print(f"equity ${state['currentEquityCents'] / 100:,.2f}")
# 3. Place one small bracketed market order, idempotently
order = {
"clientOrderId": str(uuid.uuid4()), # reuse on retry: never double-fills
"symbol": "BTC",
"side": "buy",
"volume": "0.01",
"orderType": "market",
"takeProfitPercent": 5,
"stopLossPercent": 3,
}
res = requests.post(f"{API}/v1/agent/accounts/{account_id}/orders",
headers=HEADERS, json=order, timeout=10)
res.raise_for_status()
print("order:", res.json()["data"]["order"]["status"])
# 4. Tail the event feed - real bots persist `since` across restarts
since, seen = 0, set()
while True:
feed = get("/v1/agent/events", accountId=account_id,
sinceSequence=since, limit=100)
for event in feed["events"]:
since = event["sequence"]
if event["eventId"] in seen:
continue # delivery is at-least-once - dedupe by eventId
seen.add(event["eventId"])
print(f"[{event['sequence']}] {event['type']}")
time.sleep(2)
requests. Sin SDK, sin framework. The whole API fits en plain HTTP.sinceSequence somewhere durable so a restart replays exactly the events they missed.Everything above gets tú trading; everything below es what tú come atrás para: exact fields, exact errors, exact límites.
Every request carries a bearer token. Agente endpoints son header-only: they never read tu browser session, so they sit entirely outside cookie y CSRF machinery.
# format: frm_agent_<key id>_<secret>
#
# key id 16 hex chars - identifies the key; visible in your dashboard
# secret 64 hex chars - stored only as a hash; revealed exactly once
frm_agent_1a2b3c4d5e6f7a8b_9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b
curl https://api.tryferm.com/v1/agent/accounts \
-H "Authorization: Bearer frm_agent_<keyId>_<secret>"
401 unauthorized; wrong o unknown token → 401 invalid_api_key; revoked → 401 api_key_revoked; expired → 401 api_key_expired.| Scope | Unlocks | Description |
|---|---|---|
account:read | All read endpoints | Read cuenta state, posiciones, operar historial, y the event feed. |
order:write | All trading endpoints | Place y cancelar órdenes, cerrar posiciones, y adjust brackets. |
stream:subscribe | Coming soon | Reserved para the low-latency WebSocket event stream. Selectable soon; no yet active. |
Keys son default-deny: a key puede only see y operar the cuentas tú explicitly grant it.
404 account_not_found. The API never confirms whether an cuenta exists a a key that cannot access it.Base URL https://api.tryferm.com. All requests y responses son JSON; request bodies son capped at 100 KB; timestamps son ISO 8601 UTC.
| Método | Path & description | Scope |
|---|---|---|
| GET | /v1/agent/accountsList the cuentas this key has been granted. | account:read |
| GET | /v1/agent/accounts/:id/stateLive snapshot: balance, equity, buying power, abrir posiciones, working órdenes, riesgo thresholds, y evaluación progress. | account:read |
| GET | /v1/agent/accounts/:id/tradesPaginated closed-trade historial (límite 1,500, cursor). | account:read |
| GET | /v1/agent/eventsOrdered, replayable event feed (accountId, sinceSequence, límite). | account:read |
| POST | /v1/agent/accounts/:id/ordersPlace a mercado o límite orden con optional take-profit / stop-loss brackets. | order:write |
| DELETE | /v1/agent/accounts/:id/orders/:orderIdCancelar a working límite orden. :orderId comes desde state.pendingOrders[].id. | order:write |
| POST | /v1/agent/accounts/:id/positions/:tradeId/closeCerrar an abrir posición at mercado. :tradeId comes desde state.posiciones[].id. Optional body { "closePercent": 1,99 } closes only part de the posición. | order:write |
| PATCH | /v1/agent/accounts/:id/positions/:tradeId/bracketsUpdate take-profit / stop-loss en an abrir posición. | order:write |
POST /v1/agente/cuentas/:id/órdenes places a mercado o límite orden. The schema es strict: unknown fields son rechazado rather than ignored.
| Field | Tipo | Obligatorio | Notes |
|---|---|---|---|
clientOrderId | string (UUID) | Obligatorio | Tu idempotency token. Generate a fresh UUID per orden; retries con the same id return the original result instead de filling twice. |
symbol | string | Obligatorio | Instrument symbol, e.g. BTC, EURUSD, US500, XAUUSD. Common aliases (BTCUSD, SPY, GOLD) son normalized automatically. Unknown symbols return 400 unsupported_symbol. |
side | "buy" | "sell" | Obligatorio | Direction de the orden. |
volume | string (decimal) | Obligatorio | Quantity as a decimal string con up a 8 decimal places, e.g. "0.05". Checked against the instrument's min / max / step; out de range returns 400 invalid_order_size. |
orderType | "market" | "limit" | Opcional | Defaults a "mercado". |
limitPrice | string (decimal) | Límite only | Obligatorio when orderType es "límite"; no allowed en mercado órdenes. |
takeProfitPrice | string (decimal) | Opcional | Absolute take-profit precio. Use this o takeProfitPercent, no both. |
takeProfitPercent | integer 1–100 | Opcional | Take-profit as a percent distance desde entry. |
stopLossPrice | string (decimal) | Opcional | Absolute stop-loss precio. Use this o stopLossPercent, no both. |
stopLossPercent | integer 1–100 | Opcional | Stop-loss as a percent distance desde entry. |
Tradable instruments span crypto (BTC, ETH, SOL, …), 25+ FX pairs (EURUSD, GBPJPY, …), y index / commodity CFDs (US500, NAS100, XAUUSD, USOIL, …). See the completo list en the mercados page.
Before an orden reaches the matching engine it debe clear the same rails as a manual operar: the cuenta debe be en a tradable state (active, funded, o live, otherwise 409 account_not_tradable), have sin retiro en flight (409 trading_withdrawal_pending), y pass sizing, margin, y riesgo checks en the engine itself.
clientOrderId es tu safety net para retries. What happens when the same UUID es sent twice:
| Existente state | Result de the retry |
|---|---|
| Same clientOrderId, posición already abrir | 200: returns the existente posición. Sin segundo fill. |
| Same clientOrderId, límite orden still working | 200: returns the existente pendiente orden. |
| Same clientOrderId, orden already cerrado o cancelled | 400: "client orden id has already been used". Generate a nuevo UUID. |
Cancelar, cerrar, y bracket updates address server-side ids, so read them desde the state endpoint primer. These calls son no idempotent; check state before retrying.
# Cancel a working limit order - id from state.pendingOrders[].id
curl -X DELETE https://api.tryferm.com/v1/agent/accounts/$ACCOUNT_ID/orders/$ORDER_ID \
-H "Authorization: Bearer $FERM_AGENT_KEY"
# Close an open position at market - id from state.positions[].id
# Add -d '{ "closePercent": 50 }' (with Content-Type: application/json) for a partial close
curl -X POST https://api.tryferm.com/v1/agent/accounts/$ACCOUNT_ID/positions/$TRADE_ID/close \
-H "Authorization: Bearer $FERM_AGENT_KEY"
# Move the stop to break-even on an open position
curl -X PATCH https://api.tryferm.com/v1/agent/accounts/$ACCOUNT_ID/positions/$TRADE_ID/brackets \
-H "Authorization: Bearer $FERM_AGENT_KEY" \
-H "Content-Type: application/json" \
-d '{ "stopLossPrice": "67210.50" }'
# Cancel a working limit order - id from state.pendingOrders[].id
requests.delete(f"{API}/v1/agent/accounts/{ACCOUNT_ID}/orders/{order_id}",
headers=HEADERS)
# Close an open position at market - id from state.positions[].id
requests.post(f"{API}/v1/agent/accounts/{ACCOUNT_ID}/positions/{trade_id}/close",
headers=HEADERS)
# Move the stop to break-even on an open position
requests.patch(f"{API}/v1/agent/accounts/{ACCOUNT_ID}/positions/{trade_id}/brackets",
headers=HEADERS, json={"stopLossPrice": "67210.50"})
// Cancel a working limit order - id from state.pendingOrders[].id
await fetch(`${API}/v1/agent/accounts/${ACCOUNT_ID}/orders/${orderId}`, {
method: "DELETE",
headers: HEADERS,
});
// Close an open position at market - id from state.positions[].id
await fetch(`${API}/v1/agent/accounts/${ACCOUNT_ID}/positions/${tradeId}/close`, {
method: "POST",
headers: HEADERS,
});
// Move the stop to break-even on an open position
await fetch(`${API}/v1/agent/accounts/${ACCOUNT_ID}/positions/${tradeId}/brackets`, {
method: "PATCH",
headers: { ...HEADERS, "Content-Type": "application/json" },
body: JSON.stringify({ stopLossPrice: "67210.50" }),
});
takeProfitPrice / stopLossPrice (decimal strings) o takeProfitPercent / stopLossPercent (integers 1,100). All fields son optional; send only what tú want a change.GET /v1/agente/events es an ordered, replayable log de everything that happens en an cuenta. It es the source de truth tu bot reconciles against.
| Query param | Tipo | Notes |
|---|---|---|
accountId | UUID, obligatorio | The granted cuenta a read events para. |
sinceSequence | integer, default 0 | Returns events con sequence strictly greater than this value. |
limit | 1,500, default 100 | Máximo events per response. |
| Tipo | Fires when |
|---|---|
order_accepted | A límite orden fue accepted y es working. |
order_filled | A mercado orden filled, o a working límite orden executed. |
order_cancelled | A working orden fue cancelled. |
position_closed | An abrir posición fue fully cerrado. |
position_partially_closed | Part de a posición fue cerrado. |
position_brackets_updated | Take-profit / stop-loss en a posición changed. |
account_breached | The cuenta hit a riesgo límite; trading es now blocked. |
evaluation_passed | The evaluación beneficio target fue reached. |
phase_advanced | The cuenta moved a its siguiente phase. |
sequence es monotonic per cuenta. A gap means tú have more a fetch, never that something fue skipped.eventId.clientOrderId, so tú puede match fills a requests exactly.Every response es wrapped en the same envelope, so a single check en estado tells tú whether data o error es present.
{
"status": true,
"data": { }
}
{
"status": false,
"error": {
"code": "insufficient_scope",
"message": "This API key does not have the order:write scope"
}
}
| HTTP | Código | Meaning |
|---|---|---|
| 401 | unauthorized | Sin Authorization header fue sent. |
| 401 | invalid_api_key | Malformed token, unknown key id, o wrong secret. |
| 401 | api_key_revoked | The key fue revoked desde the panel. |
| 401 | api_key_expired | The key es past its expiry date. |
| 403 | insufficient_scope | The key lacks the scope this endpoint requires. |
| 404 | account_not_found | The cuenta does no exist o es no granted a this key. |
| 400 | validation_failed | The body failed validation; error.details lists each bad field. |
| 400 | unsupported_symbol | The symbol es no en the instrument catalog. |
| 400 | invalid_order_size | Volume es outside the instrument's min / max / step. |
| 409 | account_not_tradable | The cuenta es breached, cerrado, o otherwise no en a tradable state. |
| 409 | trading_withdrawal_pending | A pendiente retiro blocks nuevo órdenes until it settles. |
| 429 | rate_limit_exceeded | Too many requests; atrás off y retry. |
| 502 | trading_engine_error | The trading engine returned an unexpected error. Safe a retry reads. |
| 503 | trading_engine_unavailable | The trading engine es unreachable. Retry con backoff. |
Validation failures include an error.details array naming each offending field. Errors surfaced desde inside the trading engine (para example "insufficient buying power") return a human-readable error.message without a machine código.
Límites son generous para polling architectures: a bot reading state once per segundo uses a tenth de its budget.
| Límite | Keyed by | Applies a |
|---|---|---|
| 600 requests / minute | Per API key | All read endpoints |
| 600 requests / minute | Per API key | All orden endpoints |
| 30 failed auths / 10 minutes | Per IP | Requests con bad credentials |
RateLimit-* headers so clients puede pace themselves before hitting 429.429 rate_limit_exceeded, atrás off y retry. Reads son always safe a retry, y órdenes son safe a retry con the same clientOrderId.Automated trading debe never mean handing over the keys a everything. Every control below es en desde the primer request.
Every key es limited a the scopes tú pick (read-only, trading, o both) y only the cuentas tú explicitly grant it.
Kill a key instantly desde the panel. In-flight requests stop the moment it es revoked; sin session lingers.
Agente órdenes run through the identical sizing, account-status, y riesgo checks as the web terminal. Sin shortcuts.
If an cuenta breaches its riesgo límites, trading scopes stop working automatically while reads keep flowing para reconciliation.
Every orden carries a clientOrderId tú generate, so a retried request after a dropped connection never double-fills.
Secrets son shown once at creation y stored only as a hash. Nosotros literally cannot recover a lost key; tú rotate it.
Use de the Agente API es authorized programmatic access under Section 6.2 de the Terms y Conditions. Everything tu keys do es attributed a tu cuenta, y the Acceptable Use Policy y all trading reglas apply exactly as they do a manual trading.
Consigue financiación, genera una clave y quédate hasta el 90% de lo que gane tu estrategia.