← Back to appMCA Manager Helpmcamgr.com
Browse help topics

Webhooks

Webhooks push events from MCA Manager into your own systems in real time. Manage endpoints under Settings → Webhooks (requires the edit company settings permission).

Add an endpoint

Provide the destination URL and the events you want (or * for all). The URL must be a public https address; private networks, localhost and cloud metadata addresses are refused, and the address is checked again before every delivery. Each endpoint gets a signing secret, shown once, used to sign every delivery.

Events

| Event | When | |---|---| | deal.created | A deal was created (staff, API, portal or email intake). | | deal.state_changed | A deal moved to a new state (funded, closed, defaulted…), from any path: screen, API, automation, early payoff. | | merchant.created | A merchant record was created. | | lead.created | A lead was created. | | lead.status_changed | A lead's status changed. | | submission.status_changed | A funder submission moved to a new pipeline status. | | payment.paid | A payment was marked paid — by staff, by a processor callback, or through the API. | | payment.bounced | A payment was returned; carries the NACHA return code when known. | | esign.signed | One party signed a document sent for signature. | | esign.completed | Every party signed; carries the filed document id and url. | | esign.declined | A signer declined; carries their reason. | | webhook.test | Sent by the Send test button. |

The same list, with example payloads, is returned by GET /api/v1/webhook-endpoints.

Envelope

{ "id": "whd_9123", "event": "payment.paid", "version": 1, "occurredAt": "2026-09-22T14:03:11.000Z", "data": { "paymentId": 9001, "dealId": 1042, "amount": "425.00", "source": "processor" } }

id is stable per delivery (a redelivery gets a new id); use it to de-duplicate on your side. version is bumped only for breaking changes to the envelope or a payload. Headers X-Webhook-Id and X-Webhook-Event repeat the id and event.

Verifying signatures

Each delivery is a JSON POST with headers:

  • X-Timestamp - unix-style timestamp (seconds)
  • X-Signature - HMAC-SHA256, hex

Compute the signature over the string timestamp + "." + body using your endpoint’s secret and compare with X-Signature in constant time. Reject if they don’t match or the timestamp is more than five minutes old.

Rotating the secret: Rotate secret on an endpoint (or POST /api/v1/webhook-endpoints/{id}?action=rotate) issues a new secret. For 24 hours every delivery also carries X-Signature-Previous, signed with the old secret, so you can switch at your own pace.

import { createHmac, timingSafeEqual } from "node:crypto";
const expected = createHmac("sha256", SECRET).update(`${ts}.${rawBody}`).digest("hex");
const ok = expected.length === sig.length && timingSafeEqual(Buffer.from(expected), Buffer.from(sig));
import hmac, hashlib, time
def verify(secret: str, ts: str, raw_body: bytes, sig: str) -> bool:
    if abs(time.time() - int(ts)) > 300: return False
    expected = hmac.new(secret.encode(), f"{ts}.".encode() + raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, sig)

Delivery, retries and the log

Deliveries are at-least-once. Each attempt times out after 10 seconds; a failed attempt is retried five times over roughly eight minutes (15 s, 30 s, 1 m, 2 m, 4 m). Return any 2xx quickly and do the work afterwards.

Open Deliveries on an endpoint to see every attempt: time, event, status, HTTP response, tries, duration, the first part of your response body, and the payload. Redeliver sends a past payload again as a new delivery. Rows are kept for 30 days.

An endpoint that fails 20 deliveries in a row is paused and the admins are notified; fix the receiver, then Re-enable it. Turning an endpoint off yourself is not a pause and is never notified.

Managing endpoints through the API

With an API key that carries the Webhooks API scope: GET/POST /api/v1/webhook-endpoints, GET/PATCH/DELETE /api/v1/webhook-endpoints/{id}, POST /api/v1/webhook-endpoints/{id}?action=rotate. The list call also returns the event catalogue with example payloads.

Inbound webhooks

POST /api/webhooks/inbound/<source> accepts signed payloads from your systems (bank statements, credit profiles, disclosures, legal updates) using the same HMAC scheme with the inboundWebhookSecret setting. Send an eventId (or id) with each payload: a repeat of the same id within 30 days is acknowledged and not applied again.


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

Webhooks - Help