PipSync
Connect Claude or ChatGPT to your live trading account — check quotes and positions, and place, modify or close trades with a two-step confirm (trading scope only, never withdrawals).
Documentation
Home›Developers›API Reference
v1 API · OpenAPI 3.1 · signed webhooks
An API built for traders who code.
REST where it makes sense, signed webhooks where events need to reach your systems. OpenAPI 3.1 spec, verifiable signatures, and copy-paste examples for every hot endpoint.
Interactive PlaygroundDownload OpenAPI spec
Getting started
QuickstartAuthenticationObtaining an API keyKey scopesKey security
Rate limits
Limits by tierResponse headersExponential backoff
Errors
Error codes
Endpoints
GET/v1/meGET/v1/signalsGET/v1/tradesGET/v1/reports
Webhooks
Realtime SSE streamEvent catalogueVerifying signatures
OpenAPI clients
Code generatorsInteractive Playground ↗
Quickstart
Store your key, call /v1/me to verify auth, then start reading signals or trades. Five minutes from zero to first API response.
cURLNode.jsPython
curl https://app.pipsync.io/api/v1/me
-H "Authorization: Bearer $PIPSYNC_KEY"
Every response is wrapped in { "data": … }. Paginated endpoints additionally return a "meta" object with total, page, totalPages, and hasMore.
Authentication
All API requests require a bearer token in the Authorization header. Keys are per-environment (live / sandbox), per-scope, and time-limited only if you choose to set an expiry.
HeaderAuthorization: Bearer pipsync_live_<32 alnum chars>
Obtaining an API key
API access requires the Enterprise plan. Once on Enterprise:
- Navigate to Settings → API Keys in your workspace.
- Click Create key, choose a name (e.g. prod-signal-reader), and select the scopes you need.
- Copy the key — it is shown only once. Store it in a secret manager (AWS Secrets Manager, Vault, Doppler, etc.).
- To rotate: create a replacement key, cut traffic over, revoke the old key. There is no downtime if you overlap by one deployment cycle.
Key scopes
| Scope | Access | Endpoints |
|---|---|---|
| signals:read | Read-only | GET /v1/signals |
| trades:read | Read-only | GET /v1/trades |
| reports:read | Read-only | GET /v1/reports, GET /v1/reports/trades |
| account:read | Read-only | GET /v1/me, GET /v1/account/usage |
| webhooks:write | Write | Manage webhook subscriptions (dashboard only) |
Key security
⚠
Never expose a live key in client-side code. Keys embedded in browser bundles, mobile apps, or public repos are compromised. Use sandbox keys for prototyping. Revoke a leaked key immediately from Settings → API Keys and create a replacement.
Additional hardening available on Enterprise: IP allowlist (restrict which CIDR ranges may use a key) and IP blocklist. Both configured per-key from the same settings page.
Rate limits
Limits are per API key per rolling 60-second window. Webhooks are separately rate-limited on their inbound delivery surface.
| Plan | API req / min | Webhooks / min | Burst | Notes |
|---|---|---|---|---|
| Basic | 60 | 10 | 1× | No burst headroom |
| Pro | 300 | 60 | 2× | Short burst window (5 s) |
| Business | 1000 | 200 | 3× | Burst up to 3 000 RPM for ≤ 5 s |
| Enterprise | Custom | Custom | Custom | Negotiated SLA, custom concurrency |
Response headers
Every API response includes rate-limit headers so your integration can stay within bounds without trial and error:
| Header | Value |
|---|---|
| X-RateLimit-Limit | Maximum requests allowed in the current window |
| X-RateLimit-Remaining | Requests remaining in the current window |
| X-RateLimit-Reset | ISO 8601 timestamp when the window resets |
| Retry-After | Seconds to wait before retrying (only on 429) |
ℹ
429 responses are retryable. Always read Retry-After and honour it. Do not hard-code a sleep duration — the exact window depends on your plan and current load.
Exponential backoff
Implement jittered exponential backoff whenever you receive a 429. This pattern prevents thundering-herd issues if your fleet is calling in parallel:
Node.jsPython
async function fetchWithRetry(url, key, maxRetries = 4) {
for (let attempt = 0; attempt <= maxRetries; attempt++) {
const res = await fetch(url, {
headers: { Authorization: Bearer ${key} },
});
if (res.status !== 429) return res.json();
const retryAfter = parseInt(res.headers.get("Retry-After") ?? "1", 10);
const backoff = retryAfter * 1000 * Math.pow(2, attempt) + Math.random() * 200;
await new Promise(r => setTimeout(r, backoff));
} throw new Error("Rate limit retries exhausted"); }
Error codes
All errors use RFC 7807 Problem Details (application/problem+json):
401 Unauthorized
{ "type": "https://app.pipsync.io/errors/unauthorized", "title": "Unauthorized", "status": 401, "detail": "Missing or invalid API key" }
| HTTP status | Meaning | Action |
|---|---|---|
| 400 | Bad Request | Fix the request body / query params |
| 401 | Unauthorized | Check key value and Authorization header format |
| 403 | Forbidden | Key lacks the required scope for this endpoint |
| 404 | Not Found | Resource does not exist or was deleted |
| 422 | Unprocessable | Passes schema but business-rule validation failed |
| 429 | Rate Limited | Back off and retry (see Retry-After) |
| 5xx | Server Error | Transient — retry with backoff; check pipsync.io/status |
GET /v1/me
Returns the profile of the workspace owner associated with the API key.
GET/v1/meTry it ↗
GET /v1/signals
Returns parsed trading signals for the workspace. Signals are the normalized output of the parser — ready for downstream processing.
GET/v1/signalsTry it ↗
Query parameters
| Param | Type | Required | Description | |
|---|---|---|---|---|
| since | ISO 8601 | No | Return signals received at or after this time | |
| limit | number | No | Max results per page (default 25, max 100) | |
| page | number | No | Page number (1-based) | |
| instrument | string | No | Filter by instrument, e.g. EURUSD | |
| status | string | No | Filter by status: parsed | pending | invalid |
curl "https://app.pipsync.io/api/v1/signals?limit=10"
-H "Authorization: Bearer $PIPSYNC_KEY"
GET /v1/trades
Returns trade records (opened, closed, partially-closed positions) for the workspace. Paginated; newest trades first.
GET/v1/tradesTry it ↗
| Param | Type | Required | Description | |
|---|---|---|---|---|
| since | ISO 8601 | No | Only trades opened at or after this time | |
| limit | number | No | Max results per page (default 25, max 100) | |
| page | number | No | Page number (1-based) | |
| instrument | string | No | Filter by instrument | |
| status | string | No | Filter by status: open | closed | pending |
curl "https://app.pipsync.io/api/v1/trades?limit=25"
-H "Authorization: Bearer $PIPSYNC_KEY"
GET /v1/reports
Enumerate generated trade reports and download links. Use /v1/reports/trades to get the detailed line-item CSV/PDF export.
GET/v1/reportsTry it ↗
✦
The full OpenAPI 3.1 spec (with request / response schemas for every endpoint) is available at /api/v1/openapi.json. Import it into Postman, Insomnia, or use the interactive playground to try every endpoint live.
Realtime stream
For browser dashboards and live monitoring, subscribe to /api/trading/stream with EventSource. This is the shipped SSE fallback when WebSocket upgrades are unavailable; keep signed webhooks for server-to-server automation.
Webhooks
Subscribe to push events from Settings → Webhooks. PipSync POSTs a signed JSON payload to your endpoint every time an event occurs. Delivery is attempted up to 5 times with exponential backoff.
POSTyour-server.com/pipsync — signed by X-PipSync-Signature
| Event | When | Payload type |
|---|---|---|
| signal.received | A signal was parsed from any source | SignalIntent |
| signal.parsed | Parser normalized the source message | ParsedSignal |
| trade.opened | A broker position was opened | TradeOpened |
| trade.closed | A broker position was closed | TradeClosed |
| trade.tp_hit | Take profit was hit | TradeClosed |
| trade.sl_hit | Stop loss was hit | TradeClosed |
| subscription.upgraded | Subscription moved to a higher tier | Subscription |
| subscription.canceled | Cancellation was scheduled | Subscription |
Verifying signatures
Every webhook delivery includes an X-PipSync-Signature header formatted as t=<unix-ts>,v1=<hex-hmac-sha256>. Verify before trusting the payload:
Node.jsPython
import crypto from "crypto";
export function verifyWebhook(rawBody: string, header: string, secret: string): boolean { const parts = Object.fromEntries( header.split(",").map((part) => part.split("=")), ); const signed = parts.t + "." + rawBody; const expected = crypto .createHmac("sha256", secret) .update(signed) .digest("hex"); // Constant-time comparison to prevent timing attacks return crypto.timingSafeEqual( Buffer.from(expected), Buffer.from(parts.v1 ?? ""), ); }
⚡
Always verify the timestamp. Reject payloads where t is more than 5 minutes in the past — this prevents replay attacks. Compare Math.abs(Date.now() / 1000 - Number(parts.t)) > 300.
OpenAPI clients
The shipped contract is the OpenAPI 3.1 spec at /api/v1/openapi.json. Generate a typed client in your runtime — or use the interactive playground for ad-hoc requests.
TypeScript
Generate with openapi-typescript
/api/v1/openapi.json
Python
Generate with openapi-python-client
Go
Generate with oapi-codegen
Rust
Generate with progenitor or openapi-generator
C#
Generate with NSwag
MQL5
Use REST + signed webhook examples
Contact us for EA samples
✦
Prefer the interactive playground for ad-hoc testing with your real key. Open Playground →