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

Your first sandbox payment

From a sandbox key to a settled payment and a signed webhook: the exact requests, and the responses the sandbox returned.

Start with step 1

Before you start

You need curl, an HTTPS address that can receive a POST for step 4, and a sandbox key from step 1. Every response below is the one the sandbox returned when these exact requests ran; IDs and times will differ on yours, and the secrets are placeholders.

fee_cents on a payment is SMP's fee, from the fee rules in force for your account (GET /v1/fees/schedule); in these examples it is worked out from example prices, not SMP's. The payer is debited exactly amount_cents; the payment pays you net_cents.

Nine steps

  1. Get a sandbox key

    Apply free at https://onboard.socialmatterspay.com/apply/. When you finish the first page (your business, and the one website or app you will use the API on), the page shows your sandbox key once, with a copy button: store it now, it is not shown again. The rest of the application can wait until you want to go live; Going live has the steps.

  2. Create the payer

    A payer is the person paying. There is one payer per email for your merchant account, so creating one for an email you already used returns the same payer with 200 instead of 201.

    Create a payer

    POST /v1/payers
    curl -X POST https://sandbox.socialmatterspay.com/v1/payers \
      -H 'Authorization: Bearer sk_sandbox_…' \
      -H 'Content-Type: application/json' \
      -d '{
      "email": "ana.lopez@example.com",
      "name": "Ana Lopez"
    }'
    The response · 201
    Response · 201
    HTTP 201
    Cache-Control: no-store
    
    {
      "data": {
        "id": "6427de75-801c-4ac6-95fa-870665d10af3",
        "object": "payer",
        "email": "ana.lopez@example.com",
        "name": "Ana Lopez",
        "phone": null,
        "created_at": "2026-10-28T00:22:35.474Z"
      }
    }

    Reference: Create the payer for an email, or return the existing one

  3. Link a sandbox bank account

    In the sandbox you can link a test bank account without a bank sign-in. available_balance_cents sets the balance the risk checks will see, so you can test a decline by setting it below the amount. Live accounts are linked through Plaid's bank sign-in instead (POST /v1/bank-accounts/link-token and POST /v1/bank-accounts/exchange).

    Link a sandbox test bank account

    POST /v1/bank-accounts/sandbox-link
    curl -X POST https://sandbox.socialmatterspay.com/v1/bank-accounts/sandbox-link \
      -H 'Authorization: Bearer sk_sandbox_…' \
      -H 'Content-Type: application/json' \
      -d '{
      "payer_email": "ana.lopez@example.com",
      "payer_name": "Ana Lopez",
      "available_balance_cents": 250000
    }'
    The response · 201
    Response · 201
    HTTP 201
    Cache-Control: no-store
    
    {
      "data": {
        "id": "1357923a-53e2-4aa9-a547-a20155759d6c",
        "object": "bank_account",
        "payer_id": "6427de75-801c-4ac6-95fa-870665d10af3",
        "account_type": "checking",
        "bank_name": "Plaid Checking (sandbox)",
        "last_four": "9606",
        "owner_name": "Ana Lopez",
        "link_method": "sandbox",
        "status": "verified",
        "identity_match_score": null,
        "signal_score": null,
        "verified_at": "2026-10-28T00:22:35.485Z",
        "disconnected_at": null,
        "is_tokenized": false,
        "item_health": "ok",
        "consent_expires_at": null,
        "disconnect_at": null,
        "debit_block": null,
        "owner_changed_from": null,
        "created_at": "2026-10-28T00:22:35.485Z",
        "available_balance_cents": 250000
      }
    }

    Reference: Sandbox only — link Plaid's documented test checking account without Plaid keys

  4. Subscribe to events

    Subscribe an HTTPS endpoint before you pay, so the payment's events reach it. The response carries the signing secret once; you need it to verify every delivery.

    Subscribe to events

    POST /v1/webhooks
    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": [
        "payment.authorized",
        "payment.settled",
        "payment.released",
        "payment.declined",
        "payment.returned",
        "payout.initiated",
        "payout.settled",
        "fee.assessed"
      ]
    }'
    The response · 201
    Response · 201
    HTTP 201
    Cache-Control: no-store
    
    {
      "data": {
        "id": "a4602568-d7c4-46ee-9f8b-b7d99c853837",
        "object": "webhook_subscription",
        "url": "https://northwind.example/smp/webhooks",
        "events": [
          "payment.authorized",
          "payment.settled",
          … 6 more
        ],
        "active": true,
        "site_id": null,
        "secret": "whsec_…",
        "created_at": "2026-10-28T00:22:34.449Z"
      }
    }

    Reference: Subscribe an HTTPS URL to events

  5. Show the payer the authorization

    Before a payer agrees to a debit taken on a website, show them the authorization: the exact words this call returns, in readable type, next to the button they press. They name your business, the amount and the last four digits of the account. Keep text_sha256: the payment sends it to prove which words were shown.

    The words to show the payer

    POST /v1/payments/authorization-text
    curl -X POST https://sandbox.socialmatterspay.com/v1/payments/authorization-text \
      -H 'Authorization: Bearer sk_sandbox_…' \
      -H 'Content-Type: application/json' \
      -d '{
      "bank_account_id": "1357923a-53e2-4aa9-a547-a20155759d6c",
      "amount_cents": 8400,
      "entry_code": "WEB"
    }'
    The response · 200
    Response · 200
    HTTP 200
    Cache-Control: no-store
    
    {
      "data": {
        "object": "payment_authorization_text",
        "text": "By completing this payment, you authorize Northwind Supply to initiate a one-time electronic debit of $84.00 from your bank account ending in 9606. You may revoke this authorization at any time by contacting Northwind Supply, with the understanding that it may take up to 3 business days to process.",
        "text_sha256": "85916f0096d185117093d29466e05b4a3a9baca8e4fc5b4bcfd467f691f035dc",
        "merchant_name": "Northwind Supply",
        "amount_cents": 8400,
        "amount_description": "$84.00",
        "entry_code": "WEB",
        "frequency": "single",
        "bank_account": {
          "id": "1357923a-53e2-4aa9-a547-a20155759d6c",
          "bank_name": "Plaid Checking (sandbox)",
          "last_four": "9606"
        },
        "ach_company": null
      }
    }

    Reference: The exact authorization words to show the payer before a debit

  6. Create the payment

    Send the bank account, the amount in cents, and an Idempotency-Key (your order number works well). For a payment taken on a website (entry_code WEB) also send the payer's IP address and browser from the checkout, and authorization_text_sha256 from step 5; without it the payment is refused with 422 authorization_required before anything is stored. The risk checks run before the bank is called: this payment passed them, so it came back submitted.

    Create a payment

    POST /v1/payments
    curl -X POST https://sandbox.socialmatterspay.com/v1/payments \
      -H 'Idempotency-Key: order_10482' \
      -H 'Authorization: Bearer sk_sandbox_…' \
      -H 'Content-Type: application/json' \
      -d '{
      "bank_account_id": "1357923a-53e2-4aa9-a547-a20155759d6c",
      "amount_cents": 8400,
      "payer_id": "6427de75-801c-4ac6-95fa-870665d10af3",
      "entry_code": "WEB",
      "external_order_id": "order_10482",
      "payer_ip": "203.0.113.7",
      "payer_user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 14_6) AppleWebKit/605.1.15 Safari/605.1.15",
      "metadata": {
        "cart_id": "c_7731"
      },
      "authorization_text_sha256": "85916f0096d185117093d29466e05b4a3a9baca8e4fc5b4bcfd467f691f035dc"
    }'
    The response · 201
    Response · 201
    HTTP 201
    Cache-Control: no-store
    
    {
      "data": {
        "id": "3c8029c9-00de-481f-aff2-4e80839dea08",
        "object": "payment",
        "status": "submitted",
        "amount_cents": 8400,
        "fee_cents": 109,
        "net_cents": 8291,
        "refunded_cents": 0,
        "currency": "USD",
        "entry_code": "WEB",
        "payer_id": "6427de75-801c-4ac6-95fa-870665d10af3",
        "bank_account_id": "1357923a-53e2-4aa9-a547-a20155759d6c",
        "statement_descriptor": "NORTHWIND",
        "external_order_id": "order_10482",
        "metadata": {
          "cart_id": "c_7731"
        },
        "risk_score": 65,
        "decline_reason": null,
        "decline_message": null,
        "bank_reference": "sbt_98eecba8-0048-4a1d-83c0-385f4ac6b04a",
        "payout_id": null,
        "return_id": null,
        "override_id": null,
        "site_id": null,
        "release_after": null,
        "created_at": "2026-10-28T00:22:35.514Z",
        "submitted_at": "2026-10-28T00:22:35.514Z",
        "settled_at": null,
        "released_at": null,
        "paid_out_at": null
      }
    }

    Reference: Authorize, then debit the payer's bank account

  7. Move the sandbox clock

    The sandbox bank settles a debit 60 seconds after it was submitted. Move the sandbox clock instead of waiting; anything due runs immediately.

    Move the sandbox clock 61 seconds

    POST /v1/sandbox/advance
    curl -X POST https://sandbox.socialmatterspay.com/v1/sandbox/advance \
      -H 'Authorization: Bearer sk_sandbox_…' \
      -H 'Content-Type: application/json' \
      -d '{
      "seconds": 61
    }'
    The response · 200
    Response · 200
    HTTP 200
    Cache-Control: no-store
    
    {
      "data": {
        "object": "sandbox_clock",
        "offset_seconds": 61,
        "now": "2026-10-28T00:23:36.567Z",
        "returns_processed": 0,
        "balances": {
          "settlement_cents": 8400,
          "merchant_balance_cents": 8051,
          "fee_revenue_cents": 349,
          "held_cents": 0,
          "pending_cents": 0,
          "reserve_held_cents": 0,
          "payable_cents": 8051
        }
      }
    }

    Reference: Move this merchant's sandbox clock forward, then run settlement and the return scan

  8. Read the payment

    The payment settled and was released at once, under this merchant's agreement. When an agreement holds a payment after it settles, it stays settled and release_after says when it will be released.

    Get a payment

    GET /v1/payments/3c8029c9-00de-481f-aff2-4e80839dea08
    curl https://sandbox.socialmatterspay.com/v1/payments/3c8029c9-00de-481f-aff2-4e80839dea08 \
      -H 'Authorization: Bearer sk_sandbox_…'
    The response · 200
    Response · 200
    HTTP 200
    Cache-Control: no-store
    
    {
      "data": {
        "id": "3c8029c9-00de-481f-aff2-4e80839dea08",
        "object": "payment",
        "status": "released",
        "amount_cents": 8400,
        "fee_cents": 109,
        "net_cents": 8291,
        "refunded_cents": 0,
        "currency": "USD",
        "entry_code": "WEB",
        "payer_id": "6427de75-801c-4ac6-95fa-870665d10af3",
        "bank_account_id": "1357923a-53e2-4aa9-a547-a20155759d6c",
        "statement_descriptor": "NORTHWIND",
        "external_order_id": "order_10482",
        "metadata": {
          "cart_id": "c_7731"
        },
        "risk_score": 65,
        "decline_reason": null,
        "decline_message": null,
        "bank_reference": "sbt_98eecba8-0048-4a1d-83c0-385f4ac6b04a",
        "payout_id": null,
        "return_id": null,
        "override_id": null,
        "site_id": null,
        "release_after": "2026-10-28T00:23:35.518Z",
        "created_at": "2026-10-28T00:22:35.514Z",
        "submitted_at": "2026-10-28T00:22:35.514Z",
        "settled_at": "2026-10-28T00:23:35.518Z",
        "released_at": "2026-10-28T00:23:36.559Z",
        "paid_out_at": null
      }
    }

    Reference: Get a payment

  9. Receive the signed event

    Your endpoint receives payment.settled, signed with the secret from step 4. Verify the signature before you trust the body; Signed webhooks has tested code for Node, PHP and Python. The example below was signed with the placeholder secret whsec_… shown in step 4.

    The delivery · payment.settled
    POST to your endpoint · payment.settled
    POST /smp/webhooks
    Content-Type: application/json
    User-Agent: SocialMatterPayments-Webhook/1.0
    X-SMP-Event: payment.settled
    X-SMP-Delivery-ID: 27a244be-357b-440f-941a-abc7bf5f9fee
    X-SMP-Timestamp: 1793146956
    X-SMP-Signature: 5d445074ffbd99d1df1f0ab4d4056746c1e8c79b1e436ce799eccd89027cdaed
    
    {
      "id": "27a244be-357b-440f-941a-abc7bf5f9fee",
      "event": "payment.settled",
      "created_at": "2026-10-28T00:23:36.559Z",
      "data": {
        "payment_id": "3c8029c9-00de-481f-aff2-4e80839dea08",
        "amount_cents": 8400,
        "fee_cents": 109,
        "net_cents": 8291,
        "settled_at": "2026-10-28T00:23:35.518Z",
        "release_after": "2026-10-28T00:23:35.518Z",
        "external_order_id": "order_10482"
      }
    }

Next

  • Make a return happen on purpose: amounts ending in .01 come back R01 after they settle. See the sandbox.
  • Pay out what was released: POST /v1/payouts/trigger.
  • Read Idempotency before you go live; every money-moving call needs a key.