Skip to main content
HomeDevelopersAPI 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.

Quickstart

Store your key, call /v1/me to verify auth, then start reading signals or trades. Five minutes from zero to first API response.

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:

  1. Navigate to Settings → API Keys in your workspace.
  2. Click Create key, choose a name (e.g. prod-signal-reader), and select the scopes you need.
  3. Copy the key — it is shown only once. Store it in a secret manager (AWS Secrets Manager, Vault, Doppler, etc.).
  4. 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

ScopeAccessEndpoints
signals:readRead-onlyGET /v1/signals
trades:readRead-onlyGET /v1/trades
reports:readRead-onlyGET /v1/reports, GET /v1/reports/trades
account:readRead-onlyGET /v1/me, GET /v1/account/usage
webhooks:writeWriteManage 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.

PlanAPI req / minWebhooks / minBurstNotes
Basic6010No burst headroom
Pro30060Short burst window (5 s)
Business1000200Burst up to 3 000 RPM for ≤ 5 s
EnterpriseCustomCustomCustomNegotiated SLA, custom concurrency

Response headers

Every API response includes rate-limit headers so your integration can stay within bounds without trial and error:

HeaderValue
X-RateLimit-LimitMaximum requests allowed in the current window
X-RateLimit-RemainingRequests remaining in the current window
X-RateLimit-ResetISO 8601 timestamp when the window resets
Retry-AfterSeconds 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:

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):

{
  "type": "https://app.pipsync.io/errors/unauthorized",
  "title": "Unauthorized",
  "status": 401,
  "detail": "Missing or invalid API key"
}
HTTP statusMeaningAction
400Bad RequestFix the request body / query params
401UnauthorizedCheck key value and Authorization header format
403ForbiddenKey lacks the required scope for this endpoint
404Not FoundResource does not exist or was deleted
422UnprocessablePasses schema but business-rule validation failed
429Rate LimitedBack off and retry (see Retry-After)
5xxServer ErrorTransient — 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 ↗
curl https://app.pipsync.io/api/v1/me \
  -H "Authorization: Bearer $PIPSYNC_KEY"

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

ParamTypeRequiredDescription
sinceISO 8601NoReturn signals received at or after this time
limitnumberNoMax results per page (default 25, max 100)
pagenumberNoPage number (1-based)
instrumentstringNoFilter by instrument, e.g. EURUSD
statusstringNoFilter 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 ↗

Query parameters

ParamTypeRequiredDescription
sinceISO 8601NoOnly trades opened at or after this time
limitnumberNoMax results per page (default 25, max 100)
pagenumberNoPage number (1-based)
instrumentstringNoFilter by instrument
statusstringNoFilter 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
EventWhenPayload type
signal.receivedA signal was parsed from any sourceSignalIntent
signal.parsedParser normalized the source messageParsedSignal
trade.openedA broker position was openedTradeOpened
trade.closedA broker position was closedTradeClosed
trade.tp_hitTake profit was hitTradeClosed
trade.sl_hitStop loss was hitTradeClosed
subscription.upgradedSubscription moved to a higher tierSubscription
subscription.canceledCancellation was scheduledSubscription

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:

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.

Prefer the interactive playground for ad-hoc testing with your real key. Open Playground →