Build a Copy-Trading SaaS
in 1 Hour.
From zero to your first signed webhook event hitting your endpoint — using CopyBridge as the copy-trading backend behind your product.
Get Integrator Access
Visit the developers page and click "Get Integrator Access". You'll go through Whop checkout (per-seat billing) — when complete, our webhook auto-provisions a parent provider for you and emails your X-Integrator-Key credential.
What you receive in your inbox:
- Your
X-Integrator-Key(shown ONCE — store it securely) - A quick-start curl example
- Link to the API reference + this tutorial
Create Your First Child Provider
Each of your customers becomes a "child provider" in CopyBridge. Provision them via API — they never need to visit copybridge.io. Start with is_sandbox: true so you can test without real broker execution.
curl -X POST https://api.copybridge.io/api/v1/integrator/providers \
-H "X-Integrator-Key: ${INTEGRATOR_KEY}" \
-H "Content-Type: application/json" \
-d '{
"name": "Trader Joe",
"email": "[email protected]",
"is_sandbox": true
}'Response (201 Created):
{
"provider": {
"id": "uuid-of-trader-joe",
"name": "Trader Joe",
"is_sandbox": true,
"parent_provider_id": "your-integrator-id"
},
"master_api_key": "uuid-master-key-shown-once",
"jwt_token": "eyJ..."
}The master_api_key + jwt_token are returned ONCE. Save them in your own database — you'll use them to interact with this child provider on your customer's behalf.
Receive Outbound Webhooks
When the child provider's trades fire (or when followers are added/removed), CopyBridge POSTs a Standard-Webhooks-signed event to YOUR endpoint. Verify the signature, then route the event in your own system.
Node (Express):
import { createHmac } from 'node:crypto';
function verifyCopyBridge(rawBody, headers, secret) {
const id = headers['webhook-id'];
const ts = headers['webhook-timestamp'];
const sig = (headers['webhook-signature'] || '').replace(/^v1,/, '');
const key = Buffer.from(secret.slice(6), 'base64'); // strip 'whsec_'
const expected = createHmac('sha256', key)
.update(`${id}.${ts}.${rawBody}`)
.digest('base64');
// Constant-time: a plain === leaks timing, and the Python example on this
// same page already uses hmac.compare_digest. timingSafeEqual throws on a
// length mismatch, so check that first.
const a = Buffer.from(sig), b = Buffer.from(expected);
return a.length === b.length && crypto.timingSafeEqual(a, b);
}Python (Flask):
import base64, hashlib, hmac
def verify_copybridge(raw_body: bytes, headers: dict, secret: str) -> bool:
eid = headers.get('webhook-id', '')
ts = headers.get('webhook-timestamp', '')
sig = headers.get('webhook-signature', '').replace('v1,', '')
key = base64.b64decode(secret[len('whsec_'):])
msg = f'{eid}.{ts}.{raw_body.decode("utf-8")}'.encode('utf-8')
expected = base64.b64encode(hmac.new(key, msg, hashlib.sha256).digest()).decode('ascii')
return hmac.compare_digest(sig, expected)Test with Sandbox Mode
The child provider you just created has is_sandbox: true — meaning trades flow through the system end-to-end but copier EAs SKIP placing real broker orders. Outbound webhooks carry an extra sandbox: true field so you can filter or route them differently in your code.
What you can verify in sandbox:
- API key creation, follower provisioning, key rotation
- Outbound webhook signing + delivery + replay
- Your end-to-end event processing pipeline
- Trade lifecycle UI (trade.opened, trade.closed events arrive normally)
What does NOT happen in sandbox: real broker orders. The copier EA logs [SANDBOX] Skipping OrderSend instead of calling OrderSend().
Going Live
When your integration is rock-solid in sandbox, toggle the child provider to live with a single API call. Note: CopyBridge refuses (HTTP 422) to enable sandbox mode if any attached follower's copier EA is below MIN_COPIER_VERSION — preventing the catastrophic case where an old EA processes a sandbox trade as real money.
curl -X PATCH https://api.copybridge.io/api/v1/integrator/providers/<child-id> \
-H "X-Integrator-Key: ${INTEGRATOR_KEY}" \
-H "Content-Type: application/json" \
-d '{"is_sandbox": false}'You're integration-ready.
That's the whole flow. Full API reference + code samples below.