Dezvoltatori

Autentificarea și semnătura cererilor

Antetele X-Ezif-Key, X-Ezif-Timestamp, X-Ezif-Signature, calculul semnăturii HMAC-SHA256, exemple PHP și Node.js.

Specificația API (JSON)
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.

Documentația aplicației eZif 0.42.6.