API til kassesystemer
Scan kundens Wallio-kort i kassen, og giv stempler, klip, rabat og træk på gavekort — uden at personalet skal bruge en anden skærm.
Kom i gang
Caféen laver en nøgle i sit dashboard under Kassesystem og API og giver den til jer. Nøglen hører til én café og kan kun se og ændre den cafés kort. Send den i hver anmodning:
Authorization: Bearer wallio_…Prøv, at nøglen virker:
curl https://wallio.dk/api/v1/me -H "Authorization: Bearer wallio_…"Alle adresser starter med https://wallio.dk/api/v1, og alle svar er JSON. Nøglen må kun ligge på jeres server eller i kassen — aldrig i en app eller hjemmeside, kunderne kan åbne. Caféen kan fjerne en nøgle når som helst; så svarer API'et 401.
Sådan foregår det ved kassen
- Kassens scanner læser QR-koden på kundens kort. Den indeholder en adresse som
https://wallio.dk/s/3f9a1c0b…. - Send teksten, som den er, til
GET /cards/lookup?code=…. I får kortet ogallowed_actions: de knapper, der giver mening lige nu. - Når kunden betaler, sendes handlingen til
POST /cards/<serial>/actionsmed enIdempotency-Key. - Kundens kort i Apple Wallet og Google Wallet opdaterer sig selv få sekunder efter. I skal ikke gøre mere.
Adresser
| Adresse | Hvad |
|---|---|
GET /me | Caféen og nøglen. Til at prøve forbindelsen. |
GET /card-types | Caféens korttyper, med signup_url (adressen bag QR-koden på disken — kan fx printes på bonen). |
GET /cards/lookup?code=… | Slå et kort op ud fra det, scanneren læste. |
GET /cards/<serial> | Slå et kort op ud fra serienummeret. |
GET /cards/<serial>/events | Kortets historik, nyeste først (?limit= 1-200, standard 50). |
POST /cards/<serial>/actions | Gør noget ved kassen (se herunder). |
Kortet
{
"serial": "3f9a1c0b7d2e4f6a8b9c0d1e",
"type": "stamp_card",
"status": "active",
"card_type_id": "5b1e…",
"business_name": "Kaffebaren",
"holder": null,
"last_activity_at": "2026-09-30T08:12:44.000Z",
"allowed_actions": ["stamp", "undo"],
"stamp_card": { "stamps": 7, "goal": 10, "reward": "Gratis kaffe", "reward_ready": false }
}type er en af stamp_card, punch_card, discount_card, coupon, gift_card og raffle, og kortet har et felt med samme navn med det, der hører til typen. status er active, blocked, expired, used (brugt kupon) eller won (vundet lod).
Beløb er i øre (heltal): 4550 er 45,50 kr. Valutaen er altid DKK.
Handlinger
| Kort | action | Hvad |
|---|---|---|
| stamp_card | stamp | Giv stempler. count 1-100 (standard 1). Aldrig ud over fuldt: står kortet på 9 af 10, gives 1. |
redeem | Belønningen er udleveret. Kortet starter forfra på 0. | |
undo | Fortryd det seneste stempel eller den seneste udlevering (inden for 10 minutter). | |
| punch_card | punch | Brug et klip. |
sell_punch_card | Kunden har købt et nyt klippekort. Klippene lægges oveni. | |
undo | Fortryd det seneste klip eller salg (inden for 10 minutter). | |
| discount_card | use_discount | Rabatten er givet. Kortet ændrer sig ikke; det tæller som et besøg i caféens statistik. |
| coupon | use_coupon | Brug kuponen én gang. Når den er brugt op, bliver den ugyldig i kundens Wallet. |
undo | Fortryd den seneste brug (inden for 10 minutter). | |
| gift_card | charge | Træk amount øre fra. Afvises, hvis der ikke er nok på kortet. |
top_up | Sæt amount øre på. "gift": true, hvis det er en gave fra caféen og ikke betalt af kunden. | |
undo | Fortryd den seneste ændring (inden for 10 minutter). |
Højst 10.000 kr pr. gang. Eksempel:
curl -X POST https://wallio.dk/api/v1/cards/3f9a1c0b7d2e4f6a8b9c0d1e/actions \
-H "Authorization: Bearer wallio_…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: ordre-10442-stempel" \
-d '{"action": "stamp", "count": 2}'Svaret har en besked, der kan vises til personalet, og kortet, som det står nu:
{
"action": "stamp",
"message": "2 stempler givet. Kortet står nu på 9 af 10.",
"card": { …kortet efter handlingen… }
}Send aldrig det samme to gange
Mister kassen forbindelsen, før svaret kommer, ved den ikke, om stemplet blev givet. Send derfor en Idempotency-Key med hver handling — fx ordrenummeret plus handlingen. Kommer den samme nøgle igen inden for et døgn, får I det første svar igen (med headeren Idempotent-Replayed: true), og der sker ikke noget nyt. Samme nøgle med et andet indhold afvises med 422.
Fejl
{
"error": { "code": "card_full", "message": "Kortet er allerede fuldt. Indløs belønningen først." },
"card": { … }
}message er skrevet til personalet og kan vises direkte. Afvises en handling, kommer kortet med, så kassen kan vise, hvordan det står.
| Status | code |
|---|---|
| 400 | invalid_json, invalid_action, invalid_count, invalid_amount, invalid_gift, invalid_code, invalid_idempotency_key |
| 401 | invalid_api_key — nøglen mangler, er forkert eller fjernet |
| 403 | plan_required — caféens pakke har ikke API'et |
| 404 | card_not_found — kortet findes ikke eller hører til en anden café |
| 409 | card_full, card_not_full, no_punches_left, coupon_used, insufficient_balance, nothing_to_undo, card_blocked, wrong_card_type, request_in_progress |
| 413 | body_too_large |
| 422 | idempotency_key_reused |
| 429 | rate_limited — højst 120 anmodninger i minuttet pr. nøgle. Se Retry-After. |
| 500/503 | server_error, try_again — prøv igen med samme Idempotency-Key |
Kundedata
Wallio gemmer ingen navne, mails eller telefonnumre på caféens kunder. Kortet er et tilfældigt nummer. Et personale- eller erhvervskort kan have et navn i holder, som caféen selv har skrevet.
Spørgsmål
Skriv til [email protected]. Vi hjælper gerne med en testcafé og en testnøgle.