Transfers, refunds, reversals, disputes, transfer groups, scheduled transfers, and wallet sweeps on the Moov platform.
Payment methods are auto-generated from linked funding sources (bank accounts, cards, wallets).
| Method | Funding source | Description |
|---|---|---|
moov-wallet | Moov wallet | Transfer from wallet balance |
ach-debit-fund | Verified bank account | Debit bank to fund wallet/payouts |
ach-debit-collect | Verified bank account | Debit bank for consumer/B2B payment |
card-payment | Card | Charge a credit or debit card |
apple-pay | Apple Pay | Accept Apple Pay |
pull-from-card | Debit/prepaid card | Pull funds from card |
| Method | Funding source | Description |
|---|---|---|
moov-wallet | Moov wallet | Credit wallet balance |
ach-credit-standard | Bank account | Credit bank (1-2 business days) |
ach-credit-same-day | Bank account | Credit bank (same day) |
instant-bank-credit | Bank account | Real-time credit via RTP/FedNow |
push-to-card | Debit/prepaid card | Instant credit to debit card |
When collecting funds, the destination (merchant) account needs the capability:
card-payment, apple-pay → destination needs collect-funds.card-paymentsach-debit-collect → destination needs collect-funds.achWhen sending funds, the source (sender) account needs the capability:
ach-credit-standard, ach-credit-same-day → source needs send-funds.achinstant-bank-credit → source needs send-funds.instant-bankpush-to-card → source needs send-funds.push-to-cardThe other party only needs the transfers capability (auto-enabled).
collect-funds.card-payments capabilitycard-payment source methodmoov-walletcollect-funds.ach capabilityach-debit-collect source methodmoov-walletsend-funds.ach capabilityach-credit-standard or ach-credit-same-day destinationmoov-walletsend-funds.push-to-card capabilitypush-to-card destination methodmoov-walletsend-funds.instant-bank capabilityinstant-bank-credit destination methodmoov-walletAlways check available payment rails before creating a transfer.
curl -X POST "https://api.moov.io/accounts/{accountID}/transfer-options" \
-H "Authorization: Bearer {token}" \
-H "x-moov-version: v2026.01.00" \
--data-raw '{
"amount": { "value": 5000, "currency": "USD" },
"source": { "accountID": "source-account-id" },
"destination": { "accountID": "destination-account-id" }
}'
curl -X POST "https://api.moov.io/accounts/{accountID}/transfers" \
-H "Authorization: Bearer {token}" \
-H "X-Idempotency-Key: {uuid}" \
-H "X-Wait-For: rail-response" \
-H "x-moov-version: v2026.01.00" \
--data-raw '{
"amount": { "value": 5000, "currency": "USD" },
"source": { "paymentMethodID": "source-pm-id" },
"destination": { "paymentMethodID": "dest-pm-id" },
"description": "Payment for order #123"
}'
// Go SDK
transfer, err := mc.CreateTransfer(ctx, moov.CreateTransfer{
Amount: moov.Amount{Value: 5000, Currency: "USD"},
Source: moov.CreateTransfer_Source{PaymentMethodID: sourcePmID},
Destination: moov.CreateTransfer_Destination{PaymentMethodID: destPmID},
Description: moov.String("Payment for order #123"),
}, moov.WithIdempotencyKey(uuid.New().String()),
moov.WithWaitForRailResponse())
// TypeScript SDK
const transfer = await moov.transfers.create({
accountID,
amount: { value: 5000, currency: "USD" },
source: { paymentMethodID: sourcePmID },
destination: { paymentMethodID: destPmID },
description: "Payment for order #123",
}, {
idempotencyKey: crypto.randomUUID(),
waitFor: "rail-response",
});
# Python SDK
transfer = client.transfers.create(
account_id=account_id,
amount={"value": 5000, "currency": "USD"},
source={"payment_method_id": source_pm_id},
destination={"payment_method_id": dest_pm_id},
description="Payment for order #123",
idempotency_key=str(uuid4()),
)
| Rail | Speed | Direction | Use case |
|---|---|---|---|
ach-debit-fund | 1-3 days | Pull from bank | Collect from merchants |
ach-debit-collect | 1-3 days | Pull from bank | Consumer/B2B collection |
ach-credit-standard | 1-2 days | Push to bank | Standard payouts |
ach-credit-same-day | Same day | Push to bank | Faster payouts |
instant-bank-credit | Seconds | Push to bank | Real-time (RTP/FedNow) |
push-to-card | Minutes | Push to card | Instant card payout |
moov-wallet | Instant | Wallet ↔ wallet | Internal transfers |
card-payment | Instant auth | Pull from card | Card acceptance |
created → pending → completed | failed | reversed
For transfer groups: created → queued → pending → completed | canceled
X-Idempotency-Key: {uuid} — Always include. Prevents duplicates.X-Wait-For: rail-response — Synchronous response. Without it, you get 202 Accepted.Use the reversals endpoint (POST /accounts/{accountID}/transfers/{transferID}/reversals) instead of the legacy refunds endpoint. Reversals are smarter — they automatically choose between canceling (if not yet settled) or refunding (if already settled), reducing processing costs.
curl -X POST "https://api.moov.io/accounts/{accountID}/transfers/{transferID}/reversals" \
-H "Authorization: Bearer {token}" \
-H "x-moov-version: v2026.01.00"
No request body needed. If the transfer hasn't settled, it's canceled instantly. If it has settled, a full refund is initiated.
curl -X POST "https://api.moov.io/accounts/{accountID}/transfers/{transferID}/reversals" \
-H "Authorization: Bearer {token}" \
-H "x-moov-version: v2026.01.00" \
--data-raw '{
"amount": { "value": 500, "currency": "USD" }
}'
Partial amounts always initiate a refund (partial cancellations are not supported).
initiated → confirmed → settled → completed (or failed)refund.created, refund.updated — refund status changescancellation.created, cancellation.updated — cancellation status changesDisputes (chargebacks) occur when a cardholder questions a payment with their card issuer. Moov handles the card network interaction — you respond through the API.
completed.| Phase | Description |
|---|---|
pre-dispute | Visa only (RDR) — can be auto-resolved before chargeback |
inquiry | Amex only — preliminary stage before formal chargeback |
chargeback | Active dispute, wallet already debited |
| Brand | Deadline |
|---|---|
| Visa | 6 calendar days |
| Mastercard | 14 calendar days |
| Discover | 14 calendar days |
| Amex | 10 calendar days |
If no response by deadline, Moov accepts the dispute on the merchant's behalf.
curl -X POST "https://api.moov.io/accounts/{accountID}/disputes/{disputeID}/accept" \
-H "Authorization: Bearer {token}" \
-H "x-moov-version: v2026.01.00"
This is final — cannot be undone.
# 1. Upload evidence file (PDF, JPG, TIFF — max 4 MB each)
curl -X POST "https://api.moov.io/accounts/{accountID}/disputes/{disputeID}/evidence-file" \
-H "Authorization: Bearer {token}" \
-H "x-moov-version: v2026.01.00" \
-F "[email protected]" \
-F "evidenceType=receipt"
# 2. Or upload text evidence
curl -X POST "https://api.moov.io/accounts/{accountID}/disputes/{disputeID}/evidence-text" \
-H "Authorization: Bearer {token}" \
-H "x-moov-version: v2026.01.00" \
--data-raw '{
"evidenceType": "cover-letter",
"text": "Customer received goods on March 15..."
}'
# 3. Submit all evidence (can only submit once per dispute)
curl -X POST "https://api.moov.io/accounts/{accountID}/disputes/{disputeID}/evidence/submit" \
-H "Authorization: Bearer {token}" \
-H "x-moov-version: v2026.01.00"
Evidence types: receipt, proof-of-delivery, cancelation-policy, terms-of-service, customer-communication, cover-letter, generic-evidence
| Status | Meaning |
|---|---|
response-needed | Default — merchant must accept or contest |
under-review | Evidence submitted, card network reviewing |
accepted | Merchant accepted liability |
won | Evidence compelling, funds credited back |
lost | Evidence insufficient |
expired | Response deadline passed |
closed | Issuer reversed chargeback |
resolved | No more action required |
GET /accounts/{accountID}/disputesGET /accounts/{accountID}/disputes/{disputeID}GET /accounts/{accountID}/disputes/{disputeID}/evidencedispute.created — new dispute receiveddispute.updated — dispute status changedDo not loop individual transfer creation to chain payments. Transfer groups let you associate multiple transfers and run them sequentially — e.g., Customer → Platform wallet → Service provider.
A child transfer references a parent transfer's ID as its source. Moov waits for the parent to complete before moving funds to the child's destination.
# Child transfer — references parent transferID as source
curl -X POST "https://api.moov.io/accounts/{accountID}/transfers" \
-H "Authorization: Bearer {token}" \
-H "X-Idempotency-Key: {uuid}" \
-H "x-moov-version: v2026.01.00" \
--data-raw '{
"amount": { "value": 4500, "currency": "USD" },
"source": { "transferID": "parent-transfer-id" },
"destination": { "paymentMethodID": "provider-pm-id" },
"description": "Provider payout for order #123"
}'
queued status, then pending when the parent completes.canceled. Funds stay at the last completed destination.transferID. Use as a filter on GET /accounts/{accountID}/transfers.Do not build your own scheduler. Moov has a native scheduling API that handles recurring transfers, future-dated payments, automatic card-on-file updates, and auto-receipts. This applies to both hosted and embedded integrations — scheduling is a server-side feature.
Use an RRULE string to define the recurrence pattern. Moov generates each future occurrence automatically.
curl -X POST "https://api.moov.io/accounts/{accountID}/schedules" \
-H "Authorization: Bearer {token}" \
-H "x-moov-version: v2026.01.00" \
--data-raw '{
"description": "Monthly subscription",
"recur": {
"recurrenceRule": "FREQ=MONTHLY;COUNT=36",
"runTransfer": {
"amount": { "currency": "USD", "amount": 1000 },
"accountID": "your-account-ID",
"source": { "paymentMethodID": "source-pm-id" },
"destination": { "paymentMethodID": "dest-pm-id" }
}
}
}'
Common RRULE patterns:
FREQ=MONTHLY;COUNT=12 — 12 monthly paymentsFREQ=WEEKLY;INTERVAL=2 — every 2 weeks, indefinitelyFREQ=MONTHLY;UNTIL=20271231T000000Z — monthly until end of 2027For irregular schedules or varying amounts, provide explicit dates:
curl -X POST "https://api.moov.io/accounts/{accountID}/schedules" \
-H "Authorization: Bearer {token}" \
-H "x-moov-version: v2026.01.00" \
--data-raw '{
"description": "Loan repayment",
"occurrences": [
{
"runOn": "2026-05-01T00:00:00Z",
"runTransfer": {
"amount": { "currency": "USD", "amount": 5000 },
"source": { "paymentMethodID": "source-pm-id" },
"destination": { "paymentMethodID": "dest-pm-id" }
}
},
{
"runOn": "2026-06-01T00:00:00Z",
"runTransfer": {
"amount": { "currency": "USD", "amount": 3000 },
"source": { "paymentMethodID": "source-pm-id" },
"destination": { "paymentMethodID": "dest-pm-id" }
}
}
]
}'
You can combine recur and occurrences in one schedule (e.g. a one-time setup fee plus monthly payments).
first-recurring or recurring.forScheduleID and Moov sends receipts for every future occurrence.GET /accounts/{accountID}/schedulesOnly the account that created the schedule can modify it. Transfers already created from a schedule won't be canceled by updating the schedule.
Do not build your own wallet-to-bank payout cron job. Moov sweeps automatically transfer wallet funds to a bank account on a daily schedule. This applies to both hosted and embedded integrations — sweeps are a server-side feature, not a UI choice.
POST /accounts/{accountID}/sweep-configsach-credit-same-day, ach-credit-standard, or rtp-credit| Method | When it arrives |
|---|---|
ach-credit-same-day | 6 PM ET same day |
ach-credit-standard | 10 AM ET next business day |
rtp-credit | Instant |
Sweeps are not processed on weekends or banking holidays — they accrue and pay out on the next business day.
If a wallet goes negative (from chargebacks, fees, etc.), Moov waits 1 day then initiates a debit from the linked bank account. No debit for amounts under $1.
sweepID. Query wallet transactions with sweepID to see subtotals grouped by transactionType (moov-fee, account-funding, etc.)sweep.updated webhook. Failed sweeps are not auto-retried. Sweep continues accruing with action-required status until a valid payment method is configured.GET /accounts/{accountID}/sweep-configs, PATCH /accounts/{accountID}/sweep-configs/{sweepConfigID}