← Back to appMCA Manager Helpmcamgr.com
Browse help topics

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.

Money moves need an action scope by name — deals:fund (move a deal to FUNDED), payments:settle (mark a payment PAID or BOUNCED) and payments:refund (refunds and overpayment decisions). No :write grant or wildcard carries them. A key or app can never be given more than the person who creates it could do on screen.

An integration can also be a connected app using OAuth 2.0 — client credentials for a service, or the authorization-code flow for an app acting on behalf of a person. Its access token (mca_at_…) is sent the same way. See Connected apps.

Start with GET /api/v1/whoami: it returns the key's (or app'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…" }
StatusCodes
400validation_error, invalid_id, invalid_json, invalid_sort, invalid_expand, invalid_cursor, bad_request
401unauthorized (missing, invalid or expired key or token)
403forbidden (scope missing, key read-only, address not allowed), missing_scope (an action scope or the scope behind an expand=)
404not_found
409conflict (illegal state transition, funding block, duplicate)
422invalid_reference, idempotency_key_reused
429rate_limited — Retry-After gives the seconds until the window reopens
500internal_error — quote the requestId
503unavailable — a write while the rate limiter cannot count; retry after Retry-After

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) and cursor (pass nextCursor back) page through results; cursors are stable under inserts.
  • sort=field:asc|desc from each resource's documented sortable fields; id is always available and used as the tiebreak.
  • expand= includes relations (e.g. merchant,payments on deals) — each needs that resource's read scope, so deals:read alone cannot pull payments; fields= returns only the named columns (plus id).
  • ids=1,2,3, createdSince, createdBefore, updatedSince work everywhere; q= (free text) only on the lists the reference marks searchable — elsewhere it is refused with 400 rather than ignored. Each resource adds its own filters (deal state, payment status/type/scheduledSince, lead status/source…).

Writes

  • Send Idempotency-Key on 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} with state runs the state machine and funding blocks; marking a payment PAID posts the ledger entry. Every write is audited and emits the matching webhook event.

Rate limits

120 requests per minute per key or app, and 600 a minute for all of a company's keys and apps together. 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. An address that presents 20 bad keys within five minutes is turned away (429) for the rest of the window.

Recipes

Keep payments in sync. Subscribe a webhook to the payment.* events and apply each one, de-duplicating on the event id. Once a day (and after any outage of your receiver), page through GET /api/v1/payments?updatedSince=<your last high-water mark>&sort=updatedAt:asc and upsert what you find: webhooks are fast, the list is the record. A payment.deleted event is the only trace of a deleted row.

Retry writes safely. Give every POST an Idempotency-Key you derive from your own record (invoice-8841, not a random value per attempt). A retry after a timeout returns the first answer instead of creating a second row; a retry that arrives while the first is still running gets 409 — wait and try again.

Try it on test data. Create a test key: with a sandbox provisioned it reads and writes the sandbox; without one it can only read production. Money moves on test data still need their action scopes.

Generate a contract. PUT /deals/{id}/signers, then POST /deals/{id}/contracts { templateId } → 202. Listen for contract.generated (it carries the draft signature request) or contract.failed, then POST /esign-requests/{id}/send.

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

  • 1.5.0 (v737–v743, 2026-10-22)
    • OAuth 2.0: client credentials, and authorization code with PKCE for apps acting for a user; tokens are accepted wherever a key is.
    • Action scopes deals:fund, payments:settle and payments:refund, never implied by write access; keys are bounded by their creator's permissions.
    • New endpoints: payment delete; deal statement, schedule health, fees, overpayment and close-out; merchant contacts, DBAs and masked bank accounts; people; signers and early delivery; contract generation (202 + webhook); document templates; e-sign requests; documents.
    • Webhooks: a stable event id across endpoints and redeliveries; new events for deal updates and deletes, payment created/cancelled/deleted/refunded, bank-account changes, person merges, contracts and e-sign; OpenAPI webhooks section.
    • expand= is held to the key's scopes; errors carry codes that follow the status; Idempotency-Key claims before running; q= is rejected where a list has no search.
    • Rate limits: a ceiling for all of a company's keys together, a failed-authentication throttle per address, writes refused (503) when the limiter is down, Retry-After from the window.
  • 1.4.0 (v630, 2026-09-24)
    • OpenAPI generated from the code (every operation, real request/response schemas), full-method explorer with Postman export.
  • 1.3.0 (v629, 2026-09-23)
    • API keys: scopes, live/test kinds, expiry, IP allow-list, rotation; GET /whoami.
  • 1.2.0 (v628, 2026-09-23)
    • 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.
  • 1.1.0 (v624–v626, 2026-09-22)
    • Webhook envelope { id, event, version, occurredAt, data }, delivery log, retries and auto-pause, /webhook-endpoints management; merchant contacts return ssnLast4 only.

Can’t find what you need? Return to the app or contact your administrator.

Using the API - Help