Payments
Yoco online payments setup for South African stores.
Yoco built its brand on the little blue card reader you see at every Cape Town coffee shop, but the Online Payments product is a separate SKU with its own API, dashboard section and fee structure. If you already use Yoco in-person, the online integration is the cleanest way to unify settlement. This guide covers the Online Checkout API, creating one-off checkout links, verifying webhook HMAC signatures, and the couple of quirks that trip up SA merchants migrating from card-present-only.
Prerequisites
- Yoco business account (Pty Ltd or Sole Prop) with FICA plus bank verification complete
- Online Payments product activated in the Yoco dashboard (distinct from the card reader product)
- Public secret key and public key from Developers → API keys
- Publicly reachable HTTPS webhook endpoint
- POPIA-compliant privacy notice covering card data redirect
Step 1. Activate Online Payments and fetch API keys
In the Yoco dashboard, open the Online Payments section and complete the activation form (expected monthly volume, product category). Once live, go to Developers → API keys and generate a Live Secret Key. Test keys are labelled explicitly — keep them separate from live.
Step 2. Install the Yoco SDK or call the REST API directly
Yoco exposes a REST API at payments.yoco.com. For Node/Workers, a thin fetch wrapper is enough — no SDK required. Always check current docs for the latest endpoint path as Yoco has versioned their Online API.
const YOCO_BASE = 'https://payments.yoco.com/api';
export async function yocoFetch(path: string, init: RequestInit = {}) {
const res = await fetch(`${YOCO_BASE}${path}`, {
...init,
headers: {
authorization: `Bearer ${process.env.YOCO_SECRET_KEY}`,
'content-type': 'application/json',
...(init.headers || {}),
},
});
if (!res.ok) {
throw new Error(`Yoco ${res.status}: ${await res.text()}`);
}
return res.json();
} Step 3. Create a checkout for an order
Yoco Online Checkout takes amountInCents (ZAR cents, integer only — no decimals), a currency of "ZAR", a metadata object, and your success and cancel URLs. The response contains a redirectUrl you send the customer to.
export async function createYocoCheckout(order: {
id: string;
amountRands: number;
email: string;
}) {
return yocoFetch('/checkouts', {
method: 'POST',
body: JSON.stringify({
amount: Math.round(order.amountRands * 100),
currency: 'ZAR',
successUrl: `https://yourstore.co.za/checkout/success?order=${order.id}`,
cancelUrl: `https://yourstore.co.za/checkout/cancel?order=${order.id}`,
metadata: { orderId: order.id, customerEmail: order.email },
}),
});
} Step 4. Redirect the buyer and handle return
On successful checkout creation, 302 to redirectUrl. On return, treat the successUrl as advisory only — it is the webhook that is authoritative, because a user can close the tab before returning.
Step 5. Register a webhook and verify the HMAC signature
In Yoco Developers → Webhooks, register your URL for payment.succeeded, payment.failed and refund.succeeded. Yoco signs the payload with a shared secret using HMAC-SHA256 and sends it as a header (check current docs for the exact header name — Yoco has iterated on this).
import crypto from 'node:crypto';
export async function handleYocoWebhook(req: Request, secret: string) {
const raw = await req.text();
const sig = req.headers.get('webhook-signature') || '';
const expected = crypto
.createHmac('sha256', secret)
.update(raw)
.digest('hex');
// Constant-time compare to avoid timing attacks
if (
sig.length !== expected.length ||
!crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))
) {
return new Response('invalid signature', { status: 401 });
}
const event = JSON.parse(raw);
if (event.type === 'payment.succeeded') {
await markOrderPaid(event.payload.metadata.orderId, event.payload.id);
}
return new Response('ok', { status: 200 });
} Step 6. Test with the sandbox environment
Use Yoco test keys with the documented test card numbers. Run a full lifecycle: successful payment, declined card, 3DS challenge, and refund. Confirm your webhook handler is idempotent against duplicate deliveries.
Step 7. Reconcile settlement in the Yoco dashboard
Yoco consolidates Online and in-person into one settlement if both are on the same business profile. Pull the daily settlement CSV and match against Shopify order exports — do this weekly for the first month.
SA gotchas
- Online and In-Person are separate products in the Yoco dashboard. You cannot use your card-reader-only account keys for online — activation is a separate step.
- amount is in cents (integer). Passing 499.00 instead of 49900 silently creates a R4.99 charge and is the most common integration bug we see.
- Online card fees are approximately 2.95% (verify current rates in the dashboard — Yoco has tiered pricing for volume and splits rates between local/international cards).
- Settlement delays are T+2 business days by default — faster settlement is a separate product upgrade with a fee.
- The successUrl is not authoritative. Always rely on the webhook for order fulfillment, because users bounce off the return page regularly.
- Yoco Online does not support subscription/recurring billing natively yet — you need Stitch, Stripe or Payfast Subscriptions for repeat charges.
Frequently asked questions
Does Yoco Online support 3DS2?
Yes, 3DS2 is handled automatically on the Yoco-hosted checkout, which is mandatory for SA card-not-present transactions under the Visa/Mastercard mandate.
Is Yoco POPIA-compliant?
Yoco is PCI-DSS compliant and processes card data on their infrastructure. You still need to cover the redirect and webhook data flow in your own POPIA privacy notice.
Can I accept international cards with Yoco Online?
Yes, Yoco accepts international Visa/Mastercard, but the fee differs from local cards and some international issuers will decline CNP transactions to SA merchants. Check current rates in your dashboard.
How do chargebacks work on Yoco?
Standard card chargeback rules apply. You will be notified via the dashboard and have a fixed window (usually 7–14 days) to submit evidence. Chargeback fees apply even if you win.
Can I use Yoco as a Shopify payment method?
Yoco does not have a native Shopify app for online at the time of writing — you integrate via Shopify Manual Payment Method plus an external checkout page, same pattern as Payfast.