> ## Documentation Index
> Fetch the complete documentation index at: https://docs.stableyard.fi/llms.txt
> Use this file to discover all available pages before exploring further.

# Platform tools

> Subscribe to payment, deposit and bank funding events, and rehearse every failure path in sandbox.

Money movement emits three webhook groups: `payments`, `deposits` and `bank_funding`. Delivery, signatures and retries are on [Webhooks](/webhooks); isolation and base URLs are on [Environments](/environments).

`GET /v2/partners/config` returns the machine-readable catalog under `capabilities.webhooks`, with `eventGroups`, a `recommendedEvents` subset and the delivery policy. Subscribe by group rather than by name, and ignore an unknown event name safely instead of throwing, because names are added over time.

## Act on each payment event

Every event is a prompt. Read `GET /v2/payments/{paymentId}` and act on what it returns.

| Event | What to do |
| - | - |
| `payment.created` | Record the payment id against your own reference. Nothing has moved |
| `payment.requires_action` | Read `nextAction` and surface it. It carries its own `expiresAt` |
| `payment.processing` | Funding or execution started. Credit nothing |
| `payment.accepted` | Funds are verified, settlement is not finished. Credit only if you decided verified receipt is enough |
| `payment.succeeded` | Value reached the destination. The safe point to credit |
| `payment.failed`, `payment.cancelled`, `payment.expired` | Terminal. Stop polling and release what you were holding |
| `payment.requires_intervention` | Hold and escalate. Read `operationalState` and `operationalReasonCode`; `status` is unchanged |
| `payment.duplicate_received` | A second valid transfer arrived. Credit once. The return is a recovery, not a reversal |
| `payment.late_received` | Funds arrived after the payment could be accepted. The terminal result stands |
| `payment.settlement_returned` | A delivered settlement came back. Reverse your credit. Nothing resends |
| `payment.refund_pending`, `payment.partially_refunded`, `payment.refunded` | Read `refundSummary`, then the linked `Refund` resources for detail |

## Act on deposit and bank funding events

`deposit.*` covers value arriving at a reusable deposit address. `bank_funding.*` covers value arriving through a [virtual account](/concepts/on-ramp-accounts); its payload carries the account, the facility, the transaction and the amounts, never bank details.

| Event | What to do |
| - | - |
| `deposit.detected` | Seen on chain. Credit nothing |
| `deposit.settled` | Complete. This is the completed-deposit event; there is no `deposit.completed` |
| `deposit.reversed` | A settled accounting record was invalidated. Reverse your credit. It does not imply an on-chain clawback |
| `deposit.requires_intervention` | Hold and escalate |
| `deposit.failed` | Terminal failure |
| `bank_funding.completed` | An incoming transfer was converted and delivered. Read the account's transactions for amounts and the on-chain hash |
| `bank_funding.failed` | The incoming transfer could not be converted |

<Note>
  The intermediate deposit states are not delivered to partner endpoints. If you need finer progress than detected, settled, reversed and requires\_intervention, poll `GET /v2/accounts/{accountId}/deposits` instead.
</Note>

## Rehearse every case in sandbox

Sandbox runs the same state machine and the same verification as production, against test networks. Have these in place first:

* A sandbox app credential, and the sandbox base URL.
* An endpoint that verifies signatures over the raw body, with delivery logs you can read.
* An account with an active settlement destination on a chain you will accept.
* `GET /v2/partners/config` read from sandbox, rather than a list copied from a page.

| Rehearse | Pass condition |
| - | - |
| The full path end to end | One credit, at the state you decided to credit on |
| The same create replayed with the same key | The same payment comes back and nothing moves twice |
| The same key with a changed body | `idempotency_conflict`, 409 |
| An unfunded payment left to expire | Nothing credits, and a fresh attempt is a new payment |
| The same webhook delivered twice | Exactly one business update |
| An invalid signature, and a stale timestamp | Both rejected |
| `accepted` observed without `succeeded` | Your credit rule behaves the way you decided it should |
| `requires_intervention` | The record goes on hold, an alert fires, nothing credits |
| A quote left to lapse | The stale option is replaced, not repriced after the fact |
| A refund on a completed payment | The refund is its own resource and the payment does not regress |

<Warning>
  One condition covers the whole table. An `accepted` or `succeeded` payment must never regress financially in your own records while operational recovery runs. If an operational field can move your record backwards, keep financial status and operational state in two columns and try again.
</Warning>

Run each case against the state your production code will actually be in. A case that passes because someone was watching the database is not a pass.

## A sandbox pass proves your code, not a live rail

* **Chain ids differ.** Sandbox runs test networks. An address or asset valid in one environment is not valid in the other, and a chain id must never be carried across.
* **Capabilities do not carry.** A capability proven in sandbox stays off in production until it is granted there. Read config with the production credential before you assume otherwise.
* **Accounts do not migrate.** Your first production call for a customer is a create.
* **Some corridors have no sandbox behind them.** Where a rail has no provider sandbox, the first production transfer is also the first real test of that corridor. Plan a supervised low-value transfer rather than a launch.
* **Virtual account issuance is certified on sandbox rather than proven in production.** See [On-ramp accounts](/concepts/on-ramp-accounts).

Ask which corridors and providers are live in which environment, and read the runtime answer for your own credential from `GET /v2/partners/config` at startup.

<Card title="Next: Webhooks" icon="bell" href="/webhooks">
  Signature verification, dedupe headers and retry behaviour.
</Card>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.