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

The payment line

Every status a payment can hold, what moves it, and why it never moves backwards.

The line

Every payment holds exactly one status at a time and only ever moves forward. declined, returned, voided and refunded are final: nothing moves a payment out of them.

Authorizedchecks passedSubmittedsent to the bankSettledbank settled itReleasedper agreementPaid outin a payoutDeclinednever debited, never paidReturnedafter settlement · netted from the next payoutAuthorizedchecks passedSubmittedsent to the bankSettledbank settled itReleasedper agreementPaid outin a payoutDeclinednever debitedReturnednetted next payout
Main line: authorized → submitted → settled → released → paid out. Sidings: a declined payment is never sent to the bank; a returned debit is netted from your next payout.

Statuses

Every value of PaymentStatus in openapi.yaml.
StatusWhat it means
pending_authorizationCreated; the risk checks are running. You will rarely see it, because they finish inside the create request.
authorizedThe risk checks passed. The debit is about to be sent to the bank.
submittedThe debit was sent to the payer's bank. It can still be voided.
settledThe bank settled the debit and the money is on the ledger. Held until release_after if your agreement holds payments.
releasedCounted in your available balance; it goes out in your next payout.
declinedStopped by the risk checks. It was never sent to the bank. decline_reason is a fixed code and decline_message a sentence you can show the payer.
returnedThe payer's bank sent the debit back. Its amount comes off your next payout.
voidedYou cancelled it before the bank settled the debit.
refundedRefunded in full. Partial refunds leave the status as it was and raise refunded_cents.

Read every change a payment went through, with its time, from GET /v1/payments/{id}/history. Each move also sends a signed event.

Checked before any debit

A payment taken on a website or by phone (WEB, TEL) first needs the payer's authorization: the words from POST /v1/payments/authorization-text, shown before they agree, and the SHA-256 of exactly those words sent with the payment. Then the risk checks run inside the create request, before anything is sent to the payer's bank:

  • your per-payment, daily and monthly limits;
  • velocity: 3 payments per payer per hour, 5 per payer per day, $5,000 per payer per day, and 30 per merchant per minute;
  • the payer's available balance, wherever a live balance can be read;
  • your merchant account's return rates.

You can let one payer past the soft checks, such as the velocity limits or a weak name match, with POST /v1/payers/{id}/override. It never lifts your own limits, the unauthorized-return pause, a balance known to be short, or an unauthorized return by that payer.

While your return rates are at the critical level, a payment above $200 waits for SMP's review before any debit: it is answered 201 and stays pending_authorization until SMP approves it (payment.authorized follows) or declines it (payment.declined).

A payment the checks stop comes back with status declined, a fixed decline_reason code and a decline_message you can show the payer; the checks' own reasons, such as the payer's balance or history, are never sent. A declined payment is recorded so you can show it, but it is never sent to the bank and never paid. A payment that passes comes back submitted: the debit is on its way to the payer's bank.

Declined before any debit (balance below the amount)

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

{
  "data": {
    "id": "482e84e1-2393-4048-bde9-465edf0a38d1",
    "object": "payment",
    "status": "declined",
    "amount_cents": 8400,
    "fee_cents": 109,
    "net_cents": 8291,
    "refunded_cents": 0,
    "currency": "USD",
    "entry_code": "WEB",
    "payer_id": "500d25bc-a844-4e3c-a460-04e971508a0b",
    "bank_account_id": "33746dac-4666-4b2a-9c31-6d3ce13afdc5",
    "statement_descriptor": "NORTHWIND",
    "external_order_id": "order_10483",
    "metadata": null,
    "risk_score": 0,
    "decline_reason": "insufficient_funds",
    "decline_message": "The bank account does not have enough available to cover this payment.",
    "bank_reference": null,
    "payout_id": null,
    "return_id": null,
    "override_id": null,
    "site_id": null,
    "release_after": null,
    "created_at": "2026-10-28T00:22:35.538Z",
    "submitted_at": null,
    "settled_at": null,
    "released_at": null,
    "paid_out_at": null
  }
}

Void or refund

Until the bank settles the debit you can void the payment with POST /v1/payments/{id}/void; after that the void answers 409 too_late_to_void. Once it has settled you refund it instead, in full or in part, with POST /v1/payments/{id}/refund. Partial refunds raise refunded_cents and leave the status alone; the payment becomes refunded when the whole amount has been refunded. A refund larger than what remains answers 422 refund_exceeds_payment.

Refund part of a payment

POST /v1/payments/3c8029c9-00de-481f-aff2-4e80839dea08/refund
curl -X POST https://sandbox.socialmatterspay.com/v1/payments/3c8029c9-00de-481f-aff2-4e80839dea08/refund \
  -H 'Idempotency-Key: refund_order_10482_1' \
  -H 'Authorization: Bearer sk_sandbox_…' \
  -H 'Content-Type: application/json' \
  -d '{
  "amount_cents": 1200,
  "reason": "One item out of stock"
}'
The response · 201
Response · 201
HTTP 201
Cache-Control: no-store

{
  "data": {
    "id": "aa7af452-4b99-49a1-9c61-630bccadbb36",
    "object": "refund",
    "payment_id": "3c8029c9-00de-481f-aff2-4e80839dea08",
    "amount_cents": 1200,
    "reason": "One item out of stock",
    "status": "submitted",
    "failure_reason": null,
    "created_at": "2026-10-28T00:23:37.591Z",
    "settled_at": null
  }
}

What the payer's statement says

The payer's bank statement shows SMS* followed by your statement descriptor: up to 12 characters of letters, digits, spaces and . & -. Set a default when you apply, or send statement_descriptor on a payment.