TTocler Docs
Dashboard
Developers›Guides

API delivery: deliver from your server

Tocler calls your https endpoint after each payment; you answer with the items or a message.

Updated 2 November 2026Live from Tocler

When a buyer pays for an API delivery product, Tocler sends one signed POST per order line to your endpoint. Your answer is what the buyer receives. API version: 2026-10-30 (it changes only when a field is removed or renamed).

  1. Add the endpoint

    Dashboard → Delivery → API delivery → Endpoints → Add. Give a public https:// address. Copy the secret (whsec_…) — it is shown once.

  2. Check the signature

    See Webhooks and signatures.

  3. Answer

    Return 200 with JSON: the items (exactly the quantity) and / or a message.

  4. Test

    Press Test on the endpoint or on a product: Tocler sends a test request with the product’s real ids and sample answers, and shows what your server answered.

The request Tocler sends
POST /your/endpoint HTTP/1.1
Content-Type: application/json
User-Agent: Tocler-API-Delivery/1
x-tocler-event: order.paid
x-tocler-timestamp: 1793650000
x-tocler-signature: v1=5f0c…
x-tocler-delivery: TRX-8F2K1.0
FieldMeaning
idStable id of this delivery (order id + line). The same on every retry — use it to never deliver twice.
eventorder.paid, or test from the Test button (then test: true).
attempt1 on the first try, higher on retries.
order.total, line.unitPriceDecimal text in the order’s currency, e.g. "19.99" — never a float.
order.paidWithcard, crypto, store_credit, provider, manual.
line.quantityHow many items you must return.
fieldsThe buyer’s answers by their key (questions without a key are only in fieldList). Secret answers are sent in clear only to your signed endpoint.
buyer.emailOnly when you switched on “Send the buyer’s email” for the endpoint.
Your answer
{ "items": ["GEMS-7Q2K-91XA", "GEMS-PL0C-55ZT"] }
RuleValue
ItemsExactly line.quantity; each text up to 4 KB, or an object of up to 8 labelled values (shown like an account; labels containing pass, pin, secret, token or code are masked for staff).
MessageUp to 2,000 characters; the buyer sees it on the order page.
TimeAnswer within 10 seconds.
SizeAnswer body up to 64 KB.
AddressPublic https only; no redirects; private and local addresses are refused.
RetriesAfter 1, 5, 15 and 30 minutes (5 tries). Then the line waits for the owner’s Try again, and the owner is emailed.
A complete endpoint
const express = require('express');
const crypto = require('crypto');
const app = express();
const done = new Map(); // use your database in production

app.post('/tocler/deliver', express.raw({ type: 'application/json', limit: '64kb' }), async (req, res) => {
  const raw = req.body.toString('utf8');
  const ts = req.get('x-tocler-timestamp');
  const expected = 'v1=' + crypto.createHmac('sha256', process.env.TOCLER_ENDPOINT_SECRET).update(`${ts}.${raw}`).digest('hex');
  const sig = Buffer.from(req.get('x-tocler-signature') || '');
  if (Math.abs(Date.now() / 1000 - Number(ts)) > 300 || sig.length !== expected.length || !crypto.timingSafeEqual(sig, Buffer.from(expected))) {
    return res.status(401).end();
  }
  const body = JSON.parse(raw);
  if (done.has(body.id)) return res.json(done.get(body.id)); // a retry: same answer
  const items = [];
  for (let i = 0; i < body.line.quantity; i += 1) items.push(await makeCode(body.line.variant.sku, body.fields));
  const answer = { items };
  if (!body.test) done.set(body.id, answer);
  res.json(answer);
});
Was this page helpful?