Agent skill
Yoco Webhooks Skill
Receive and verify Yoco webhooks (South African payments). Use when setting up Yoco webhook handlers for the Yoco API or Checkout API, debugging Standard Webhooks signature verification (webhook-id, webhook-timestamp, webhook-signature, whsec_ secret), or handling events like payment.created, payment.refunded, order.completed, payment.succeeded, and refund.succeeded.
Install this skill
npx skills add hookdeck/webhook-skills --skill yoco-webhooks
Yoco (South African card machines, POS, and online payments) sends webhooks from two APIs: the Yoco API (payments, orders, catalogue) and the Checkout API (hosted checkout payments and refunds). Both sign deliveries with Standard Webhooks: HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{rawBody} with a whsec_ secret.
When to Use This Skill
- How do I receive Yoco webhooks in Express, Next.js, or FastAPI?
- How do I verify Yoco webhook signatures?
- How do I handle
payment.created,payment.refunded, ororder.completedevents? - How do I confirm a Checkout API payment with
payment.succeeded? - Why is my Yoco webhook signature verification failing?
- Where do I get the Yoco webhook secret?
Signature at a Glance
| Property | Value |
|---|---|
| Headers | webhook-id, webhook-timestamp, webhook-signature |
| Algorithm | HMAC-SHA256, base64-encoded |
| Signed content | {webhook-id}.{webhook-timestamp}.{rawBody} |
| Key | Strip whsec_ from the secret, base64-decode the rest |
| Signature header | Space-separated list of v1,<base64sig>; accept if any matches |
| Timestamp tolerance | Yoco recommends 3 minutes |
| Secret | Returned once, in the create-subscription response |
Verification (core)
Yoco recommends the Standard Webhooks library (standardwebhooks on npm and PyPI). It defaults to a 5-minute window, so check Yoco's 3 minutes first. Always pass the raw request body.
const { Webhook } = require('standardwebhooks');
function verifyYocoWebhook(rawBody, headers, secret) {
const ts = Number(headers['webhook-timestamp']);
if (!Number.isInteger(ts) || Math.abs(Date.now() / 1000 - ts) > 180) {
throw new Error('Timestamp outside the 3-minute tolerance');
}
// Strips "whsec_", base64-decodes the key, HMACs "{id}.{ts}.{body}",
// and compares each "v1," signature in constant time. Throws on mismatch.
return new Webhook(secret).verify(rawBody, headers);
}
from standardwebhooks.webhooks import Webhook
if abs(int(time.time()) - int(headers["webhook-timestamp"])) > 180:
raise ValueError("Timestamp outside the 3-minute tolerance")
event = Webhook(secret).verify(raw_body, headers) # raises on mismatch -> return 400
For complete handlers with tests, see examples/express/, examples/nextjs/, examples/fastapi/.
A manual (library-free) implementation is in references/verification.md.
Common Event Types
Yoco API events carry event_type; Checkout API events carry type. Read event.event_ if one endpoint receives both.
| Event | API | Triggered When |
|---|---|---|
payment.created | Yoco API | A payment is created |
payment.refunded | Yoco API | A payment is refunded |
order.created / order.updated | Yoco API | An order is opened / changed |
order.completed / order.cancelled | Yoco API | An order is fully paid / cancelled |
item.*, item_category.* | Yoco API | Catalogue items or categories are created, updated, or deleted |
payment.succeeded / payment.failed | Checkout API | A checkout payment succeeds / fails |
refund.succeeded / refund.failed | Checkout API | A refund succeeds / fails |
Checkout API webhooks fire for every payment on the account. Match payload.metadata.checkoutId to your checkout before fulfilling. See references/overview.md for payloads.
Environment Variables
YOCO_WEBHOOK_SECRET=whsec_xxxxx # From the create-subscription response (shown once)
Local Development
Receive webhooks locally with the Hookdeck CLI — no account required, one paste-and-run line:
npx hookdeck-cli listen 3000 yoco --path /webhooks/yoco
Register the printed URL as your subscription's notification_url (Yoco API) or url (Checkout API). With the Yoco API, POST /v1/webhooks/subscriptions/{id}/test sends a signed sample event.
Reference Materials
- references/overview.md - Yoco API vs Checkout API webhooks, full event list, payloads, retries
- references/setup.md - Create a subscription, store the secret, rotate it, send test events
- references/verification.md - Signature details, SDK and manual verification, debugging