Skip to main content
Add a “Pay with crypto” button to your checkout alongside your other payment methods. When a customer chooses it, they are taken to the SaturnShift hosted checkout to pay on-chain, and you receive a webhook when it settles. This is the model for a platform that renders the button on behalf of its merchants: you integrate once and pass the correct merchant per checkout.

1. Get the merchant’s publishable key

Each merchant has a publishable key (pk_live_...) that is safe to use in the browser. Fetch just the merchant you need, either by the reference you set when you onboarded them (psp_reference_id) or by the SaturnShift merchant id. Store the public_key against your merchant record once and reuse it on every checkout for that merchant.
# By your own reference (returns a list with the matching merchant)
curl "https://api.saturnshift.io/v1/merchants?psp_reference_id=YOUR-MERCHANT-REF" \
  -H "Authorization: Bearer <access_token>"

# Or directly by SaturnShift id (returns the merchant object)
curl https://api.saturnshift.io/v1/merchants/116 \
  -H "Authorization: Bearer <access_token>"
{
  "object": "merchant",
  "id": 116,
  "name": "Green Leaf Coffee",
  "public_key": "pk_live_29935fed5bc9878299588621772e0bc9",
  "psp_reference_id": "YOUR-MERCHANT-REF",
  "status": "ACTIVE"
}

2. Render the button

Load the checkout script and initialize it with the merchant’s publicKey, the order amount, and your own order id. Use a stable order id for both externalReference and idempotencyKey so a retry of the same order dedupes instead of creating a duplicate payment.
<button id="payWithCryptoBtn">Pay with crypto</button>

<script src="https://api.saturnshift.io/checkout.js"></script>
<script>
  const orderId = "ORDER-123"; // your stable order id

  SaturnShift.checkout({
    publicKey: "pk_live_29935fed5bc9878299588621772e0bc9", // the merchant's key
    amount: 1.00,
    currency: "USD",
    title: "Order #123",
    externalReference: orderId,
    idempotencyKey: orderId,
    redirectUrl: "https://your-portal.com/paylink/success",
    openInNewTab: true,   // opens the hosted checkout in a new page
    allowCrypto: true,
  }, "#payWithCryptoBtn");
</script>
The customer is taken to the SaturnShift hosted checkout to connect a wallet and pay, then returned to your redirectUrl.

3. Verify the amount before you fulfill

The amount is set in the browser, so you must confirm it server-side. When the payment.paid webhook arrives, check that the amount actually paid is at least your order amount, matched by external_reference, before you mark the order paid or fulfill it. Never fulfill on the event type alone.
// In your webhook handler, after verifying the signature (see Webhooks):
const event = JSON.parse(rawBody);

if (event.type === "payment.paid") {
  const order = await getOrder(event.data.external_reference);
  const paid = Number(event.data.amount.gross); // what the customer paid

  if (!order || paid < order.amount) {
    // Underpaid or unknown order. Do not fulfill; flag for review.
    return;
  }

  await markOrderPaid(order.id, event.data.id);
}
data.amount.gross is the amount the customer actually paid. data.amount_status (EXACT / UNDERPAID / OVERPAID) tells you how it compared to what was requested, but always compare against your own order amount as well, since the requested amount originates in the browser. See Webhooks for signature verification and the full event payload.