Transactions
Every write is a ledger row. Send an Idempotency-Key and a retry will return the first result instead of double-charging a customer.
Endpoints
POST
/cards/{serial}/earnAward points from a sale amount or a fixed point count.
POST
/cards/{serial}/stampAdd stamps, respecting the cooldown and per-visit maximum.
POST
/cards/{serial}/redeemRedeem a reward and write the redemption row.
POST
/cards/{serial}/checkinRecord a membership check-in.
POST
/cards/{serial}/adjustManual correction with a reason, recomputed from the ledger.
POST
/cards/{serial}/topupPrepaid: sell packs. Body packs (default 1) and amount (default packs × pack_price). Adds packs × units_per_pack.
POST
/cards/{serial}/usePrepaid: deduct count units, 1 up to max_use_per_scan. Refused with insufficient_units when fewer remain.
GET
/cards/{serial}/transactionsThe ledger for one card, newest first.
Example
curl -X POST https://perfito.al/v1/cards/PF-8F2A-19/earn \ -H "Authorization: Bearer sk_test_…" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: 34dc17ae" \ -d '{ "amount": 1450, "reference": "order_10492" }'
$ch = curl_init('https://perfito.al/v1/cards/PF-8F2A-19/earn'); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_POSTFIELDS => '{ "amount": 1450, "reference": "order_10492" }', CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $key, 'Content-Type: application/json'], ]); $data = json_decode(curl_exec($ch), true);
const res = await fetch('https://perfito.al/v1/cards/PF-8F2A-19/earn', { method: 'POST', headers: { Authorization: `Bearer ${key}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ "amount": 1450, "reference": "order_10492" }), }); const data = await res.json();