Browse docs

Developers

Quickstart

Accept your first USDC payment in about five minutes: create an API key, create an invoice, send the customer to the hosted checkout, and fulfill on the invoice.paid webhook.

Soca is closer to Stripe Payment Links than to a card API. Your backend creates a payable object: a one-time invoice or a subscription plan, and Soca returns a hosted, non-custodial checkout_url. You send the customer there, they pay in USDC (gas is sponsored, so they never pay network fees), and the money settles directly to your wallet in the same transaction. You never build payment UI, and you fulfill the order from a signed webhook.

Amounts are USDC base units

Every amount in the API is an integer in USDC base units: USDC on Solana (base units, 6 decimals: $9.00 = 9000000). In JavaScript: Math.round(dollars * 1e6). Amounts come back as strings.

  1. 1

    Get an API key

    In the Dashboard, open Developers and create a secret key. Keys are shown once, so store it in your server environment (for example SOCA_SECRET_KEY). Start with a test key. It begins with sk_test_ and everything it creates stays in test mode. See Authentication.

  2. 2

    Create an invoice

    From your backend, POST to /v1/invoices with an amount (base units) and a description. The response includes a hosted checkout_url. Use raw HTTP or the official @usesoca/sdk. Both examples are below.

  3. 3

    Send the customer to checkout_url

    Link, redirect, or email the customer to the checkout_url. The hosted page handles everything: they connect a Solana wallet or sign in with email/Google (an embedded wallet is created for them), approve once, and pay in USDC with no gas. No money moves until they pay.

  4. 4

    Receive the invoice.paid webhook and fulfill

    Register an HTTPS endpoint in Dashboard → Developers → Webhooks and you get a whsec_ signing secret. When the customer pays, Soca POSTs an invoice.paid event to your endpoint. Verify the x-wc-signature header with one SDK line, then fulfill the order. Details in Webhooks and events.

  5. 5

    Go live

    Swap sk_test_ for an sk_live_ key. Nothing else changes: same endpoints, same fields, same webhooks. Test and live data are fully isolated from each other.

Create an invoice with curl

POST /v1/invoices
curl -X POST https://soca.to/v1/invoices \
-H "Authorization: Bearer sk_test_..." \
-H "Content-Type: application/json" \
-d '{"amount":"2500000","description":"Acme Pro, March","invoice_number":"INV-1041"}'
Response: 201 Created
{
"object": "invoice",
"id": "inv_...",
"amount": "2500000",
"status": "open",
"checkout_url": "https://soca.to/invoice/inv_..."
}

Create an invoice with @usesoca/sdk

npm i @usesoca/sdk
import { Soca } from '@usesoca/sdk';
const soca = new Soca(process.env.SOCA_SECRET_KEY);
const invoice = await soca.invoices.create({
amount: _500_000, // $2.50 in USDC base units
description: 'Acme Pro, March',
invoice_number: 'INV-1041',
});
// Send the customer here. The page is fully hosted.
console.log(invoice.checkout_url);

Verify the webhook and fulfill

Soca signs every delivery with HMAC-SHA256 over the raw body. Verify before trusting anything, using the raw (unparsed) request body:

Webhook handler (Express-style)
import { verifyWebhookSignature } from '@usesoca/sdk';
app.post('/webhooks/soca', express.raw({ type: 'application/json' }), (req, res) => {
const ok = verifyWebhookSignature(
process.env.SOCA_WEBHOOK_SECRET, // whsec_...
req.body.toString('utf8'), // the RAW body
req.headers['x-wc-signature'],
);
if (!ok) return res.status(400).end();
const event = JSON.parse(req.body.toString('utf8'));
if (event.type === 'invoice.paid') {
// Fulfill the order for event.data
}
res.status(200).end();
});

Fulfill on invoice.paid, not on redirect

The webhook is the source of truth. There is no payment.confirmed event. One-time purchases are fulfilled on invoice.paid, and subscription access starts on subscription.active. See the full event list in Webhooks and events.

Where to next

Was this page helpful?

A quick signal helps us improve the right pages.