Paid by push, matched by account
A debit pulls money from the payer's bank, within your per-payment limits. An invoice works the other way round: the customer sends the money from their own bank, by ACH credit or instant payment, to an account number that belongs to that one invoice. No debit limit applies, and the money that lands in that account is matched to the invoice: part of it, all of it, or more.
Create an invoice
Call POST / with an Idempotency-Key, the customer, the amount and a due date of today or later. Line items are optional; when you send them they must add up to amount_cents.
The response carries payment_instructions: the invoice's own account and routing number. Put them on the invoice you send. The full account number is returned here and by GET / only; lists show its last four digits.
Invoice a business customer
curl -X POST https://sandbox.socialmatterspay.com/v1/invoices \
-H 'Idempotency-Key: inv_2026_0412' \
-H 'Authorization: Bearer sk_sandbox_…' \
-H 'Content-Type: application/json' \
-d '{
"customer_name": "Acme Wholesale Inc",
"customer_email": "ap@acme.example",
"amount_cents": 1850000,
"due_date": "2026-11-27",
"description": "October shop supplies",
"external_id": "INV-2026-0412",
"line_items": [
{
"description": "Shelving units",
"quantity": 40,
"unit_price_cents": 42500
},
{
"description": "Delivery and installation",
"quantity": 1,
"unit_price_cents": 150000
}
]
}'
The response · 201
HTTP 201
Cache-Control: no-store
{
"data": {
"id": "69fcf9e0-a58f-4891-ac46-3f2a615e070d",
"object": "invoice",
"status": "sent",
"amount_cents": 1850000,
"paid_cents": 0,
"remaining_cents": 1850000,
"overpaid_cents": 0,
"currency": "USD",
"customer_name": "Acme Wholesale Inc",
"customer_email": "ap@acme.example",
"due_date": "2026-11-27",
"description": "October shop supplies",
"line_items": [
{
"description": "Shelving units",
"quantity": 40,
"unit_price_cents": 42500
},
{
"description": "Delivery and installation",
"quantity": 1,
"unit_price_cents": 150000
}
],
"external_id": "INV-2026-0412",
"funds": {
"received_cents": 0,
"booked_cents": 0,
"held_at_bank_cents": 0,
"status": "none"
},
"virtual_account_last_four": "6252",
"paid_at": null,
"cancelled_at": null,
"overdue_at": null,
"created_at": "2026-10-28T00:27:40.662Z",
"payment_instructions": {
"account_number": "9434316252",
"routing_number": "110000000",
"account_type": "checking",
"reference": "69fcf9e0-a58f-4891-ac46-3f2a615e070d"
}
}
}
How it gets paid
SMP reads every invoice's account every 10 minutes, and GET / reads it first, so money that just landed shows at once. What lands moves the invoice on:
| Status | What it means |
|---|---|
sent | Open, with nothing received yet. |
partially_paid | Some money has landed in its account; remaining_cents is still owed. |
paid | What landed covers amount_cents; anything over it shows as overpaid_cents. |
overdue | Past due_date with money still owed. Set once; money that lands later moves it on. |
cancelled | You cancelled it before anything was paid. Money that lands afterwards is still recorded on it. |
Each step sends an event: invoice.partially_paid, invoice.paid and, once, invoice.overdue. Subscribe to them with POST /. The first two say how much arrived (received_now_cents) and what is still owed (remaining_cents). Money the customer sends after the invoice is paid is recorded and booked like the rest, and invoice.paid comes again with received_now_cents and overpaid_cents, so you can send the extra back.
Subscribe to invoice events
curl -X POST https://sandbox.socialmatterspay.com/v1/webhooks \
-H 'Authorization: Bearer sk_sandbox_…' \
-H 'Content-Type: application/json' \
-d '{
"url": "https://northwind.example/smp/webhooks",
"events": [
"invoice.paid",
"invoice.partially_paid",
"invoice.overdue"
]
}'
The delivery · invoice.partially_paid
POST /smp/webhooks
Content-Type: application/json
User-Agent: SocialMatterPayments-Webhook/1.0
X-SMP-Event: invoice.partially_paid
X-SMP-Delivery-ID: 82ccb661-72a4-4bed-b2b9-936f386d0b0a
X-SMP-Timestamp: 1793146959
X-SMP-Signature: 13f51566ca8195bffb5bdbc425b6b90c895bde69270d8387f43741781a330391
{
"id": "82ccb661-72a4-4bed-b2b9-936f386d0b0a",
"event": "invoice.partially_paid",
"created_at": "2026-10-28T00:28:41.680Z",
"data": {
"invoice_id": "69fcf9e0-a58f-4891-ac46-3f2a615e070d",
"status": "partially_paid",
"amount_cents": 1850000,
"paid_cents": 1000000,
"received_now_cents": 1000000,
"remaining_cents": 850000,
"overpaid_cents": 0,
"held_at_bank_cents": 1000000,
"external_id": "INV-2026-0412"
}
}
The delivery · invoice.overdue
POST /smp/webhooks
Content-Type: application/json
User-Agent: SocialMatterPayments-Webhook/1.0
X-SMP-Event: invoice.overdue
X-SMP-Delivery-ID: 2b9f8be4-5783-4be9-abb9-bcb5e768f136
X-SMP-Timestamp: 1793146959
X-SMP-Signature: 8262733aa34e839cc782ba7055708e4bcc9a3b0178950bb872aa2a80d26284fd
{
"id": "2b9f8be4-5783-4be9-abb9-bcb5e768f136",
"event": "invoice.overdue",
"created_at": "2026-10-30T00:28:41.718Z",
"data": {
"invoice_id": "9d34a1e9-c788-4301-8025-1f403666ff5e",
"amount_cents": 120000,
"paid_cents": 0,
"due_date": "2026-10-28",
"external_id": "INV-2026-0414"
}
}
Where the money is
Money the customer sends stays in the invoice's account at the bank until it is booked into your balance. Until then it is not in your balance and not in a payout. funds on every invoice says how much was received, how much was booked and how much is still held at the bank.
Partly paid, the money held at the bank
The response · 200
HTTP 200
Cache-Control: no-store
{
"data": {
"id": "69fcf9e0-a58f-4891-ac46-3f2a615e070d",
"object": "invoice",
"status": "partially_paid",
"amount_cents": 1850000,
"paid_cents": 1000000,
"remaining_cents": 850000,
"overpaid_cents": 0,
"currency": "USD",
"customer_name": "Acme Wholesale Inc",
"customer_email": "ap@acme.example",
"due_date": "2026-11-27",
"description": "October shop supplies",
"line_items": [
{
"description": "Shelving units",
"quantity": 40,
"unit_price_cents": 42500
},
{
"description": "Delivery and installation",
"quantity": 1,
"unit_price_cents": 150000
}
],
"external_id": "INV-2026-0412",
"funds": {
"received_cents": 1000000,
"booked_cents": 1000000,
"held_at_bank_cents": 0,
"status": "booked"
},
"virtual_account_last_four": "6252",
"paid_at": null,
"cancelled_at": null,
"overdue_at": null,
"created_at": "2026-10-28T00:27:40.662Z",
"payment_instructions": {
"account_number": "9434316252",
"routing_number": "110000000",
"account_type": "checking",
"reference": "69fcf9e0-a58f-4891-ac46-3f2a615e070d"
}
}
}
Cancel an invoice
Cancel an invoice nothing has been paid on with POST /; once money has landed, cancelling answers 422. If the customer still sends money to a cancelled invoice, it is recorded on the invoice, which stays cancelled and sends no event, so you can see it and send it back.
Cancel an unpaid invoice
The response · 200
HTTP 200
Cache-Control: no-store
{
"data": {
"id": "9e80b109-af15-4764-9a39-0d09aa053140",
"object": "invoice",
"status": "cancelled",
"amount_cents": 64000,
"paid_cents": 0,
"remaining_cents": 64000,
"overpaid_cents": 0,
"currency": "USD",
"customer_name": "Acme Wholesale Inc",
"customer_email": "ap@acme.example",
"due_date": "2026-11-27",
"description": null,
"line_items": null,
"external_id": "INV-2026-0413",
"funds": {
"received_cents": 0,
"booked_cents": 0,
"held_at_bank_cents": 0,
"status": "none"
},
"virtual_account_last_four": "8494",
"paid_at": null,
"cancelled_at": "2026-10-28T00:28:41.700Z",
"overdue_at": null,
"created_at": "2026-10-28T00:28:41.695Z"
}
}
In the sandbox
Play the customer with POST /. An ACH credit lands after the sandbox settle delay, so move the clock with POST / and read the invoice; an instant payment lands at once.
The customer sends part by ACH
curl -X POST https://sandbox.socialmatterspay.com/v1/sandbox/invoices/69fcf9e0-a58f-4891-ac46-3f2a615e070d/push \
-H 'Authorization: Bearer sk_sandbox_…' \
-H 'Content-Type: application/json' \
-d '{
"amount_cents": 1000000,
"rail": "ach"
}'
The response · 202
HTTP 202
Cache-Control: no-store
{
"data": {
"object": "sandbox_incoming_credit",
"invoice_id": "69fcf9e0-a58f-4891-ac46-3f2a615e070d",
"amount_cents": 1000000,
"rail": "ach",
"bank_status": "pending",
"lands_at": "2026-10-28T00:28:40.666Z",
"invoice": {
"id": "69fcf9e0-a58f-4891-ac46-3f2a615e070d",
"object": "invoice",
"status": "sent",
"amount_cents": 1850000,
"paid_cents": 0,
"remaining_cents": 1850000,
"overpaid_cents": 0,
"currency": "USD",
"customer_name": "Acme Wholesale Inc",
"customer_email": "ap@acme.example",
"due_date": "2026-11-27",
"description": "October shop supplies",
"line_items": [
{
"description": "Shelving units",
"quantity": 40,
"unit_price_cents": 42500
},
{
"description": "Delivery and installation",
"quantity": 1,
"unit_price_cents": 150000
}
],
"external_id": "INV-2026-0412",
"funds": {
"received_cents": 0,
"booked_cents": 0,
"held_at_bank_cents": 0,
"status": "none"
},
"virtual_account_last_four": "6252",
"paid_at": null,
"cancelled_at": null,
"overdue_at": null,
"created_at": "2026-10-28T00:27:40.662Z"
}
}
}
