Using the API
MCA Manager exposes a REST API (v1) for automating intake, syncing deals and
payments, and integrating your stack. Everything below is also in the
machine-readable spec at /api/openapi.json and the
interactive API reference, where you can send real
requests and download a Postman collection.
Authentication and scopes
Requests authenticate with a per-tenant API key sent as a bearer token on your company host:
Authorization: Bearer mca_live_…
Keys are created under Settings → API keys (guide) with
per-resource scopes (deals:read, payments:write, *:read…; write
implies read), an optional expiry and an IP allow-list. A test key
(mca_test_…) is served by your sandbox tenant, or read-only until one exists.
Start with GET /api/v1/whoami: it returns the key's scopes, the tenant it is
pointed at and the rate limit.
Responses and errors
Every response carries X-Request-Id. Errors share one envelope:
{ "error": "request did not validate", "code": "validation_error",
"details": [{ "path": "amount", "message": "money must be a decimal string…" }],
"requestId": "6f0c…" }
| Status | Codes |
|---|---|
| 400 | validation_error, invalid_id, invalid_json, invalid_sort, invalid_expand, invalid_cursor, bad_request |
| 401 | unauthorized (missing, invalid or expired key) |
| 403 | forbidden (scope missing, key read-only, address not allowed) |
| 404 | not_found |
| 409 | conflict (illegal state transition, funding block, duplicate) |
| 422 | invalid_reference, idempotency_key_reused |
| 429 | rate_limited — Retry-After: 60 |
| 500 | internal_error — quote the requestId |
Lists: pagination, sorting, filtering
GET /api/v1/deals?state=FUNDED&limit=100&sort=fundedAt:desc&expand=merchant&fields=id,dealNumber,fundedAmount
→ { "deals": [...], "count": 100, "hasMore": true, "nextCursor": "MTA0Mg" }
limit(1–200, default 50) andcursor(passnextCursorback) page through results; cursors are stable under inserts.sort=field:asc|descfrom each resource's documented sortable fields;idis always available and used as the tiebreak.expand=includes relations (e.g.merchant,paymentson deals);fields=returns only the named columns (plusid).ids=1,2,3,q=(free text where supported),createdSince,createdBefore,updatedSincework everywhere; each resource adds its own filters (dealstate, paymentstatus/type/scheduledSince, leadstatus/source…).
Writes
- Send
Idempotency-Keyon POSTs. The first request runs; a repeat with the same key and body returns the stored response (Idempotency-Replayed: true) for 24 hours; the same key with a different body is refused with 422. - Money is a decimal string with at most two places (
"425.00"); a cent-exact number is accepted, anything else is rejected. Amounts come back as decimal strings. - Timestamps are UTC ISO-8601; dates as
YYYY-MM-DD. - Deal and payment writes run the same code as the staff screens: a deal created through the API gets its deal number, house submission and stip matrix;
PATCH /deals/{id}withstateruns the state machine and funding blocks; marking a paymentPAIDposts the ledger entry. Every write is audited and emits the matching webhook event.
Rate limits
120 requests per minute per key. X-RateLimit-Limit and X-RateLimit-Remaining
are on every response; a 429 carries Retry-After. Back off and retry with the
same Idempotency-Key on writes.
Versioning
The API is versioned in the path (/api/v1). Additive changes — new fields,
filters, endpoints, events — ship without notice and are listed in the changelog
below. Breaking changes ship as /api/v2 with at least 12 months of overlap,
and deprecated operations carry a Deprecation header during that time.
Examples
Create a lead from a website form (cURL):
curl -X POST https://acme.mcamgr.com/api/v1/leads \
-H "Authorization: Bearer mca_live_…" -H "Content-Type: application/json" \
-H "Idempotency-Key: form-8841" \
-d '{ "businessName": "Acme Diner LLC", "contactName": "Pat Owner", "email": "pat@example.com", "phone": "555-0100", "source": "website" }'
Page through funded deals (Node):
let cursor = null;
do {
const r = await fetch(`https://acme.mcamgr.com/api/v1/deals?state=FUNDED&limit=200${cursor ? `&cursor=${cursor}` : ""}`, { headers: { Authorization: `Bearer ${KEY}` } });
const page = await r.json();
for (const deal of page.deals) sync(deal);
cursor = page.nextCursor;
} while (cursor);
Mark a payment paid (Python):
import requests
r = requests.patch("https://acme.mcamgr.com/api/v1/payments/9001",
headers={"Authorization": f"Bearer {KEY}"}, json={"status": "PAID", "clearedDate": "2026-09-22"})
r.raise_for_status(); print(r.headers["X-Request-Id"], r.json()["payment"]["status"])
API changelog
- v630 — OpenAPI generated from the code (every operation, real request/response schemas), full-method explorer with Postman export.
- v629 — API keys: scopes, live/test kinds, expiry, IP allow-list, rotation;
GET /whoami. - v628 — Error envelope with
requestId,X-RateLimit-*, cursor pagination,sort/expand/fields/ids/date windows, per-resource filters,Idempotency-Key, decimal-string money; deal and payment writes through the shared services. - v626 — Webhook envelope
{ id, event, version, occurredAt, data }, new lifecycle events,/webhook-endpointsmanagement, inbound idempotency. - v625 — Webhook delivery log, retries, auto-pause; https-only endpoints.
- v624 — Merchant contacts return
ssnLast4only.
Can’t find what you need? Return to the app or contact your administrator.