Ghiduri de integrare
Actualizări, în ritmul tău.
Alege modul de livrare potrivit aplicației tale.
Interoghează lista de rezultate
Simplu și ieftin cu ETag-uri — o interogare care nu a găsit nicio schimbare primește un 304.
Alegerea potrivită pentru un import zilnic sau pentru o pagină care se reîmprospătează.
curl 'https://api.lottevo.com/v1/draws?filter[lottery]=EU-001' \
-H 'X-Api-Key: …' \
-H 'If-None-Match: "…"'
Abonează-te la webhook-uri
Necesită webhooks:manage, inclus în toate planurile și în perioada de probă. Înregistrează un endpoint https pentru
evenimentele care te interesează și, opțional, doar pentru jocurile care contează pentru tine:
curl -X POST https://api.lottevo.com/v1/webhooks \
-H 'X-Api-Key: …' \
-H 'Content-Type: application/json' \
-d '{
"url": "https://yourapp.example/hooks/lottevo",
"events": ["draw.published", "jackpot.updated"],
"lottery_codes": ["EU-001", "RO-001"]
}'
Secretul de semnare vine în acel răspuns și niciodată din nou. Dacă ajunge pe mâini străine,
regenerează-l cu POST /v1/webhooks/{id}/rotate-secret.
| Eveniment | Se declanșează când |
|---|---|
draw.published | Este înregistrat un rezultat nou |
draw.revised | Numerele unui rezultat înregistrat au fost corectate |
draw.confirmed | Un rezultat publicat în direct (provisional: true) a fost confirmat de operator, cu aceleași numere |
jackpot.updated | Valoarea unui jackpot s-a schimbat fără ca numerele să se schimbe, pe o extragere din ultimele 48 de ore sau pe cea mai nouă a jocului |
draw.missed | O extragere așteptată nu a sosit până la sfârșitul ferestrei de supraveghere |
lottery.paused | Operatorul unui joc a încetat să publice rezultate; extragerile lui nu sunt raportate ca lipsă între timp |
lottery.resumed | Operatorul unui joc pus pe pauză publică din nou rezultate |
După un draw.missed
Continuăm să încercăm, iar o trecere zilnică recuperează din arhiva operatorului ce lipsește încă.
Fiecare extragere recuperată din pana despre care ai fost anunțat îți ajunge ca draw.published,
la fel ca oricare alta, cu "recovered": true și recovered_at lângă draw. O extragere care
sosește pe loc are "recovered": false. Istoricul importat din arhivă nu se trimite;
GET /v1/draws/changes îl listează și pe acela.
Când un joc e pus pe pauză
Când un operator nu mai publică (site-ul lui e oprit de zile întregi sau jocul nu se mai trage),
punem jocul pe pauză în loc să trimitem câte un draw.missed pentru fiecare extragere din program.
lottery.paused conține lottery_code, reason (operator_not_publishing) și since, iar
câmpul paused al jocului din GET /v1/lotteries/{code} spune același lucru cât durează pauza. Când
operatorul publică din nou, lottery.resumed adaugă resumed_at, iar extragerile publicate între
timp le căutăm în arhiva lui; extragerile pe care nu le-a ținut rămân în afara cifrelor de completitudine.
Verificarea unei livrări
Fiecare livrare este un POST care conține id, event, created_at și data, cu headerele
X-Lottevo-Event, X-Lottevo-Delivery și X-Lottevo-Signature.
X-Lottevo-Signature: t=1758374400,v1=5d41402abc4b2a76b9719d911017c592…
v1 este HMAC-SHA256 peste {t}.{raw body}, cu secretul endpoint-ului tău.
import { createHmac, timingSafeEqual } from 'node:crypto'
function verify(header, body, secret) {
const parts = Object.fromEntries(header.split(',').map((p) => p.trim().split('=')))
const timestamp = Number(parts.t)
if (Math.abs(Date.now() / 1000 - timestamp) > 300) return false
const expected = createHmac('sha256', secret).update(`${timestamp}.${body}`).digest('hex')
const a = Buffer.from(parts.v1, 'utf8')
const b = Buffer.from(expected, 'utf8')
return a.length === b.length && timingSafeEqual(a, b)
}
Verifică și marcajul de timp. Un receptor care verifică doar HMAC-ul acceptă reluarea oricărei cereri pe care a primit-o vreodată. Și verifică pe corpul brut — reserializarea JSON-ului poate reordona cheile și invalida semnătura.
X-Lottevo-Delivery rămâne același la reîncercări, deci este cheia ta de idempotență.
Evenimentul de test
Când te abonezi și de fiecare dată când muți un abonament pe o adresă nouă, îi trimitem un
webhook.ping, semnat ca orice altă livrare. Dacă serverul tău nu răspunde cu un 2xx, îți scriem pe
e-mail ce a răspuns, înainte să se piardă vreun eveniment real. Poți trimite oricând încă unul:
curl -X POST https://api.lottevo.com/v1/webhooks/{id}/test -H 'X-Api-Key: …'
{ "data": { "delivered": false, "status_code": 404, "error": "The receiver answered 404.", "duration_ms": 182 } }
Un test nu este o livrare: nu apare în jurnalul de livrări și nu se adună la eșecurile care dezactivează un abonament. Răspunde-i cu orice 2xx, ca la un eveniment pe care nu-l tratezi.
Reîncercări
Orice răspuns în afară de un 2xx este un eșec, inclusiv o redirecționare. Șase încercări, la
intervale tot mai mari — 10s, 1m, 5m, 15m, 1h — apoi livrarea este marcată ca eșuată definitiv și
apare în GET /v1/webhooks/{id}/deliveries, de unde o poți retrimite.
După 20 de livrări eșuate consecutiv, abonamentul este dezactivat și primești o notificare;
PATCH /v1/webhooks/{id} cu "active": true îl reactivează.
Deschide fluxul live
Necesită stream:read, de la planul Pro în sus și în perioada de probă. GET /v1/stream folosește Server-Sent Events.
id: 10482
event: draw.published
data: {"draw":{"id":10482,"lottery_code":"EU-001","numbers":[7,16,24,38,45],…}}
ID-ul cadrului este punctul tău de reluare: Last-Event-ID este respectat, așa că o reconectare
continuă de unde a rămas, fără să reia sau să sară evenimente. Restrânge cu filter[lottery] sau
cu filtrele de locație; fără filtru primești exact jocurile pe care le acoperă cheia ta, nu tot
torentul de date.
O conexiune durează până la 100 de secunde, apoi trimite stream.reconnect — orice EventSource se
reconectează singur. Comentariile keep-alive sosesc la fiecare 20 de secunde. Până la 2 conexiuni
simultane per cont, cu toate cheile lui la un loc.
EventSource nu poate seta headere, deci nu poate trimite X-Api-Key. Consumă fluxul de pe
serverul tău și distribuie-l tu către browsere.
Rezultatele adăugate ulterior în istoric nu sunt transmise niciodată în flux: un flux duce ce tocmai s-a întâmplat, nu istoricul care se scrie.
Descarcă un export în bloc
Necesită exports:read, pe planul Enterprise. Un export este tot istoricul inclus în planul tău
pentru o loterie la care are acces cheia ta, într-un singur fișier comprimat gzip, cu cea mai
veche extragere întâi.
POST /v1/exports
{"lottery": "RO-001", "format": "csv"}
Folosește ndjson în loc de csv pentru câte un obiect JSON pe linie. O linie NDJSON este
obiectul de extragere de la GET /v1/draws/{id}, cu categoriile de premii; CSV-ul are aceleași
câmpuri fără categorii, cu listele separate prin spații.
Răspunsul este 202, cu id-ul exportului și status: "building". Interoghează
GET /v1/exports/{id} până când status devine ready, apoi urmează download_url. Un joc cu
milioane de extrageri durează câteva minute. Extragerile de după as_of nu sunt în fișier, deci e
o imagine consecventă: continuă cu GET /v1/draws/changes ca să rămâi la zi.
Linkul de descărcare merge până la expires_at, deci păstrează-l secret. Verifică fișierul cu
sha256. Fiecare descărcare este înregistrată.
Fiecare export se numără în plafonul lunar al contului, pe toate cheile lui, fie că îl descarci,
fie că nu; un export eșuat nu se numără. GET /v1/exports listează exporturile cheii și spune în
meta câte mai rămân luna aceasta și când se reînnoiește plafonul. Poți cere exporturi și din
consolă, la Exporturi.