Skip to content

Stablecoin payin API sandbox testing checklist: 20 cases before you go live

A payin API testing checklist with 20 sandbox cases: happy path, failed and refunded payins, duplicate webhooks, expired quotes, plus a go-live list.

To test a stablecoin payin API, run the happy path first. Then run every failure path: duplicate webhooks, delayed deposits, mismatched amounts, rejected KYC, wrong network, and expired quotes. After each case, confirm your ledger and customer state are still correct. BlindPay's development instances let you force most of these without real money.

This checklist covers the payin direction. For the general gap between sandbox and production, read stablecoin API sandbox vs production. For virtual accounts specifically, see how to test a virtual accounts API integration.

Key takeaways

  • Development payins complete about 30 seconds after creation and deliver the USDB test token. Amounts 66600 and 77700 force failed and refunded.
  • Some cases need fixtures, not the sandbox: late deposits and mismatched amounts cannot be forced.
  • Your webhook handler needs the most testing: replays, disorder, bad signatures, and 500s.
  • Test the write side too: quote expiry, idempotent retries, and the 40 requests per minute development limit.
  • The sandbox does not prove production timing. Plan one small supervised payin per rail.

What should I set up first?

Set up a development instance, an API key, and a webhook endpoint that logs everything before any business logic exists. Keys belong to one instance, and every request goes to https://api.blindpay.com, so the key alone decides the environment.

Register the endpoint with POST /v1/instances/{instance_id}/webhook-endpoints. An empty events array receives every event. Fetch the signing secret from the /secret route. The first working test is a payin that you can see arriving in your log with its svix-id, payin.new, and payin.complete events. The exact calls are in the integration quickstart.

Also create fixtures for what the sandbox cannot do: a payin that stays processing past its window, and a payin whose receiver_amount does not match what you expected. Save real payload shapes from the events dashboard and replay them against your handler.

Which test cases are required?

Run all twenty. Cases marked "fixture" cannot be forced in the sandbox, so inject the payload yourself.

#CaseStepsExpected resultPass criteria
1Happy path ACH payinCreate customer, wallet, quote, and payinCompletes after about 30 seconds, USDB delivered; memo_code shows <development>One credit, status completed, placeholder never shown to a payer
2Failed payinQuote with request_amount 66600payin.complete with failedPayment closed, no credit, no success message
3Refunded payinQuote with request_amount 77700payin.complete with refundedPayment closed as refunded, customer notified
4Duplicate deliveryReplay a payin.complete from the events dashboardSame svix-id arrives againExactly one credit
5Out-of-order eventFixture: send payin.update (processing) after completedEvent ignoredStatus stays completed
6Bad signatureSend a payload with a wrong svix-signatureRejected4xx response, no state change
7Stale timestampFixture: valid signature, timestamp older than 5 minutesRejected4xx response, no state change
8Handler returns 500Fail the handler once after verifyingBlindPay retries deliverySecond delivery processed once
9Expired quoteWait more than 5 minutes, then create the payinCreate is rejectedNew quote requested, user sees a clear retry
10Idempotent retryCreate a payin twice with one Idempotency-Key and one bodyStored response replays with Idempotency-Replayed: trueOne payin exists
11Changed body, same keyReuse the key with a different body422 idempotency_key_payload_mismatchError surfaced, no second payin
12In-flight duplicateSend the same keyed request twice at once409 idempotency_key_in_flight with Retry-AfterClient waits, then retries safely
13Rejected KYCCreate a customer with first name FailCustomer rejectedNo quote attempted, new customer path works
14Delayed depositFixture: payin in processing past its windowStuck-payin alert firesAlert reaches a human
15Mismatched amountFixture: ledger amount differs from receiver_amountReconciliation check flags itException queued with the payin id
16Wrong token or networkQuote USDT to a wallet on a network without itRequest rejectedError shown, no payin created
17Whole-unit ruleMXN quote with request_amount 10050request_amount_must_be_a_whole_currency_unitClient rounds or validates first
18Rate limitSend more than 40 requests in a minute429 development_instance_rate_limit_exceededClient backs off using Retry-After
19Virtual account depositCreate an account, then call simulate-spei-deposit on a SPEI CLABE accountNew payin, payin.new, mapped to the customerDeposit tied to the right customer_id
20Daily reconciliationList payins with limit, compare with ledgerZero unexplained differencesException queue empty or assigned

Case 16 is worth a note. A payin quote never takes a network, because BlindPay reads it from the wallet, and the token and network must be a supported pair. Read the error text instead of hardcoding rules. The deeper logic for cases 4 to 8 and 14 to 15 is in payin webhooks, idempotency, and reconciliation, and the failure behaviour is covered in failed, late, or mismatched stablecoin payins.

How do I test webhooks locally?

Expose your local handler on a public https URL, because BlindPay rejects local and private addresses and accepts only https endpoints. For a first look at payloads before you have a handler, point an endpoint at a temporary request logger such as webhook.cool.

Three habits make local testing reliable:

  1. Verify against the raw body. Parsing and re-serializing JSON changes the bytes and breaks the signature.
  2. Use the events dashboard on your development instance to inspect delivery attempts and response codes, and to replay any event. A replay resends the exact original payload with a new delivery attempt.
  3. Keep your test and production endpoints separate. The development webhook configuration does not carry over to production.

Webhooks behave identically in development and production: the same event names, payload shapes, and signatures. Signature rules are in the webhooks docs.

What should I monitor at launch?

Watch the state of payments, not only errors. In the first weeks, track:

  • Webhook non-2xx responses and signature failures
  • Payins in processing beyond the rail window (30 minutes for Pix, SPEI, Transfers, and PSE; 5 business days for ACH and wire)
  • Payins on_hold for more than 24 hours, because an unanswered request for information may end in a refund
  • Any terminal payin that changes state
  • Daily reconciliation exceptions
  • Share of quotes that expire before a payin is created

You can script these checks. The BlindPay CLI has blindpay payin_quotes create and blindpay payins create --quote-id qu_..., with --json output and exit codes 0 (success), 1 (user error), and 2 (API error), so a CI job can fail on a bad code. Agents connected to the MCP server can read payins with GetV1InstancesPayins and GetV1InstancesPayinsById. Point them at the read-only URL when they should only observe.

What belongs on the go-live checklist?

Copy this list into your release ticket.

  1. Production instance exists (it can take up to 3 business days to provision) and has its own API key.
  2. Real KYC documents are submitted for every customer; placeholder URLs removed.
  3. token changed from USDB to USDC or USDT, and networks changed from testnets to mainnets.
  4. Test amounts 66600 and 77700 removed from your code.
  5. A new webhook endpoint exists on the production instance, and its signing secret is stored.
  6. Signature check, svix-id dedupe, and forward-only status logic are tested (cases 4 to 8).
  7. Idempotency-Key sent on every create call.
  8. Stuck-payin, on-hold, and reconciliation alerts have an owner.
  9. Payer screens show real bank details, not <development>.
  10. One small supervised payin per rail has completed in production.

For tokens and networks, which blockchain network to use for payins helps with the choice.

Where does BlindPay fit?

BlindPay offers the pieces this checklist relies on: development instances with automatic KYC approval, a 30-second payin completion, forced outcomes at 66600 and 77700, a Fail name for KYC rejection, identical webhook behavior across environments, a replayable events dashboard, and idempotent create calls. Details are in the sandbox vs production docs.

The sandbox has limits. Real bank timing, real KYC review, and payer mistakes only appear in production, so keep the supervised first payin. BlindPay's pricing is a monthly plan plus per-transaction fees disclosed in the quote (see /pricing). To see how a vendor's tooling fits, start with what a stablecoin payin API is.

Sources

This article is for general information only and is not legal, tax, or financial advice.

FAQ

One API.
Multiple payment rails.

Blind Pay, Inc. (“BlindPay”) is a United States-based financial technology and payments infrastructure company, incorporated in the State of Delaware on May 2, 2024. BlindPay is duly registered as a Money Services Business (“MSB”) with the Financial Crimes Enforcement Network (“FinCEN”) under registration number 31000277566153. BlindPay is not a state-licensed money transmitter and does not, in its own capacity, engage in regulated money transmission services. All such regulated activities are conducted exclusively through, and under the licenses of, duly authorized financial institution partners. BlindPay's role is limited to providing financial technology, virtual account management, payment processing, and related payments infrastructure services that facilitate payment flows and account functionalities. These services are provided in coordination with its licensed partners and in compliance with applicable federal MSB requirements and relevant state regulatory frameworks.

Blind Pay, LLC (“BlindPay”) is a Delaware limited liability company formed on June 24, 2025. BlindPay is duly registered as a Money Services Business (“MSB”) with the Financial Crimes Enforcement Network (“FinCEN”) under registration number 31000318334247 and is listed in the Nationwide Multistate Licensing System (“NMLS”) under NMLS ID #2745309.

BLIND PAY SOCIEDADE PRESTADORA DE SERVIÇOS DE ATIVOS VIRTUAIS LTDA. (“BlindPay”) is a Virtual Asset Service Provider (“VASP”) operating in Brazil. The company is presently completing the regulatory adaptation process required of Virtual Asset Service Provider Companies (SPSAV) under Central Bank of Brazil Resolution No. 520/2025, and remains subject to the transitional regime set forth in Article 88 of that Resolution. Registered address: Avenida Princesa Isabel, nº 15, Sala 1405, Edifício Martinho de Freitas, Centro, Vitória/ES, 29010-361.

BlindPay is a stablecoin API that enables individuals and businesses to move money worldwide.