Ledger endpoints

Each call is an HTTPS POST with a JWE envelope. Authorize places a hold; that hold then ends in capture or release.

Field-by-field claims are in the API reference: authorize, capture, release, credit account. A paid request is the other direction: credit books a deposit after money is already in your wallet.

Authorize #

Called when a user initiates a payment. You decide whether to place a hold on their funding source. Claims: authorize.

The request claims include the payout ID, your own externalID for the sender (so you can resolve them without Moov’s participant IDs), fundingSource (the providerSourceID you registered for the account to hold against), the amount, and a fraudScore from 0.0 to 1.0, where higher means riskier. You may factor the score into your decision, for example requiring step-up authentication above a threshold. How that score is produced, and when a payment is held for review instead, is in trust & safety.

amount is a decimal string plus a currency descriptor. Scale by currency.decimalPlaces into minor units; never parse value as a float:

{ "value": "100.00", "currency": { "code": "USD", "decimalPlaces": 2 } }

Authorize may also carry callerSubject and requestID. Both are audit-only trace values; this requestID is not a request for payment.

Outcomes on 200 OK:

OutcomeMeaningYou must return
approvedHold placedholdReference, your ledger’s reference for the hold
deniedYou declined: insufficient funds, risk rules, step-up requiredreason

Moov supplies your holdReference back to you on the later capture or release call for the same payout.

Do not return 200 with any other outcome value to signal a processing failure. Moov Money treats unmodeled outcomes as an internal unknown result and discards your reason. If your ledger is unavailable, return a retryable HTTP status (408, 429, or 5xx) instead.

Capture #

Called after the recipient completes their claim onto a debit card, Apple Pay, or Google Pay. You settle the hold, debiting the sender so you can originate the push-to-card payment. See flow of funds. Claims: capture.

The request carries the holdReference you returned on authorize. Capture has no denied outcome. Either you captured the hold or you did not:

OutcomeMeaningYou must return
approvedHold captured, funds movedcaptureReference
failedYour ledger could not capture the holdreason

Two capture-specific rules:

  • Already-captured holds must return approved. A repeat capture of the same holdReference, whether or not the idempotency key matches, must return approved, reusing the original captureReference if you can look it up.
  • Unknown holds must return approved. If a holdReference has aged out of your records entirely, still return approved. Moov Money treats unknown holds as already captured; the alternative would strand funds in flight. If this doesn’t fit your ledger model, escalate to Moov before implementing.

Release #

Called when a payment is canceled or its 10-day claim window expires. You release the hold, returning funds to the sender. Claims: release.

The request carries the holdReference plus a non-normative reason, with values like cancelled (user-initiated) and expired (hold time to live exceeded) so you can distinguish them in your ledger.

OutcomeMeaningYou must return
approvedHold releasedreleaseReference
failedYour ledger could not release the holdreason

Releasing an already-released hold must return approved, reusing the original releaseReference when you can.

Credit #

Called after a request has been paid and the funds are in your wallet (the request is funded). You book a deposit to the requester. Same JWE envelope as authorize. Claims: credit account.

The request carries requestID (the request-for-payment, not a payout ID), requesterExternalID, fundingDestination (opaque token for where the deposit lands), the amount, and an idempotencyKey. Deduplicate on that key so a retry never double-posts. The key’s scope is one disbursement attempt.

Outcomes on 200 OK:

OutcomeMeaningYou must return
approvedDeposit postedcreditReference, your ledger’s reference for the credit
destination_unavailableThis destination cannot receive it (closed or invalid account). Retryable.reason
refusedYou refuse the deposit itself. Terminal; Moov begins reversal.reason

Do not return 200 with unknown or any other unmodeled value. Moov synthesizes unknown for timeouts and unrecognized outcomes; if your ledger is down, return 408, 429, or a 5xx so Moov retries the same idempotencyKey. Other 4xx are terminal.

Repeating an approved credit with the same key must return approved and the original creditReference.

Card-funded programs skip this callback: the requester is credited by an OCT to their FI-issued card instead. See flow of funds.

Every response, every time #

Regardless of endpoint or outcome:

  • Echo the request’s idempotencyKey (under moov) exactly. Moov rejects the response if it doesn’t match.
  • Omit the reference field (holdReference, captureReference, releaseReference, creditReference) on any non-approved outcome.
  • Put iat and exp at the top of the response JWT, not inside moov.
  • Include a human-readable reason for any non-approved outcome (denied, failed, destination_unavailable, refused).

Next steps #