DRAFTThe sandbox is not live yet. Every example here was returned by the platform's code in a test run on 2026-10-28, priced with example fees: no fee amount in them is an SMP price. Paths and fields can change before launch. Live keys are issued only after our bank program is approved.Sandbox not live yet · examples from a test run on 2026-10-28 · example fees

Guide

Returns and payouts

What happens when a payer's bank sends a debit back, what SMP charges you, and how released money reaches your bank account.

Returns

After a debit settles, the payer's bank can still send it back with a return code: the account had too little money, was closed, or the payer says they did not authorize it. When the bank reports a return, SMP books it:

  • the payment's status becomes returned and a payment.returned event is sent;
  • a return object records the code, its category (nsf, admin or unauthorized) and the amount;
  • the return fee in force for your account is assessed and a fee.assessed event is sent; payment.returned carries it as return_fee_cents;
  • the amount and the fee come off your next payout. Your merchant_balance_cents can go below zero for a while; available_cents never does.

If SMP has turned Bounce Protection on for your account (an optional add-on, priced per account), a payment it covers that comes back R01 or R09 is paid back to you from SMP's reserve, up to the per-payment cap: payment.returned says covered: true and how much in covered_cents, and only the rest comes off your payout. The return fee is still charged. An unauthorized return is never covered.

Get a return

The response · 200
Response · 200
HTTP 200
Cache-Control: no-store

{
  "data": {
    "id": "cf78dfa0-3095-4c6b-aab7-e7fd7a67d3c0",
    "object": "return",
    "payment_id": "b17067cf-5562-4448-a039-3149a0ccd6cc",
    "amount_cents": 4200,
    "return_code": "R01",
    "return_reason": "Insufficient Funds",
    "category": "nsf",
    "netted": false,
    "netted_from_payout_id": null,
    "evidence_url": null,
    "covered": false,
    "covered_cents": 0,
    "external_order_id": "order_10485",
    "returned_at": "2026-10-28T00:24:38.640Z",
    "created_at": "2026-10-28T00:27:38.650Z"
  }
}

Fees and your statement

Every fee amount on this page comes from example prices, not SMP's.

SMP's fee on a payment is its fee_cents. It comes out of what settles: the payer is debited exactly amount_cents and the payment pays you net_cents. A declined or voided payment never settles, so its fee is never charged.

A fee charged outside a payment, such as the return fee, is a fee assessment. GET /v1/fees lists them, each with the rule that priced it and the payout that netted it; GET /v1/fees/schedule shows the rules in force for your account. A rule that is not active is never charged.

Fees charged outside a payment

The response · 200
Response · 200
HTTP 200
Cache-Control: no-store

{
  "data": [
    {
      "id": "fa:return:ret_sbt_e9fa3956-1381-4f03-9a17-50e7ff8ed218",
      "object": "fee_assessment",
      "code": "return",
      "amount_cents": 1200,
      "base_amount_cents": 4200,
      "rule": {
        "source": "schedule",
        "basis": "fixed",
        "bps": null,
        "fixed_cents": 1200,
        "min_cents": null,
        "max_cents": null
      },
      "payment_id": "b17067cf-5562-4448-a039-3149a0ccd6cc",
      "return_id": "cf78dfa0-3095-4c6b-aab7-e7fd7a67d3c0",
      "refund_id": null,
      "period": null,
      "netted": false,
      "netted_from_payout_id": null,
      "assessed_at": "2026-10-28T00:27:38.650Z"
    },
    {
      "id": "fa:payout.instant:7b6d615c-b239-44a0-b13d-fc2507da24ab",
      "object": "fee_assessment",
      "code": "payout.instant",
      "amount_cents": 110,
      "base_amount_cents": 10964,
      "rule": {
        "source": "schedule",
        "basis": "bps",
        "bps": 100,
        "fixed_cents": null,
        "min_cents": 25,
        "max_cents": null
      },
      "payment_id": null,
      "return_id": null,
      "refund_id": null,
      "period": null,
      "netted": true,
      "netted_from_payout_id": "7b6d615c-b239-44a0-b13d-fc2507da24ab",
      "assessed_at": "2026-10-28T00:24:38.631Z"
    },
    … 4 more
  ],
  "pagination": {
    "total": 6,
    "limit": 25,
    "offset": 0,
    "has_more": false
  }
}

GET /v1/statements/{month} gives one month line by line: each settled payment with its fee, each refund, payout, return and assessed fee, and the balance after each.

This month's statement

The response · 200
Response · 200
HTTP 200
Cache-Control: no-store

{
  "data": {
    "object": "statement",
    "month": "2026-10",
    "period_start": "2026-10-01T00:00:00.000Z",
    "period_end": "2026-11-01T00:00:00.000Z",
    "opening_balance_cents": 0,
    "closing_balance_cents": -5400,
    "fees": {
      "per_payment_cents": 176,
      "assessed": [
        {
          "code": "bank_verification",
          "count": 2,
          "cents": 200
        },
        {
          "code": "merchant.batch",
          "count": 1,
          "cents": 40
        },
        … 3 more
      ],
      "assessed_cents": 1570
    },
    "bounce_protection": {
      "fees_cents": 0,
      "covers_cents": 0
    },
    "lines": [
      {
        "at": "2026-10-28T00:22:35.486Z",
        "type": "fee_assessed",
        "description": "Fee bank_verification: 100 cents",
        "credit_cents": 0,
        "debit_cents": 100,
        "balance_after_cents": -100,
        "payment_id": null,
        "payout_id": null,
        "return_id": null,
        "refund_id": null,
        "fee_assessment_id": "fa:bank_verification:1357923a-53e2-4aa9-a547-a20155759d6c",
        "fee_collection_id": null,
        "invoice_id": null,
        "fee_code": "bank_verification"
      },
      {
        "at": "2026-10-28T00:22:35.532Z",
        "type": "fee_assessed",
        "description": "Fee bank_verification: 100 cents",
        "credit_cents": 0,
        "debit_cents": 100,
        "balance_after_cents": -200,
        "payment_id": null,
        "payout_id": null,
        "return_id": null,
        "refund_id": null,
        "fee_assessment_id": "fa:bank_verification:33746dac-4666-4b2a-9c31-6d3ce13afdc5",
        "fee_collection_id": null,
        "invoice_id": null,
        "fee_code": "bank_verification"
      },
      … 9 more
    ],
    "fee_collections": []
  }
}

What payouts can't cover

Fees and returns come off your payouts first. What they can't cover, such as a balance gone negative after returns, is debited from your payout account on your payout day, under an authorization you accept once: GET /v1/fee-debit-authorization gives the exact words and PUT /v1/fee-debit-authorization records your signer's acceptance. GET /v1/fee-collections lists those debits. A debit returned for insufficient or uncollected funds is tried again for the same amount, at most twice. Any other return ends the authorization, and an unauthorized one also suspends the merchant account.

Debits from your own account

The response · 200
Response · 200
HTTP 200
Cache-Control: no-store

{
  "data": [
    {
      "id": "fc_d7dfee96-ee3a-4a4b-96f5-bb17919f1b76",
      "object": "fee_collection",
      "status": "submitted",
      "amount_cents": 3198,
      "entry_code": "CCD",
      "same_day": true,
      "attempt_kind": "initial",
      "reinitiates_collection_id": null,
      "return_code": null,
      "failure_reason": null,
      "created_at": "2026-11-03T15:00:00.778Z",
      "submitted_at": "2026-11-03T15:00:00.778Z",
      "settled_at": null,
      "returned_at": null
    }
  ],
  "pagination": {
    "total": 1,
    "limit": 25,
    "offset": 0,
    "has_more": false
  }
}

Evidence for unauthorized returns

When a payer says a debit was not authorized, the return gets an evidence packet: the return, the payment, the authorization the payer agreed to (its exact words, time, IP address and browser), and the bank account's details. Fetch it with GET /v1/returns/{id}/evidence. Returns in other categories have none and answer 404.

An unauthorized return's evidence packet

The response · 200
Response · 200
HTTP 200
Cache-Control: private, no-store

{
  "return": {
    "id": "e1c07144-04d7-4196-9b40-4d528eb48f74",
    "code": "R10",
    "reason": "Customer Advises Not Authorized",
    "returned_at": "2026-10-28T00:23:38.732Z"
  },
  "payment": {
    "id": "3078ebdd-da4d-492a-9050-f2bcc55a14ea",
    "amount_cents": 3300,
    "entry_code": "WEB",
    "statement_descriptor": "LAKESIDE",
    "external_order_id": "order_20311",
    "created_at": "2026-10-28T00:22:37.714Z",
    "settled_at": "2026-10-28T00:23:37.717Z"
  },
  "authorization": {
    "authorization_text": "By completing this payment, you authorize Lakeside Outfitters to initiate a one-time electronic debit of $33.00 from your bank account ending in 9606. You may revoke this authorization at any time by contacting Lakeside Outfitters, with the understanding that it may take up to 3 business days to process.",
    "ip_address": "203.0.113.7",
    "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 14_6) AppleWebKit/605.1.15 Safari/605.1.15",
    "consent_timestamp": "2026-10-28T00:22:37.714Z",
    "entry_code": "WEB",
    "frequency": "one_time",
    "expires_at": "2028-10-27T12:22:37.714Z"
  },
  "bank_account": {
    "last_four": "9606",
    "owner_name": "Riley Ng",
    "link_method": "sandbox",
    "identity_match_score": null,
    "verified_at": "2026-10-28T00:22:37.706Z"
  }
}

Return rates

SMP measures your return rates every day on Nacha's 60-day method: the returns of the last 60 days against the debits sent to the bank in them, for unauthorized returns, administrative returns (R02, R03, R04) and all returns. GET /v1/returns/summary shows yours.

  • Unauthorized returns at 0.3% of your debits suspend your merchant account at once: new payments and payouts are refused with 403 forbidden, while refunds and voids still work.
  • At the critical level your per-payment and daily limits are halved, and every payment above $200 waits for SMP's review.
  • At Nacha's own limits (0.5% unauthorized, 3% administrative, 15% of all debits) your account is suspended.

With fewer than 20 debits in the 60 days, one return is a large share, so the number of returns sets a step instead: one return sends a warning email, two halve your limits, three pause new payments. Each step lifts on its own as returns age past 60 days. An unauthorized return still suspends the account at any volume.

Return codes

Generated from the return-code table the engine itself uses.
CodeMeaningCategoryWhat to do
R01Insufficient FundsnsfAsk the customer to pay again with a new payment once the funds are there; SMP does not re-present a returned debit
R02Account ClosedadminRequest new bank account from customer
R03No Account/Unable to LocateadminVerify account number with customer
R04Invalid Account NumberadminRe-link bank account via Plaid
R05Unauthorized Debit (Corporate)unauthorizedEvidence packet — verify authorization was obtained
R07Authorization RevokedunauthorizedDo not re-debit. Evidence packet if disputed.
R08Payment StoppedadminContact customer to resolve
R09Uncollected FundsnsfAsk the customer to pay again with a new payment once the deposit has cleared; SMP does not re-present a returned debit
R10Customer Advises Not AuthorizedunauthorizedEvidence packet — identity match and the authorization record with its exact words
R11Customer Advises Entry Not in Accordance with the Terms of the AuthorizationunauthorizedEvidence packet — show the debit matched the authorization; do not re-debit without a corrected authorization
R16Account FrozenadminRequest alternative payment method
R20Non-Transaction AccountadminRequest checking account instead
R29Corporate Customer Not AuthorizedunauthorizedEvidence packet. Verify authorization with corporate customer.
R51Item Related to RCK Entry is IneligibleunauthorizedDo not re-present

Payouts

A payout sends your released balance to the bank account on your merchant account, net of returns and fees not yet netted. Payouts run on the schedule SMP sets for your account: every Fed business day, weekly or every two weeks on a weekday (Tuesday unless set otherwise), monthly on the 1st, or only when you ask. A payout day on a weekend or a Fed holiday goes out on the next Fed business day; GET /v1/payouts/settings shows yours. An early payout now ("Pay me now"), with POST /v1/payouts/trigger and an Idempotency-Key, is off until SMP turns it on for your account, and it carries the early payout fee in your fee schedule. On the only-when-you-ask schedule, a payout you ask for carries no fee. Each payout lists how many payments it includes and how much it netted for returns and for fees, and sends payout.initiated, then payout.settled or payout.failed.

Pay out the available balance now

The response · 201
Response · 201
HTTP 201
Cache-Control: no-store

{
  "data": {
    "id": "7b6d615c-b239-44a0-b13d-fc2507da24ab",
    "object": "payout",
    "status": "submitted",
    "amount_cents": 10964,
    "fee_cents": 110,
    "net_cents": 10854,
    "returns_netted_cents": 0,
    "fees_netted_cents": 370,
    "fees_included": 5,
    "method": "ach_credit",
    "trigger": "manual",
    "payments_included": 2,
    "returns_included": 0,
    "period_start": "2026-10-28T00:22:34.395Z",
    "period_end": "2026-10-28T00:24:38.631Z",
    "initiated_at": "2026-10-28T00:24:38.631Z",
    "settled_at": null,
    "failed_reason": null
  }
}

Holds

Every day SMP reconciles its ledger with the bank's, to the cent. Any difference puts payouts on hold until it is resolved; while a hold is on, a payout answers 422 payout_held and payout_hold on your balance says why.

SMP staff can also keep part of your balance back as a reserve, or delay when your payments are released. Neither is ever set automatically: each is recorded with who set it and why, and your balance shows what a reserve holds in reserve_held_cents.

Balance after the return

The response · 200
Response · 200
HTTP 200
Cache-Control: no-store

{
  "data": {
    "object": "balance",
    "available_cents": 0,
    "merchant_balance_cents": -5400,
    "held_cents": 0,
    "reserve_held_cents": 0,
    "pending_cents": 0,
    "unnetted_return_cents": 4200,
    "unnetted_fee_cents": 1200,
    "pending_payout_cents": 0,
    "payout_hold": {
      "active": false
    },
    "currency": "USD",
    "as_of": "2026-10-28T00:22:36.681Z"
  }
}