Your analytics

Live data from your Otterpay checkout — last 30 days.

No orders in this range yet.

Developers

API keys, embed snippet, webhooks & delivery logs.

Open

Use API keys to authenticate requests from your storefront. Drop the embed snippet onto your checkout page, or call the API from your backend. Webhooks let us notify you the moment a basket is paid.

API keys

test mode

Safe for development — baskets won't be sent to real fulfillment.

Publishable key
Secret key

live mode

Live mode — real merchants, real notifications.

Publishable key
Secret key

Embed on your site

Preview
Otterpay· Send to a frienddefault
Otterpay· Send to a frienddark
Otterpay· Send to a friendoutline

Drop the snippet below — embed.js auto-styles any [data-otterpay] button into the pill above. Use data-variant="dark|outline" to switch styles.

HTML snippet
<script src="https://otterpay.app/embed.js" data-pk="pk_live_…"></script>
<button
  data-otterpay
  data-basket='{"basket_id":"B-123","total":42.00,"items":[{"sku":"X","name":"Tee","price":42,"qty":1}]}'
></button>

<!-- Variants: data-variant="dark" or data-variant="outline" -->
<!-- Custom label: data-label="Pay with a friend" -->
cURL — create basket from your backend
curl https://otterpay.app/api/public/v1/baskets \
  -H "Authorization: Bearer sk_test_…" \
  -H "Content-Type: application/json" \
  -d '{
    "basket_id": "B-123",
    "total_amount": 42.00,
    "items": [{"sku":"X","name":"Tee","price":42,"qty":1}],
    "success_url": "https://yoursite.com/thanks",
    "cancel_url": "https://yoursite.com/cart"
  }'

Webhooks

We POST signed JSON to your endpoint on every basket status change. Verify the Otterpay-Signature header using your signing secret.

No webhooks configured yet.

Recent deliveries

EventStatusCodeAttemptsWhen
No deliveries yet.

Verify webhook signatures

Node.js
import crypto from "crypto";
const header = req.headers["otterpay-signature"]; // "t=...,v1=..."
const parts = Object.fromEntries(header.split(",").map(p => p.split("=")));
const expected = crypto.createHmac("sha256", SIGNING_SECRET)
  .update(parts.t + "." + rawBody).digest("hex");
const ok = crypto.timingSafeEqual(Buffer.from(parts.v1), Buffer.from(expected));