Developer documentation

OpenAPI specification

Partner API

Version 1.1.0OpenAPI 3.1.014 endpoints · 5 webhooks

Downloads are OpenAPI 3.1.0 with this host's server URL, ready to import into Postman, Insomnia, Swagger Editor or a code generator.

Machine-readable spec URL

https://your-portal-host/api/partner/v1/openapi.json

Overview

Send merchant deals, track their status, receive webhooks and pull residuals from your own software. Every API key acts as ONE partner account inside ONE organization and can only see that partner's own deals and residuals.

All requests and responses are JSON with camelCase field names. Money amounts are integer cents in USD.

This document is the source of truth for the API; the server is tested against it.

Permissions. Keys are read_write (default) or read_only. Read-only keys may call every GET endpoint; any other method returns 403 insufficient_permission.

Expiry and rotation. Keys can carry an expiry date. Rotating a key in the portal issues a replacement and keeps the old key working for a grace period; during that period responses carry X-Api-Key-Grace-Ends. Expired keys and rotated keys past their grace period return 401 unauthorized.

Request ids. Every response carries X-Request-Id; quote it when asking for support. Requests are listed in the portal's Logs section.

Base URL
https://your-portal-host/api/partner/v1

All endpoint paths below are relative to this URL. Relative to the host you use for the partner portal.

Rate limit: 120 requests per minute per API key.

Authentication

bearerAuth · http bearer

Authorization: Bearer ptk_live_... (live) or ptk_test_... (test). Create keys in the partner portal under Developer API. The full key is shown once.

Applies to every endpoint unless the endpoint says otherwise.

Endpoints

Account

GET/meIdentify the partner and key

Requires bearerAuthgetMe

Handy first call to confirm your key works and whether it is live or test.

Responses

200

The partner behind this key.

application/json

Schema

TypeMe

Example

{
  "object": "partner",
  "livemode": false,
  "partner": {
    "id": 731,
    "name": "Acme Referral Partners"
  },
  "apiKey": {
    "id": 12,
    "mode": "test"
  }
}

Missing, malformed, revoked, expired or unknown key, or a rotated key past its grace period (unauthorized).

application/json · error response

Schema

The partner account behind the key is not active (forbidden), or a read-only key called a write endpoint (insufficient_permission).

application/json · error response

Schema

Too many requests for this key (rate_limited). Wait for Retry-After seconds.

Headers: Retry-After (integer), X-RateLimit-Limit (integer)

application/json · error response

Schema

Unexpected server error (internal_error). Safe to retry; use an Idempotency-Key for writes.

application/json · error response

Schema

Deals

POST/dealsSubmit a deal

Requires bearerAuthcreateDeal

Creates a merchant lead credited to your partner account, exactly like a portal submission. Only contactName is required; unknown fields are ignored. Send an Idempotency-Key header so a retried request never creates a duplicate: repeating the same key with the same body returns the original response (with Idempotent-Replayed: true); the same key with a different body returns 409 idempotency_conflict. Test keys create sandbox deals only.

Parameters

Idempotency-Keyheaderstring

Unique value per logical deal, e.g. your own record id.

Request body · required

application/json

Schema

Example

{
  "contactName": "Jordan Lee",
  "companyName": "Lee's Coffee Bar",
  "contactEmail": "jordan@leescoffee.example",
  "contactPhone": "+13055550142",
  "monthlyVolume": "45000",
  "averageTicket": "12.50",
  "businessCity": "Miami",
  "businessState": "FL",
  "notes": "Wants countertop terminal"
}

Responses

201

Deal created (or replayed).

application/json

Schema

TypeDeal

Example

{
  "id": 48213,
  "object": "deal",
  "livemode": true,
  "status": "received",
  "contactName": "Jordan Lee",
  "companyName": "Lee's Coffee Bar",
  "contactEmail": "jordan@leescoffee.example",
  "contactPhone": "+13055550142",
  "monthlyVolume": "45000",
  "createdAt": "2026-09-01T14:03:11.000Z",
  "updatedAt": "2026-09-03T09:12:40.000Z"
}
400

Validation failed (validation_error).

application/json · error response

Schema

Missing, malformed, revoked, expired or unknown key, or a rotated key past its grace period (unauthorized).

application/json · error response

Schema

The partner account behind the key is not active (forbidden), or a read-only key called a write endpoint (insufficient_permission).

application/json · error response

Schema

409

Idempotency-Key reused with a different body (idempotency_conflict).

application/json · error response

Schema

Too many requests for this key (rate_limited). Wait for Retry-After seconds.

Headers: Retry-After (integer), X-RateLimit-Limit (integer)

application/json · error response

Schema

Unexpected server error (internal_error). Safe to retry; use an Idempotency-Key for writes.

application/json · error response

Schema

GET/dealsList your deals

Requires bearerAuthlistDeals

Newest first. Page with cursor = the previous page's nextCursor.

Parameters

limitqueryinteger
cursorqueryinteger

Return deals older than this id.

statusqueryDealStatus

Responses

200

A page of deals.

application/json

Schema

Example

{
  "object": "list",
  "livemode": true,
  "data": [
    {
      "id": 48213,
      "object": "deal",
      "livemode": true,
      "status": "in_progress",
      "contactName": "Jordan Lee",
      "companyName": "Lee's Coffee Bar",
      "contactEmail": "jordan@leescoffee.example",
      "contactPhone": "+13055550142",
      "monthlyVolume": "45000",
      "createdAt": "2026-09-01T14:03:11.000Z",
      "updatedAt": "2026-09-03T09:12:40.000Z"
    }
  ],
  "hasMore": false,
  "nextCursor": null
}
400

Invalid query parameter.

application/json · error response

Schema

Missing, malformed, revoked, expired or unknown key, or a rotated key past its grace period (unauthorized).

application/json · error response

Schema

The partner account behind the key is not active (forbidden), or a read-only key called a write endpoint (insufficient_permission).

application/json · error response

Schema

Too many requests for this key (rate_limited). Wait for Retry-After seconds.

Headers: Retry-After (integer), X-RateLimit-Limit (integer)

application/json · error response

Schema

Unexpected server error (internal_error). Safe to retry; use an Idempotency-Key for writes.

application/json · error response

Schema

GET/deals/{id}Get one deal with its status history

Requires bearerAuthgetDeal

Parameters

idpathintegerrequired

Deal id.

Responses

200

The deal.

application/json

Schema

Example

{
  "id": 48213,
  "object": "deal",
  "livemode": true,
  "status": "in_progress",
  "contactName": "Jordan Lee",
  "companyName": "Lee's Coffee Bar",
  "contactEmail": "jordan@leescoffee.example",
  "contactPhone": "+13055550142",
  "monthlyVolume": "45000",
  "createdAt": "2026-09-01T14:03:11.000Z",
  "updatedAt": "2026-09-03T09:12:40.000Z",
  "history": [
    {
      "status": "received",
      "at": "2026-09-01T14:03:11.000Z"
    },
    {
      "status": "in_progress",
      "at": "2026-09-02T16:20:05.000Z"
    }
  ]
}

Missing, malformed, revoked, expired or unknown key, or a rotated key past its grace period (unauthorized).

application/json · error response

Schema

The partner account behind the key is not active (forbidden), or a read-only key called a write endpoint (insufficient_permission).

application/json · error response

Schema

404

No such deal for this key (not_found). Deals belonging to anyone else also return 404.

application/json · error response

Schema

Too many requests for this key (rate_limited). Wait for Retry-After seconds.

Headers: Retry-After (integer), X-RateLimit-Limit (integer)

application/json · error response

Schema

Unexpected server error (internal_error). Safe to retry; use an Idempotency-Key for writes.

application/json · error response

Schema

PATCH/deals/{id}Update a deal

Requires bearerAuthupdateDeal

Updates fields on a deal you submitted while its status is received or in_progress. Once the deal reaches application_submitted (underwriting) or later, returns 409 deal_locked. Requires a read-write key. Safe to retry.

Parameters

idpathintegerrequired

Deal id.

Request body · required

application/json

Schema

Example

{
  "contactPhone": "+13055550199",
  "monthlyVolume": "52000"
}

Responses

200

The updated deal.

application/json

Schema

TypeDeal

Example

{
  "id": 48213,
  "object": "deal",
  "livemode": true,
  "status": "in_progress",
  "contactName": "Jordan Lee",
  "companyName": "Lee's Coffee Bar",
  "contactEmail": "jordan@leescoffee.example",
  "contactPhone": "+13055550199",
  "monthlyVolume": "52000",
  "createdAt": "2026-09-01T14:03:11.000Z",
  "updatedAt": "2026-09-03T09:12:40.000Z"
}

Invalid input (validation_error).

application/json · error response

Schema

Missing, malformed, revoked, expired or unknown key, or a rotated key past its grace period (unauthorized).

application/json · error response

Schema

The partner account behind the key is not active (forbidden), or a read-only key called a write endpoint (insufficient_permission).

application/json · error response

Schema

No such resource for this key (not_found). Resources belonging to anyone else also return 404.

application/json · error response

Schema

The deal is in underwriting or later and can no longer be changed through the API (deal_locked). details.status holds its current status.

application/json · error response

Schema

Too many requests for this key (rate_limited). Wait for Retry-After seconds.

Headers: Retry-After (integer), X-RateLimit-Limit (integer)

application/json · error response

Schema

Unexpected server error (internal_error). Safe to retry; use an Idempotency-Key for writes.

application/json · error response

Schema

POST/deals/{id}/withdrawWithdraw a deal

Requires bearerAuthwithdrawDeal

Withdraws a deal you submitted while it is received or in_progress; the deal moves to closed and a deal.status_changed event fires. Idempotent: withdrawing an already-withdrawn deal returns it unchanged. Returns 409 deal_locked once the deal is in underwriting or later. Requires a read-write key.

Parameters

idpathintegerrequired

Deal id.

Request body · optional

application/json

Schema

Example

{
  "reason": "Merchant signed elsewhere"
}

Responses

200

The withdrawn deal.

application/json

Schema

TypeDeal

Example

{
  "id": 48213,
  "object": "deal",
  "livemode": true,
  "status": "closed",
  "contactName": "Jordan Lee",
  "companyName": "Lee's Coffee Bar",
  "contactEmail": "jordan@leescoffee.example",
  "contactPhone": "+13055550142",
  "monthlyVolume": "45000",
  "createdAt": "2026-09-01T14:03:11.000Z",
  "updatedAt": "2026-09-03T09:12:40.000Z"
}

Invalid input (validation_error).

application/json · error response

Schema

Missing, malformed, revoked, expired or unknown key, or a rotated key past its grace period (unauthorized).

application/json · error response

Schema

The partner account behind the key is not active (forbidden), or a read-only key called a write endpoint (insufficient_permission).

application/json · error response

Schema

No such resource for this key (not_found). Resources belonging to anyone else also return 404.

application/json · error response

Schema

The deal is in underwriting or later and can no longer be changed through the API (deal_locked). details.status holds its current status.

application/json · error response

Schema

Too many requests for this key (rate_limited). Wait for Retry-After seconds.

Headers: Retry-After (integer), X-RateLimit-Limit (integer)

application/json · error response

Schema

Unexpected server error (internal_error). Safe to retry; use an Idempotency-Key for writes.

application/json · error response

Schema

Merchants

Your merchants that are live. Processors are shown only as anonymized lane labels.

GET/merchantsList live merchants

Requires bearerAuthlistMerchants

Your merchants that are live, newest first. The processor is an anonymized lane label; real processor names are never returned. Test keys list sandbox deals simulated to live.

Parameters

limitqueryinteger
cursorqueryinteger

nextCursor from the previous page.

Responses

200

A page of merchants.

application/json

Schema

Example

{
  "object": "list",
  "livemode": true,
  "data": [
    {
      "object": "merchant",
      "id": 912,
      "livemode": true,
      "businessName": "Lee's Coffee Bar",
      "dba": "Lee's Coffee",
      "mccCode": "5814",
      "status": "live",
      "processor": "Lane 2",
      "liveSince": "2026-09-20"
    }
  ],
  "hasMore": false,
  "nextCursor": null
}

Invalid input (validation_error).

application/json · error response

Schema

Missing, malformed, revoked, expired or unknown key, or a rotated key past its grace period (unauthorized).

application/json · error response

Schema

The partner account behind the key is not active (forbidden), or a read-only key called a write endpoint (insufficient_permission).

application/json · error response

Schema

Too many requests for this key (rate_limited). Wait for Retry-After seconds.

Headers: Retry-After (integer), X-RateLimit-Limit (integer)

application/json · error response

Schema

Unexpected server error (internal_error). Safe to retry; use an Idempotency-Key for writes.

application/json · error response

Schema

Events

Every webhook event, retrievable for 90 days so a missed delivery can be recovered.

GET/eventsList events

Requires bearerAuthlistEvents

Events for this key's partner and mode, newest first. Use it to recover events your webhook endpoint missed. Events are kept for 90 days and are recorded while you hold an API key of that mode.

Parameters

typequeryEventType
createdAfterquerystring (date-time)

Only events created after this time.

limitqueryinteger
cursorquerystring

nextCursor from the previous page.

Responses

200

A page of events.

application/json

Schema

Example

{
  "object": "list",
  "livemode": true,
  "data": [
    {
      "object": "event",
      "id": "evt_3f9a0c1e8b7d4a2f9e6c5b4a3d2e1f00",
      "type": "deal.status_changed",
      "createdAt": "2026-09-02T16:20:05.000Z",
      "livemode": true,
      "data": {
        "deal": {
          "id": 48213,
          "status": "in_progress",
          "previousStatus": "received",
          "changedAt": "2026-09-02T16:20:05.000Z"
        }
      }
    }
  ],
  "hasMore": false,
  "nextCursor": null
}

Invalid input (validation_error).

application/json · error response

Schema

Missing, malformed, revoked, expired or unknown key, or a rotated key past its grace period (unauthorized).

application/json · error response

Schema

The partner account behind the key is not active (forbidden), or a read-only key called a write endpoint (insufficient_permission).

application/json · error response

Schema

Too many requests for this key (rate_limited). Wait for Retry-After seconds.

Headers: Retry-After (integer), X-RateLimit-Limit (integer)

application/json · error response

Schema

Unexpected server error (internal_error). Safe to retry; use an Idempotency-Key for writes.

application/json · error response

Schema

GET/events/{id}Get one event

Requires bearerAuthgetEvent

Parameters

idpathstringrequired

Event id (evt_...), the same id sent in the webhook body.

Responses

200

The event.

application/json

Schema

Example

{
  "object": "event",
  "id": "evt_3f9a0c1e8b7d4a2f9e6c5b4a3d2e1f00",
  "type": "deal.status_changed",
  "createdAt": "2026-09-02T16:20:05.000Z",
  "livemode": true,
  "data": {
    "deal": {
      "id": 48213,
      "status": "in_progress",
      "previousStatus": "received",
      "changedAt": "2026-09-02T16:20:05.000Z"
    }
  }
}

Missing, malformed, revoked, expired or unknown key, or a rotated key past its grace period (unauthorized).

application/json · error response

Schema

The partner account behind the key is not active (forbidden), or a read-only key called a write endpoint (insufficient_permission).

application/json · error response

Schema

No such resource for this key (not_found). Resources belonging to anyone else also return 404.

application/json · error response

Schema

Too many requests for this key (rate_limited). Wait for Retry-After seconds.

Headers: Retry-After (integer), X-RateLimit-Limit (integer)

application/json · error response

Schema

Unexpected server error (internal_error). Safe to retry; use an Idempotency-Key for writes.

application/json · error response

Schema

Residuals

GET/residualsResiduals by month

Requires bearerAuthlistResiduals

Monthly totals and per-merchant lines for your account — the same figures as the Earnings view in your partner portal. Defaults to the last 12 months; at most 24 months per request.

Parameters

fromquerystring

Example: 2026-01

toquerystring

Example: 2026-08

Responses

200

Residual report.

application/json

Schema

Example

{
  "object": "residual_report",
  "livemode": true,
  "currency": "USD",
  "from": "2026-07",
  "to": "2026-08",
  "totals": {
    "volumeCents": 9120000,
    "earningsCents": 22800,
    "lineCount": 2
  },
  "months": [
    {
      "month": "2026-08",
      "volumeCents": 4600000,
      "earningsCents": 11500,
      "lines": [
        {
          "merchantId": 9001,
          "merchantName": "Lee's Coffee Bar",
          "type": "merchant",
          "volumeCents": 4600000,
          "earningsCents": 11500
        }
      ]
    },
    {
      "month": "2026-07",
      "volumeCents": 4520000,
      "earningsCents": 11300,
      "lines": [
        {
          "merchantId": 9001,
          "merchantName": "Lee's Coffee Bar",
          "type": "merchant",
          "volumeCents": 4520000,
          "earningsCents": 11300
        }
      ]
    }
  ]
}
400

Invalid month range.

application/json · error response

Schema

Missing, malformed, revoked, expired or unknown key, or a rotated key past its grace period (unauthorized).

application/json · error response

Schema

The partner account behind the key is not active (forbidden), or a read-only key called a write endpoint (insufficient_permission).

application/json · error response

Schema

Too many requests for this key (rate_limited). Wait for Retry-After seconds.

Headers: Retry-After (integer), X-RateLimit-Limit (integer)

application/json · error response

Schema

Unexpected server error (internal_error). Safe to retry; use an Idempotency-Key for writes.

application/json · error response

Schema

GET/residuals/{month}Residuals for one month

Requires bearerAuthgetResidualMonth

Parameters

monthpathstringrequired

Example: 2026-08

Responses

200

One month.

application/json

Example

{
  "object": "residual_month",
  "livemode": true,
  "currency": "USD",
  "month": "2026-08",
  "volumeCents": 4600000,
  "earningsCents": 11500,
  "lines": [
    {
      "merchantId": 9001,
      "merchantName": "Lee's Coffee Bar",
      "type": "merchant",
      "volumeCents": 4600000,
      "earningsCents": 11500
    }
  ]
}
400

Invalid month.

application/json · error response

Schema

Missing, malformed, revoked, expired or unknown key, or a rotated key past its grace period (unauthorized).

application/json · error response

Schema

The partner account behind the key is not active (forbidden), or a read-only key called a write endpoint (insufficient_permission).

application/json · error response

Schema

Too many requests for this key (rate_limited). Wait for Retry-After seconds.

Headers: Retry-After (integer), X-RateLimit-Limit (integer)

application/json · error response

Schema

Unexpected server error (internal_error). Safe to retry; use an Idempotency-Key for writes.

application/json · error response

Schema

Sandbox

Test-mode only helpers for exercising your integration.

POST/sandbox/deals/{id}/simulateMove a sandbox deal to a status

Requires bearerAuthsimulateDealStatus

Test keys only. Changes a sandbox deal's status and fires the same webhooks a real change would (deal.status_changed, plus deal.approved/deal.declined).

Parameters

idpathintegerrequired

Deal id.

Request body · required

application/json

Schema

statusDealStatusrequired

Example

{
  "status": "approved"
}

Responses

200

The updated sandbox deal.

application/json

Schema

400

Invalid status.

application/json · error response

Schema

Missing, malformed, revoked, expired or unknown key, or a rotated key past its grace period (unauthorized).

application/json · error response

Schema

403

Live key used (test_mode_only).

application/json · error response

Schema

404

No such sandbox deal.

application/json · error response

Schema

Too many requests for this key (rate_limited). Wait for Retry-After seconds.

Headers: Retry-After (integer), X-RateLimit-Limit (integer)

application/json · error response

Schema

Unexpected server error (internal_error). Safe to retry; use an Idempotency-Key for writes.

application/json · error response

Schema

POST/sandbox/residuals/simulateFire a residuals.posted webhook

Requires bearerAuthsimulateResidualsPosted

Test keys only. Sends a test-mode residuals.posted event to your test webhook endpoints.

Request body · optional

application/json

Schema

monthstring

pattern ^\d{4}-(0[1-9]|1[0-2])$

Example

{
  "month": "2026-08"
}

Responses

202

Event queued.

application/json

Schema

400

Invalid month.

application/json · error response

Schema

Missing, malformed, revoked, expired or unknown key, or a rotated key past its grace period (unauthorized).

application/json · error response

Schema

403

Live key used (test_mode_only).

application/json · error response

Schema

Too many requests for this key (rate_limited). Wait for Retry-After seconds.

Headers: Retry-After (integer), X-RateLimit-Limit (integer)

application/json · error response

Schema

Unexpected server error (internal_error). Safe to retry; use an Idempotency-Key for writes.

application/json · error response

Schema

Spec

GET/openapi.jsonDownload this API specification

No authentication requiredgetOpenApiSpec

Responses

200

This document.

application/json

Schema

Typeobject

Webhooks

Events the API sends to your webhook endpoint. Each delivery is signed; see the headers on any event.

EVENTdeal.createdA deal credited to you was created.

Delivered as POST to your configured webhook endpoint.

Fires for every deal credited to you, whatever created it: this API, your portal, your landing pages, chat, referrals, social inboxes, imports or an admin.

Headers

X-Webhook-Signatureheaderstringrequired

t = unix seconds; v1 = hex HMAC-SHA256 of {t}.{raw body} with your endpoint's signing secret.

Example: t=1759075200,v1=5f2b...

X-Webhook-Idheaderstringrequired
X-Webhook-Eventheaderstringrequired

Payload · required

application/json

Schema

All of

TypeEvent
type"deal.created"

Your response

2XX

Return any 2xx within 10 seconds to acknowledge. Anything else (or a timeout/redirect) is retried with exponential backoff, up to 8 attempts.

EVENTdeal.status_changedA deal's public status changed. Moves inside one public status never fire.

Delivered as POST to your configured webhook endpoint.

Headers

X-Webhook-Signatureheaderstringrequired

t = unix seconds; v1 = hex HMAC-SHA256 of {t}.{raw body} with your endpoint's signing secret.

Example: t=1759075200,v1=5f2b...

X-Webhook-Idheaderstringrequired
X-Webhook-Eventheaderstringrequired

Payload · required

application/json

Schema

All of

TypeEvent
type"deal.status_changed"

Your response

2XX

Return any 2xx within 10 seconds to acknowledge. Anything else (or a timeout/redirect) is retried with exponential backoff, up to 8 attempts.

EVENTdeal.approvedA deal moved to approved (also sends deal.status_changed).

Delivered as POST to your configured webhook endpoint.

Headers

X-Webhook-Signatureheaderstringrequired

t = unix seconds; v1 = hex HMAC-SHA256 of {t}.{raw body} with your endpoint's signing secret.

Example: t=1759075200,v1=5f2b...

X-Webhook-Idheaderstringrequired
X-Webhook-Eventheaderstringrequired

Payload · required

application/json

Schema

All of

TypeEvent
type"deal.approved"

Your response

2XX

Return any 2xx within 10 seconds to acknowledge. Anything else (or a timeout/redirect) is retried with exponential backoff, up to 8 attempts.

EVENTdeal.declinedA deal was declined (also sends deal.status_changed).

Delivered as POST to your configured webhook endpoint.

Headers

X-Webhook-Signatureheaderstringrequired

t = unix seconds; v1 = hex HMAC-SHA256 of {t}.{raw body} with your endpoint's signing secret.

Example: t=1759075200,v1=5f2b...

X-Webhook-Idheaderstringrequired
X-Webhook-Eventheaderstringrequired

Payload · required

application/json

Schema

All of

TypeEvent
type"deal.declined"

Your response

2XX

Return any 2xx within 10 seconds to acknowledge. Anything else (or a timeout/redirect) is retried with exponential backoff, up to 8 attempts.

EVENTresiduals.postedResiduals for a month were posted or updated for you.

Delivered as POST to your configured webhook endpoint.

Headers

X-Webhook-Signatureheaderstringrequired

t = unix seconds; v1 = hex HMAC-SHA256 of {t}.{raw body} with your endpoint's signing secret.

Example: t=1759075200,v1=5f2b...

X-Webhook-Idheaderstringrequired
X-Webhook-Eventheaderstringrequired

Payload · required

application/json

Schema

All of

TypeEvent
type"residuals.posted"

Your response

2XX

Return any 2xx within 10 seconds to acknowledge. Anything else (or a timeout/redirect) is retried with exponential backoff, up to 8 attempts.

Schemas

DealStatus

Typestring

Stable public deal status. received: submitted, not yet worked. in_progress: being worked by the sales team. application_submitted: merchant application submitted for underwriting. approved: application approved. boarding: merchant account being set up. live: processing. declined: application declined. closed: closed without an account (e.g. merchant not interested).

receivedin_progressapplication_submittedapprovedboardinglivedeclinedclosed

ErrorCode

Typestring
unauthorizedforbiddennot_foundvalidation_erroridempotency_conflictrate_limitedtest_mode_onlyinsufficient_permissiondeal_lockedinternal_error

EventType

Typestring
deal.createddeal.status_changeddeal.approveddeal.declinedresiduals.postedwebhook.test

ErrorResponse

errorobjectrequired
codeErrorCoderequired
messagestringrequired
detailsobject

e.g. {"field": "contactName"} for validation errors.

Me

object"partner"required
livemodebooleanrequired
partnerobjectrequired
idinteger
namestring
apiKeyobjectrequired
idinteger
modestring
livetest
permissionKeyPermission
expiresAtstring | null (date-time)
graceEndsAtstring | null (date-time)

Set while this key is being rotated out; it stops working at this time.

DealInput

String fields are limited to 2000 characters. Unknown fields are ignored.

contactNamestringrequired

min length 2 · max length 2000

contactEmailstring (email)
contactPhonestring
companyNamestring
monthlyVolumestring

Estimated monthly card volume in dollars.

averageTicketstring

Average ticket in dollars.

mccCodestring
mccDescriptionstring
currentProcessorstring
cardPresentPercentinteger

min 0 · max 100

websiteUrlstring
businessStreetstring
businessUnitstring
businessCitystring
businessStatestring
businessZipstring
notesstring

Deal

idintegerrequired
object"deal"required
livemodebooleanrequired

false for sandbox deals created with a test key.

statusDealStatusrequired
contactNamestringrequired
companyNamestring | null
contactEmailstring | null
contactPhonestring | null
monthlyVolumestring | null
createdAtstring (date-time)required
updatedAtstring (date-time)required

DealHistoryEntry

statusDealStatusrequired
atstring (date-time)required

DealWithHistory

All of

TypeDeal
historyarray<DealHistoryEntry>required

DealList

object"list"required
livemodebooleanrequired
dataarray<Deal>required
hasMorebooleanrequired
nextCursorinteger | nullrequired

ResidualLine

merchantIdinteger | nullrequired
merchantNamestring | nullrequired
typestringrequired

month_total lines carry a whole-month amount not broken down by merchant.

merchantmonth_total
volumeCentsintegerrequired
earningsCentsintegerrequired

Your earnings for the line.

ResidualMonth

monthstringrequired
volumeCentsintegerrequired
earningsCentsintegerrequired
linesarray<ResidualLine>required

ResidualReport

object"residual_report"required
livemodebooleanrequired
currency"USD"required
fromstringrequired
tostringrequired
totalsobjectrequired
volumeCentsinteger
earningsCentsinteger
lineCountinteger
monthsarray<ResidualMonth>required

ResidualMonthReport

object"residual_month"required
livemodebooleanrequired
currency"USD"required
monthstringrequired
volumeCentsintegerrequired
earningsCentsintegerrequired
linesarray<ResidualLine>required

SimulatedEvent

object"event"
livemodefalse
idstring
dataobject

Event

Webhook body. Verify the X-Webhook-Signature header before trusting it. Use id to ignore duplicates: deliveries are at-least-once.

idstringrequired
typeEventTyperequired
createdAtstring (date-time)required
livemodebooleanrequired
dataobjectrequired

DealEventData

dealobject
idinteger
previousStatusDealStatus
changedAtstring (date-time)
contactNamestring
companyNamestring | null
createdAtstring (date-time)

ResidualsEventData

Fetch GET /residuals/{month} for the figures.

residualsobject
monthstring

KeyPermission

Typestring

read_only keys may only call GET endpoints.

read_onlyread_write

DealPatch

Any subset of the deal input fields. Send an empty string to clear an optional field. contactName cannot be cleared.

contactNamestring

min length 2 · max length 2000

contactEmailstring (email)
contactPhonestring
companyNamestring
monthlyVolumestring

Estimated monthly card volume in dollars.

averageTicketstring

Average ticket in dollars.

mccCodestring
mccDescriptionstring
currentProcessorstring
cardPresentPercentinteger

min 0 · max 100

websiteUrlstring
businessStreetstring
businessUnitstring
businessCitystring
businessStatestring
businessZipstring
notesstring

WithdrawInput

reasonstring

Optional note shown to the agent's team.

max length 500

EventList

object"list"required
livemodebooleanrequired
dataarray<StoredEvent>required
hasMorebooleanrequired
nextCursorstring | nullrequired

Pass as cursor to fetch the next (older) page.

StoredEvent

The exact event body that was (or would have been) sent to your webhooks.

All of

TypeEvent
object"event"required

Merchant

object"merchant"required
idintegerrequired
livemodebooleanrequired
businessNamestringrequired
dbastring | null
mccCodestring | null
status"live"required
processorstring | nullrequired

Anonymized lane label such as Lane 2. Never a real processor name.

dealIdinteger | nullrequired

The id of your deal (from POST /deals) this merchant was boarded from, or null when the merchant is not linked to one of your deals.

liveSincestring | nullrequired

Boarding date (YYYY-MM-DD) in live mode.

MerchantList

object"list"required
livemodebooleanrequired
dataarray<Merchant>required
hasMorebooleanrequired
nextCursorinteger | nullrequired

Shared responses

Unauthorized

Missing, malformed, revoked, expired or unknown key, or a rotated key past its grace period (unauthorized).

application/json

Forbidden

The partner account behind the key is not active (forbidden), or a read-only key called a write endpoint (insufficient_permission).

application/json

RateLimited

Too many requests for this key (rate_limited). Wait for Retry-After seconds.

Headers: Retry-After, X-RateLimit-Limit

application/json

InternalError

Unexpected server error (internal_error). Safe to retry; use an Idempotency-Key for writes.

application/json

DealLocked

The deal is in underwriting or later and can no longer be changed through the API (deal_locked). details.status holds its current status.

application/json

NotFound

No such resource for this key (not_found). Resources belonging to anyone else also return 404.

application/json

ValidationError

Invalid input (validation_error).

application/json

Changelog

1.1.0 · 2026-09-29

  • Added GET /events and GET /events/{id} to recover missed webhooks.

  • Added PATCH /deals/{id} and POST /deals/{id}/withdraw (before underwriting only).

  • Added GET /merchants (live merchants, anonymized processor labels).

  • Added read-only keys (insufficient_permission), key expiry and rotation with a grace period (X-Api-Key-Grace-Ends).

  • Added deal_locked error code and X-Request-Id on every response.

  • deal.created now fires for every deal credited to you, whatever created it.

1.0.0 · 2026-09-15

  • Initial release: deals, residuals, webhooks and sandbox.