| Mediu | Adresă de bază |
|---|---|
| Dezvoltare (test) | https://dev.ezif.ro/api/ext/v1 |
| Producție | https://app.ezif.ro/api/ext/v1 |
Fiecare cerere are trei antete (plus Content-Type: application/json la POST):
| Antet | Valoare |
|---|---|
X-Ezif-Key |
cheia (ezk_…) |
X-Ezif-Timestamp |
ora cererii, secunde Unix (UTC); diferență acceptată: 5 minute |
X-Ezif-Signature |
HMAC-SHA256 hex, cu secretul, peste: timestamp + \n + METODA + \n + calea + \n + sha256(corp) |
Calea este partea de după domeniu, fără parametrii de după ? (ex. /api/ext/v1/invoices). La GET corpul e gol (sha256 al șirului gol). X-Ezif-Site se trimite doar dacă firma are domenii autorizate.
PHP
<?php
const EZIF = 'https://dev.ezif.ro';
const KEY = 'ezk_…'; // din configurarea aplicației, nu din cod
const SECRET = 'ezs_…';
function ezif(string $method, string $path, ?array $body = null, array $query = []): array {
$raw = $body === null ? '' : json_encode($body, JSON_UNESCAPED_UNICODE);
$ts = (string) time();
$sig = hash_hmac('sha256', $ts . "\n" . $method . "\n" . $path . "\n" . hash('sha256', $raw), SECRET);
$url = EZIF . $path . ($query ? '?' . http_build_query($query) : '');
$ch = curl_init($url);
curl_setopt_array($ch, [CURLOPT_CUSTOMREQUEST => $method, CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 30,
CURLOPT_POSTFIELDS => $raw ?: null, CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'X-Ezif-Key: ' . KEY,
'X-Ezif-Timestamp: ' . $ts, 'X-Ezif-Signature: ' . $sig]]);
$res = json_decode(curl_exec($ch), true);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($code >= 400) throw new RuntimeException(($res['code'] ?? 'HTTP') . ': ' . ($res['title'] ?? $code));
return $res;
}
print_r(ezif('GET', '/api/ext/v1/ping')); // firma, drepturile, seriile și setările aplicației
Node.js
import crypto from 'node:crypto';
const EZIF = 'https://dev.ezif.ro', KEY = process.env.EZIF_KEY, SECRET = process.env.EZIF_SECRET;
export async function ezif(method, path, body = null, query = null) {
const raw = body ? JSON.stringify(body) : '';
const ts = Math.floor(Date.now() / 1000).toString();
const hash = crypto.createHash('sha256').update(raw).digest('hex');
const sig = crypto.createHmac('sha256', SECRET).update(`${ts}\n${method}\n${path}\n${hash}`).digest('hex');
const url = EZIF + path + (query ? '?' + new URLSearchParams(query) : '');
const r = await fetch(url, { method, body: raw || undefined, headers: { 'Content-Type': 'application/json',
'X-Ezif-Key': KEY, 'X-Ezif-Timestamp': ts, 'X-Ezif-Signature': sig } });
const j = await r.json();
if (!r.ok) throw new Error(`${j.code}: ${j.title}`);
return j;
}
Prima cerere de probă: GET /ping — întoarce firma, technical_user: true, drepturile, seriile și evenimentele cheii. Dacă răspunsul e 401, vezi Erori, coduri și limite.