Copy Trading API Integration Guide: From First Call to Production
Building copy trading into a product isn't complicated, but there are enough moving pieces — auth headers, webhook signatures, idempotency, live vs sandbox — that getting the first integration right saves days of debugging later. This guide walks through the CopyBridge copy trading API end-to-end: from your first authenticated request to a production-ready integration.
What Is a Copy Trading API and Why Integrate One
A copy trading API lets your platform receive or rebroadcast trade signals in real time, without forcing followers onto a specific broker. Instead of building WebSocket infrastructure, position-sizing logic, broker adapters, and failover yourself, you call an API that handles all of that.
Use cases that commonly integrate a copy trading API:
- SaaS trading platforms that want copy-trading as a feature without building the execution layer
- Signal providers automating delivery from their Master EA to subscribers at scale
- Prop firms distributing funded-account trades to evaluation accounts
- White-label resellers operating a branded copy service on top of shared infrastructure
CopyBridge exposes a REST API plus Standard Webhooks for outbound events. The developer landing page has the full endpoint reference, and the interactive API explorer lets you try calls in-browser before writing code.
Auth Model
Every request carries one of three headers depending on the caller role:
| Header | Role | Scope |
|---|---|---|
X-API-Key |
Signal provider (master) | Submit trades, manage provider config |
X-Subscriber-Key |
Follower / Copier EA | Poll for pending trades |
X-Integrator-Key |
White-label reseller | Provision child providers, billing |
Keys are generated in the dashboard and never expire until rotated. There is no OAuth flow — keep keys server-side and out of client bundles.
Outbound webhooks (events your server receives) use a separate signing secret, which starts with whsec_. Each delivery carries the three Standard Webhooks headers — webhook-id, webhook-timestamp and webhook-signature — and the signature covers all three joined together, not the body alone. Verify before processing; the exact construction is in the webhook section below.
Your First API Call
The core endpoint for a provider submitting a trade is POST /api/v1/trades. Here is a minimal curl example:
curl -X POST https://api.copybridge.io/api/v1/trades \
-H "Content-Type: application/json" \
-H "X-API-Key: <your-master-key-uuid>" \
-d '{
"action": "OPEN",
"symbol": "EURUSD",
"type": "BUY",
"lots": 0.10,
"price": 1.08542,
"sl": 1.08200,
"tp": 1.09100,
"magic": 42001,
"ticket": 98765
}'
action, symbol, type, lots, price and ticket are all required. action must be OPEN, CLOSE or MODIFY, and type must be BUY or SELL — both are matched case-sensitively, so "buy" is rejected.
A successful response returns HTTP 201 with the stored row: id, seq, action, symbol, type, lots, price, sl, tp, magic, ticket, timestamp, created_at and is_sandbox. id is the canonical reference for the trade; seq is the cursor followers poll against.
ticket is your broker's order ID, and CopyBridge deduplicates on the combination of provider, ticket and action — with no time window, so a resubmission is a no-op however long afterwards it arrives. A duplicate answers HTTP 200 with {"status": "duplicate"} rather than 201 and the row, so branch on the status code, not on the body shape.
For the close event:
curl -X POST https://api.copybridge.io/api/v1/trades \
-H "Content-Type: application/json" \
-H "X-API-Key: <your-master-key-uuid>" \
-d '{
"action": "CLOSE",
"ticket": 98765,
"symbol": "EURUSD",
"type": "BUY",
"lots": 0.10,
"price": 1.08890
}'
The full endpoint reference lives at /docs.
Webhook Handling
When a trade event occurs — opened, closed, copied to a follower, or rejected — CopyBridge sends an HTTP POST to your registered webhook URL. The payload follows the Standard Webhooks spec.
Signature Verification
Always verify signatures before acting on a delivery. Here is a Node.js helper:
import crypto from 'crypto';
/**
* Returns true if the webhook delivery is authentic.
*
* @param {string} rawBody - Raw request body string. Do not parse it first:
* re-serialising JSON reorders keys and the
* signature stops matching.
* @param {object} headers - The request headers.
* @param {string} secret - Signing secret from the dashboard, `whsec_...`.
*/
export function verifyWebhook(rawBody, headers, secret) {
const id = headers['webhook-id'];
const timestamp = headers['webhook-timestamp'];
const received = headers['webhook-signature']; // e.g. "v1,Base64Sig="
// The signed payload is the id, the timestamp and the body joined by dots —
// signing the body alone will never match.
const signedPayload = `${id}.${timestamp}.${rawBody}`;
// The secret is `whsec_` plus base64. Strip the prefix and decode: the key
// is those raw bytes, not the string you were given.
const key = Buffer.from(secret.slice(6), 'base64');
const expected = 'v1,' + crypto
.createHmac('sha256', key)
.update(signedPayload)
.digest('base64');
const a = Buffer.from(expected);
const b = Buffer.from(received || '');
// timingSafeEqual throws on a length mismatch, so check that first.
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
Reject anything older than about five minutes as well — comparing webhook-timestamp against your own clock is what stops a captured delivery being replayed.
In Express, mount express.raw({ type: 'application/json' }) on the webhook route before your JSON parser, and pass req.body as rawBody — express.raw() puts the Buffer there, and there is no req.rawBody unless you add a verify callback yourself. If the body has already been parsed and re-serialised, key order changes and the signature will never match.
Idempotency
Each delivery carries a webhook-id header. Store processed IDs and skip duplicates. The retry budget is small: 2 attempts total, roughly 500 ms apart, each timing out after 5 seconds. If both fail, the delivery is marked failed with no further automatic retry — recover it with POST /api/v1/providers/me/outbound-webhook/replay. Your endpoint should return 2xx within 5 seconds; CopyBridge won't wait longer than that per attempt.
Event types you will receive:
trade.opened— new trade submitted by the providertrade.closed— trade closedfollower.created— a new follower subscribed to the providerfollower.deactivated— a follower's subscription ended
Sandbox vs Live Mode
Sandbox mode runs the full API surface with synthetic execution — no real broker connections required. There is no separate set of test credentials: sandbox is a flag on the provider account itself, set by an integrator through the integrator API, so the same key works either way and you switch a provider between modes rather than switching keys.
In sandbox mode:
- Trade submissions are accepted and stored exactly as in production, with the same validation
- Sandbox trades are excluded from the follower feed, so no Copier EA ever sees them
- Webhook deliveries fire to your endpoint, carrying
sandbox: truein the payload - No trades touch any brokerage
There is no simulated execution and no synthetic fill. Nothing in the backend generates prices or models latency — sandbox trades are simply filtered out of every follower-facing query, which is why they never reach a broker.
Run your complete integration test suite against sandbox before touching a live key. The build-a-copy-trading-SaaS tutorial walks through a complete sandbox-to-production scenario with example code.
Going from Prototype to Production
A checklist before flipping to live keys:
Auth
-
X-API-Keystored in environment variable, not hardcoded - Webhook signing secret stored separately from the API key
- No keys exposed in client-side bundles or version control
Reliability
- Webhook handler returns 2xx within 10 s (offload slow work to a queue)
- Idempotency check on
webhook_idbefore processing - Signature verified on every inbound delivery
Correctness
-
ticketfield populated from your broker's order ID (not a random value) - Close events sent promptly — stale open trades confuse follower position sizing
-
lotsis the provider lot size; each follower's Copier EA scales it independently
Testing
- All happy-path and error-path scenarios exercised in sandbox
- Retry behavior tested by returning 500 from your webhook endpoint deliberately
Once you have checked everything, generate live keys in the dashboard, point your webhook URL at your production server, and swap the credential env vars. The developers page has a step-by-step deployment checklist and links to language-specific SDK examples.
What Comes Next
The API is intentionally minimal — it does one thing (replicate trades in real time across brokers) and exposes enough surface to integrate without locking you into proprietary abstractions. If you are building a white-label product on top of CopyBridge, the X-Integrator-Key auth tier gives you multi-tenant provider provisioning; see the white-label docs for details.
Questions, edge cases, or a bespoke integration? The developer docs include runnable examples in the interactive explorer, and the team is reachable at the link in the footer.