Sari la conținut

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ă.

Exemplu de cod
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:

Exemplu de cod
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.

EvenimentSe declanșează când
draw.publishedEste înregistrat un rezultat nou
draw.revisedNumerele unui rezultat înregistrat au fost corectate
draw.confirmedUn rezultat publicat în direct (provisional: true) a fost confirmat de operator, cu aceleași numere
jackpot.updatedValoarea 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.missedO extragere așteptată nu a sosit până la sfârșitul ferestrei de supraveghere
lottery.pausedOperatorul unui joc a încetat să publice rezultate; extragerile lui nu sunt raportate ca lipsă între timp
lottery.resumedOperatorul 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.

Exemplu de cod
X-Lottevo-Signature: t=1758374400,v1=5d41402abc4b2a76b9719d911017c592…

v1 este HMAC-SHA256 peste {t}.{raw body}, cu secretul endpoint-ului tău.

Exemplu de cod
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:

Exemplu de cod
curl -X POST https://api.lottevo.com/v1/webhooks/{id}/test -H 'X-Api-Key: …'
Exemplu de cod
{ "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.

Exemplu de cod
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.

Exemplu de cod
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.