Quickstart
Get from zero to a stablecoin payment and verified webhook in ten minutes.
1. Install the SDKs
pnpm add @stableops/api-sdk @stableops/wallet-sdkThe API SDK is plain TypeScript with no runtime dependencies beyond Node's
crypto. The wallet SDK runs in the browser and asks the user's wallet to send
the on-chain transfer.
2. Configure your server client
import { StableOps } from '@stableops/api-sdk'
const client = new StableOps({
apiKey: process.env.STABLEOPS_API_KEY!,
environment: 'sandbox', // Sandbox is the default. Switch to "live" only after test.
})Do not expose STABLEOPS_API_KEY in the browser. Create payment orders and call
merchant APIs from your server.
3. Prepare in the Dashboard
Before you create your first order, complete two setup steps in the Dashboard:
- Import receiving addresses: add the on-chain addresses you accept. StableOps allocates one address from this pool for each payment order.
- Register a webhook endpoint: enter your callback URL, for example
https://your-app.example.com/hooks/stableops.
Webhook secrets are only shown when created or rotated. Store the secret in a
server-side environment variable such as STABLEOPS_WEBHOOK_SECRET. For
automation, use the Addresses API and
Webhook Endpoints API.
4. Create a payment order
const order = await client.paymentOrders.create(
{
merchantOrderId: 'sub_89231_2026_06',
amount: '49.00',
settlementAsset: 'USDC',
acceptedAssets: [
{ chain: 'base-sepolia', asset: 'USDC' },
{ chain: 'ethereum-sepolia', asset: 'USDC' },
],
// Auto-expire after 30 minutes; the order moves to `expired` and the address is released.
expiresAt: new Date(Date.now() + 30 * 60 * 1000).toISOString(),
metadata: { customerId: 'cus_9821', plan: 'pro_monthly' },
},
{ idempotencyKey: crypto.randomUUID() },
)
console.log(order.paymentInstructions)
// [
// { chain: 'base-sepolia', asset: 'USDC', address: '0x...' },
// { chain: 'ethereum-sepolia', asset: 'USDC', address: '0x...' },
// ]Return only the order id, amount, and paymentInstructions to your frontend.
5. Pay with the wallet SDK
After the frontend receives the order from your server, use the wallet SDK to ask the browser wallet to send the transfer:
import {
getInjectedWalletProviders,
selectWalletPaymentInstruction,
sendWalletPayment,
} from '@stableops/wallet-sdk'
const { instruction, provider } = selectWalletPaymentInstruction(
order.paymentInstructions,
getInjectedWalletProviders(),
)
const sent = await sendWalletPayment({
provider,
amount: order.amount,
instruction,
})
console.log(sent.txHash)This example picks a payable instruction from the wallets currently available in the browser. For TRON, Solana, or a custom multi-chain selector, see the Wallet SDK. Once the transfer is on-chain, StableOps scanners match the deposit address and dispatch webhooks as the order state changes.
The wallet SDK is a convenience, not a requirement. The payer can settle this transfer any way they like — sending manually from MetaMask / Phantom / TronLink, withdrawing from an exchange, or using another backend script — as long as
order.amountlands on the matching chain'spaymentInstructions[].address. Scanners always match deposits by(chain, address), regardless of where the funds come from.
6. Verify the signature
Every delivery carries X-Product-Signature: t=…,v1=…. Use the SDK's
constant-time helper to validate it before you parse the body.
import { verifySignature } from '@stableops/api-sdk/webhooks'
export async function POST(req: Request) {
const rawBody = await req.text()
const result = verifySignature({
secrets: [process.env.STABLEOPS_WEBHOOK_SECRET!],
header: req.headers.get('x-product-signature') ?? undefined,
rawBody,
})
if (!result.ok) {
return new Response(`invalid: ${result.reason}`, { status: 400 })
}
const event = JSON.parse(rawBody)
// Use event.data.payment_order_id and your own ledger to update entitlement.
return new Response('ok')
}What you just built
- Imported receiving addresses and registered a webhook endpoint in the Dashboard.
- Created an order with a chain-specific deposit address.
- Sent an on-chain payment through the wallet SDK.
- Verified a signed webhook delivery end to end.
Next: read Concepts → Confirmations for the state machine, or jump to the API reference.