Added
15 September 2026
3 days ago
🚀 New APIs
- Compliance API — RFI webhooks:
rfi_createdandrfi_status_changed. Stop polling RFIs. Both payloads carryorganizationId,rfiId, andorigin;rfi_status_changedaddspreviousStatus/currentStatusinstatusChangeDetails, drawn fromoutstanding,validatingSubmission,submissionValidationsFailed,submitted, andcancelled. Events fire only on a real transition. Fetch submission failures and cancellation reasons fromGET /compliance/rfis/{rfiId}.
⭐ Enhancements
- Platform — API keys are environment-prefixed, and you can hold more than one. New keys start with
mural_test_(sandbox) ormural_live_(production). A key sent to the wrong environment now returns401with a message naming the correct endpoint, rejected before any decrypt or database lookup. Keys issued before this change have no prefix and continue to work unchanged. An organization can also hold several active keys at once and rotate by minting a new key and explicitly revoking the old one, so a rotation no longer has to break a running integration. Rate limits remain the same in aggregate, not per-key. - Platform — rate-limited requests return a typed
RateLimitExceededError. Exceeding the API key rate limit now returns a documented429carryingparams.retryAfterSeconds, alongside a standardRetry-Afterheader. The API has always enforced this limit; it was never documented. Successful responses now also carryX-RateLimit-Limit/-Remaining/-Resetunder the standard names, so you can stay under the limit without provoking a rejection. Previously those shipped only suffixed (X-RateLimit-Limit-api) and only on allowed requests; a rejection carriedRetry-After-apiand a body naming the third-partyThrottlerException. The suffixed headers still ship unchanged. The error is published on every secured operation in the OpenAPI spec, and the new Rate Limits guide explains how the limit is counted — notably that requests made on behalf of a child organization count against the parent, so all children share one budget per endpoint. The limit and its window stay out of the error body; read them from the headers, which a429also carries. - Compliance API — government ID failures now name the specific document problem. The attestation
failureInfounion adds ten government-ID members, plusdocumentSide(front/back) where one side is at fault. Failures are ordered most-actionable first. See uploadAttestations for more information. - Compliance API — stricter postal-code and address validation. A postal code containing
.(for example the Brazilian CEP06.465-134) now returns400"Postal code must not contain a period" for every country, instead of being forwarded to the KYC provider and rejected downstream. - Payins API — pay-ins expire, and late deposits are refunded. Each pay-in carries an
expiresAt, and funds arriving after it are returned to the sender rather than credited. The payin status union addsrefundedwithrefundInfogiving the cause (payinAfterExpiry, or a provider-initiated refund). Refunds arrive as a separate event after the pay-in closes: the pay-in transitions tocanceledfirst, then a secondpayin_status_changeddeliverscanceled→refundedonce the refund settles. - Sandbox — simulated deposit caps are lower, and an over-cap request is rejected.
POST /api/sandbox/simulate/payinnow caps each rail well below the previous limits: 50 USD for ACH and wire, 1,000 MXN for SPEI, 65,000 ARS for CVU, and 275 BRL for PIX (previously 100 USD and 100,000 MXN). A request above the cap returns400. The caps exist to conserve the shared sandbox testnet balance and are not product limits. The per-rail cap is published in each amount field's description in the API reference.
🐛 Bug Fixes
- Compliance API — RFI submissions are no longer blocked by unrelated attestations. Submitting an RFI response previously returned a retryable
412when any attestation on the review was rejected or still validating, including types the RFI never requested and that cannot be re-uploaded through it. Both checks are now scoped to the attestation types the RFI names. - Payouts API —
TransactionInProgressErroris documented as409, not429. This error returned429from February 2026 until a change on 2026-05-04 set it to409 Conflict, so two errors would stop sharing one status code in the OpenAPI spec. The error reference was never updated and still said429. If you branch on429to detect a concurrent transaction on the same account, that branch stopped firing in May — switch it to409. A429from the API now means rate limiting and nothing else. The Errors reference is corrected and live.