API publik 4invoices mengirim data faktur dari sistem Anda ke 4invoices dan membawa faktur sampai ke sistem faktur elektronik nasional (di Rumania: SPV ANAF). Satu host produksi, satu alur client_credentials, penulisan fiskal yang idempoten, dan satu amplop error di setiap rute.
https://api.4invoices.net/v1 · Spesifikasi OpenAPI (tanpa perlu kunci)
Apa itu API 4invoices
- API publik 4invoices adalah REST melalui HTTPS, dengan JSON masuk dan JSON keluar.
- Satu host produksi: https://api.4invoices.net/v1. Tidak ada host sandbox terpisah.
- Spesifikasi OpenAPI 3.1 bersifat publik dan tanpa kunci — impor langsung ke Postman atau generator klien.
- Setiap respons membawa header X-Request-Id; sertakan saat Anda meminta dukungan.
- Setiap penulisan fiskal bersifat idempoten: percobaan ulang setelah timeout tidak pernah menerbitkan dokumen kedua.
- Seluruh alur faktur elektronik nasional melalui API (di Rumania: e-Factura ANAF): pemeriksaan awal, pengajuan, pelacakan, respons bertanda tangan, dan kotak masuk pesan masuk. Tidak ada pesaing Rumania yang menyediakan ini.
- SmartBill sama sekali tidak memiliki endpoint untuk pengajuan ke sistem faktur elektronik nasional (ANAF, di Rumania) — pengiriman hanya berupa pengaturan akun di antarmuka — dan tidak ada endpoint pendaftaran faktur sama sekali.
- Oblio hanya dapat membuat klien dan produk sebagai efek samping saat menerbitkan dokumen, bukan sebagai sumber daya kelas satu.
- Pembuatan XML UBL tanpa pengajuan (CIUS-RO untuk Rumania): Anda mendapatkan dokumen hukum sebagai file tanpa menyentuh sistem nasional.
- Idempotensi pada penulisan fiskal: percobaan ulang setelah timeout tidak menghasilkan faktur kedua atau menghabiskan nomor kedua.
- Kotak masuk faktur pemasok yang dapat dibaca secara terprogram — dasar rekonsiliasi otomatis.
Faktur pertama Anda dalam 6 langkah
- Buat kredensial di panel pada Faktur → Pengaturan → Akses API, lalu salin client_secret — secret hanya ditampilkan sekali.
- Lengkapi profil perusahaan dan aktifkan minimal satu seri berjenis fiscale, jika tidak penerbitan akan mengembalikan issuer_profile_incomplete atau no_series_configured.
- Buat kredensial di panel pada Faktur → Pengaturan → Akses API, lalu salin client_secret — secret hanya ditampilkan sekali.
- Lengkapi profil perusahaan dan aktifkan minimal satu seri berjenis fiscale, jika tidak penerbitan akan mengembalikan issuer_profile_incomplete atau no_series_configured.
- Tukar kredensial dengan token: POST /v1/auth/token dengan grant_type client_credentials. Token berlaku satu jam — simpan dalam cache, jangan minta satu per permintaan.
- Terbitkan faktur: POST /v1/invoices dengan header Idempotency-Key dan vat_rate sebagai persen (21, bukan 0,21).
- Jalankan pemeriksaan awal (CIUS-RO untuk Rumania) dengan POST /v1/invoices/{id}/efactura/validate, lalu kirim ke sistem faktur elektronik nasional dengan POST /v1/invoices/{id}/efactura/submit.
- Pantau statusnya dengan GET /v1/efactura/submissions/{id} hingga mencapai accepted atau rejected.
bash
# 1 — token (1 jam, simpan dalam cache)
ACCESS_TOKEN=$(curl -sS -X POST https://api.4invoices.net/v1/auth/token \
-H 'Content-Type: application/json' \
-d '{"grant_type":"client_credentials","client_id":"cli_XXX","client_secret":"sec_XXX"}' \
| python3 -c 'import sys,json; print(json.load(sys.stdin)["access_token"])')
# 2 — terbitkan faktur (Idempotency-Key WAJIB)
curl -sS -X POST https://api.4invoices.net/v1/invoices \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: order-10457-invoice' \
-d '{"buyer":{"name":"Exemplu Comert SRL","tax_id":"RO12345678","county":"Cluj","city":"Cluj-Napoca","country":"RO"},
"lines":[{"description":"Abonament SaaS","quantity":1,"unit_price":400,"vat_rate":21}]}'
# 3 — preflight CIUS-RO, then send to ANAF
curl -sS -X POST https://api.4invoices.net/v1/invoices/inv_01J7ABC/efactura/validate \
-H "Authorization: Bearer $ACCESS_TOKEN"
curl -sS -X POST https://api.4invoices.net/v1/invoices/inv_01J7ABC/efactura/submit \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H 'Idempotency-Key: efactura-inv_01J7ABC-1'javascript
const BASE = "https://api.4invoices.net/v1";
const token = await fetch(`${BASE}/auth/token`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
grant_type: "client_credentials",
client_id: process.env.FOURINVOICES_CLIENT_ID,
client_secret: process.env.FOURINVOICES_CLIENT_SECRET,
}),
}).then((r) => r.json()).then((d) => d.access_token);
const invoice = await fetch(`${BASE}/invoices`, {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
"Idempotency-Key": `order-${orderId}-invoice`,
},
body: JSON.stringify({
buyer: { name: "Exemplu Comert SRL", tax_id: "RO12345678", county: "Cluj", city: "Cluj-Napoca", country: "RO" },
lines: [{ description: "Abonament SaaS", quantity: 1, unit_price: 400, vat_rate: 21 }],
currency: "RON",
metadata: { order_id: String(orderId) },
}),
}).then((r) => r.json());
console.log(invoice.number, invoice.totals); // "FCT-000123" { net, vat, gross }python
import os, uuid, requests
BASE = "https://api.4invoices.net/v1"
token = requests.post(f"{BASE}/auth/token", json={
"grant_type": "client_credentials",
"client_id": os.environ["FOURINVOICES_CLIENT_ID"],
"client_secret": os.environ["FOURINVOICES_CLIENT_SECRET"],
}, timeout=30).json()["access_token"]
headers = {
"Authorization": f"Bearer {token}",
# Satu kunci per operasi LOGIS — pakai ulang saat mencoba lagi, jangan pernah membuat ulang.
"Idempotency-Key": f"order-{order_id}-invoice",
}
invoice = requests.post(f"{BASE}/invoices", headers=headers, json={
"buyer": {"name": "Exemplu Comert SRL", "tax_id": "RO12345678",
"county": "Cluj", "city": "Cluj-Napoca", "country": "RO"},
"lines": [{"description": "Abonament SaaS", "quantity": 1,
"unit_price": 400, "vat_rate": 21}], # persen, bukan 0,21
"currency": "RON",
}, timeout=60).json()
print(invoice["number"], invoice["totals"])Autentikasi
- Alurnya adalah client_credentials: Anda menukar client_id + client_secret dengan access_token Bearer.
- Token berakhir dalam 3600 detik. Perbarui sebelum kedaluwarsa, bukan di setiap panggilan — POST /auth/token memiliki batas laju per IP sendiri.
- client_secret hanya disimpan sebagai hash dan tidak dapat dipulihkan. Jika hilang, buat kredensial baru dan cabut yang lama.
- Hanya server-ke-server. Tidak ada origin browser yang diizinkan lewat CORS: dari JavaScript halaman, secret akan bocor ke pengunjung.
- Scope diberikan per kredensial. Terbitkan kredensial terpisah untuk setiap sistem dan berikan scope minimum yang dibutuhkannya.
Faktur → Pengaturan → Akses API
bash
curl -sS -X POST https://api.4invoices.net/v1/auth/token \
-H 'Content-Type: application/json' \
-d '{
"grant_type": "client_credentials",
"client_id": "cli_XXXXXXXXXXXX",
"client_secret": "sec_XXXXXXXXXXXXXXXXXXXX"
}'
# → {"access_token":"eyJ...","token_type":"Bearer","expires_in":3600,
# "scope":"invoices:read invoices:write efactura:submit"}javascript
// Simpan token dalam cache; jangan buat satu per permintaan.
let cached = { token: "", expiresAt: 0 };
async function getToken() {
if (cached.token && Date.now() < cached.expiresAt - 60_000) return cached.token;
const res = await fetch("https://api.4invoices.net/v1/auth/token", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
grant_type: "client_credentials",
client_id: process.env.FOURINVOICES_CLIENT_ID,
client_secret: process.env.FOURINVOICES_CLIENT_SECRET,
}),
});
if (!res.ok) throw new Error(`token ${res.status}`);
const data = await res.json();
cached = { token: data.access_token, expiresAt: Date.now() + data.expires_in * 1000 };
return cached.token;
}Tarif PPN adalah persen
vat_rate: 21 ✓ · vat_rate: 0.19 ✗ · vat_rate: 1 ✗- vat_rate adalah PERSEN: 21 berarti 21%.
- Nilai dalam rentang (0, 1] ditolak — 0,19 adalah pecahan, dan 1 ambigu antara 1% dan 100%.
- 0 valid dan berarti bebas pajak atau reverse charge; cantumkan keterangan hukumnya di notes.
- unit_price adalah harga satuan NETO jika penerbit adalah pembayar PPN.
- Perlu total sebelum Anda melakukan komitmen? POST /v1/invoices/preview-totals menjalankan aritmatika yang sama tanpa menggunakan nomor fiskal.
Idempotensi pada penulisan fiskal
- Header Idempotency-Key WAJIB ada pada POST /invoices, POST /invoices/{id}/storno, dan POST /invoices/{id}/efactura/submit.
- Kunci diingat selama 24 jam. Memutar ulang kunci yang sama dengan isi yang sama mengembalikan hasil asli dan menetapkan Idempotency-Replayed: true.
- Kunci yang sama dengan isi berbeda mengembalikan 409 idempotency_key_reuse — dokumen fiskal yang sudah diterbitkan tidak pernah ditimpa.
- Satu kunci untuk SETIAP operasi LOGIS, bukan setiap percobaan HTTP: order-10457-invoice, bukan UUID baru di setiap percobaan ulang.
- Alasannya bersifat hukum, bukan teknis: nomor fiskal yang sudah terpakai dan faktur yang sudah diajukan ke sistem faktur elektronik nasional tidak dapat ditarik kembali.
bash
curl -sS -X POST https://api.4invoices.net/v1/invoices \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: order-10457-invoice' \
-d '{
"buyer": {
"name": "Exemplu Comert SRL",
"tax_id": "RO12345678",
"address": "Str. Fabricii 12",
"city": "Cluj-Napoca",
"county": "Cluj",
"country": "RO",
"email": "[email protected]"
},
"lines": [
{ "description": "Abonament SaaS, iulie", "quantity": 1, "unit_price": 400, "vat_rate": 21, "unit": "buc" },
{ "description": "Implementare", "quantity": 6, "unit_price": 250, "vat_rate": 21, "unit": "ora" }
],
"currency": "RON",
"document_kind": "factura",
"due_date": "2026-08-15",
"metadata": { "order_id": "10457" }
}'Semua endpoint
| Metode | Endpoint | Scope | Idempotency-Key | Permintaan / menit |
|---|---|---|---|---|
| POST | /auth/token Tukar kredensial dengan access token | — | — | 120 |
| GET | /me Tenant, scope, dan batas saat ini | invoices:read | — | 120 |
| POST | /invoices Terbitkan faktur atau proforma | invoices:write | wajib | 30 |
| GET | /invoices Daftar faktur (paginasi kursor) | invoices:read | — | 120 |
| POST | /invoices/preview-totals Hitung total tanpa membuat apa pun | invoices:read | — | 120 |
| GET | /invoices/{invoice_id} Ambil satu faktur | invoices:read | — | 120 |
| GET | /invoices/{invoice_id}/pdf Unduh PDF faktur | invoices:read | — | 120 |
| GET | /invoices/{invoice_id}/xml Unduh XML UBL (CIUS-RO untuk Rumania) | invoices:read | — | 120 |
| POST | /invoices/{invoice_id}/storno Terbitkan nota kredit yang membatalkan faktur ini | invoices:write | wajib | 30 |
| POST | /invoices/{invoice_id}/payments Tandai faktur sebagai lunas | invoices:write | — | 30 |
| DELETE | /invoices/{invoice_id}/payments Tandai faktur sebagai belum lunas | invoices:write | — | 30 |
| GET | /clients Daftar klien | clients:read | — | 120 |
| POST | /clients Buat atau perbarui klien | clients:write | — | 30 |
| GET | /lookup/company/{tax_id} Validasi nomor pajak terhadap registri resmi (di Rumania: ANAF) | clients:read | — | 120 |
| GET | /series Daftar seri penomoran | invoices:read | — | 120 |
| POST | /invoices/{invoice_id}/efactura/validate Pemeriksaan awal — validasi tanpa mengirim | efactura:read | — | 120 |
| POST | /invoices/{invoice_id}/efactura/submit Ajukan faktur ke sistem faktur elektronik nasional | efactura:submit | wajib | 10 |
| GET | /efactura/submissions Daftar pengajuan ke sistem nasional | efactura:read | — | 120 |
| GET | /efactura/submissions/{submission_id} Ambil satu pengajuan | efactura:read | — | 120 |
| POST | /efactura/submissions/{submission_id}/refresh Minta status terkini dari sistem nasional | efactura:read | — | 10 |
| GET | /efactura/submissions/{submission_id}/download Unduh arsip respons bertanda tangan | efactura:read | — | 120 |
| GET | /efactura/inbox Faktur pemasok yang diterima melalui sistem nasional | efactura:read | — | 120 |
| GET | /efactura/inbox/{inbound_id} Ambil satu faktur masuk | efactura:read | — | 120 |
| GET | /efactura/inbox/{inbound_id}/download Unduh arsip faktur masuk | efactura:read | — | 120 |
| POST | /efactura/inbox/sync Tarik pesan baru dari sistem nasional ke kotak masuk | efactura:read | — | 10 |
25 endpoints · https://api.4invoices.net/v1/openapi.json
Scope
- invoices:read
- invoices:write
- clients:read
- clients:write
- efactura:read
- efactura:submit
Alur faktur elektronik nasional
- Pembeda utamanya: seluruh alur faktur elektronik nasional berjalan melalui API, bukan hanya pembuatan dokumen.
- POST /invoices/{id}/efactura/validate menjalankan pemeriksaan awal (CIUS-RO untuk Rumania) dan mengembalikan field persis yang akan ditolak sistem faktur elektronik nasional, tanpa mengirim apa pun.
- GET /invoices/{id}/xml menghasilkan XML UBL (CIUS-RO untuk Rumania) tanpa pengajuan — berguna untuk arsip Anda sendiri atau audit internal.
- POST /invoices/{id}/efactura/submit mengajukannya ke sistem faktur elektronik nasional. Ini tidak dapat dibatalkan: salinan kedua dari faktur yang sama tidak dapat ditarik dari sistem.
- Siklus hidupnya ternormalisasi: not_sent → validating → queued → sent → processing → accepted | rejected | error. accepted berarti telah dikirim secara sah; error adalah kegagalan transportasi di pihak kami dan aman untuk dicoba ulang.
- GET /efactura/submissions/{id}/download mengambil arsip dengan respons bertanda tangan dari sistem faktur elektronik nasional.
- Sisi masuk juga tersedia: POST /efactura/inbox/sync menarik pesan baru dari sistem faktur elektronik nasional dan GET /efactura/inbox mendaftar faktur yang dikirim pemasok Anda kepada Anda.
bash
# CIUS-RO preflight. Sends NOTHING to ANAF.
curl -sS -X POST "https://api.4invoices.net/v1/invoices/inv_01J7ABC/efactura/validate?include_xml=true" \
-H "Authorization: Bearer $ACCESS_TOKEN"
# → {"invoice_id":"inv_01J7ABC","valid":false,
# "errors":["buyer.county is required for RO buyers"],
# "xml_base64":"PD94bWwg..."}bash
curl -sS -X POST https://api.4invoices.net/v1/invoices/inv_01J7ABC/efactura/submit \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H 'Idempotency-Key: efactura-inv_01J7ABC-1'
# → {"submission_id":"sub_01J7XYZ","status":"queued"}python
import time, requests
BASE = "https://api.4invoices.net/v1"
TERMINAL = {"accepted", "rejected"}
H = {"Authorization": f"Bearer {token}"}
def wait_for_anaf(submission_id, timeout=900):
deadline = time.time() + timeout
delay = 15
while time.time() < deadline:
r = requests.get(f"{BASE}/efactura/submissions/{submission_id}", headers=H, timeout=30)
r.raise_for_status()
status = r.json()["status"]
if status in TERMINAL:
return r.json()
# /refresh asks ANAF directly and shares the 10/min submit bucket.
requests.post(f"{BASE}/efactura/submissions/{submission_id}/refresh", headers=H, timeout=30)
time.sleep(delay)
delay = min(delay * 2, 120)
raise TimeoutError(submission_id)Error
- Setiap 4xx dan 5xx menggunakan amplop yang sama: { "error": { type, code, message, param?, doc_url, request_id, errors? } }.
- type adalah kelas kasar yang Anda jadikan dasar percabangan ("bisakah saya mencoba lagi?"), dan code adalah alasan stabil yang Anda petakan ke sistem Anda sendiri.
- param adalah jalur bertitik ke field yang bermasalah, misalnya lines.0.vat_rate.
- errors[] muncul ketika satu permintaan bermasalah di lebih dari satu field.
- request_id dicatat di sisi kami. Sertakan dalam setiap tiket dukungan — ia menunjuk tepat ke permintaan tersebut.
- 404 juga dikembalikan untuk id yang milik tenant lain: kami tidak pernah mengonfirmasi bahwa data orang lain ada.
json
{
"error": {
"type": "invalid_request_error",
"code": "validation_failed",
"message": "Datele trimise nu sunt valide.",
"param": "lines.0.vat_rate",
"doc_url": "https://4invoices.net/ro/api-dezvoltatori#errors",
"request_id": "req_8a893f2f33d4472da8d6e144",
"errors": [
{ "param": "lines.0.vat_rate", "message": "VAT rate must be a percent (21), not a fraction", "type": "value_error" }
]
}
}| Status | Tipe | Kode |
|---|---|---|
| 401 | authentication_error | missing_bearer_token |
| 401 | authentication_error | invalid_client |
| 401 | authentication_error | token_expired |
| 401 | authentication_error | invalid_token |
| 401 | authentication_error | unauthorized |
| 403 | permission_error | insufficient_scope |
| 403 | permission_error | forbidden |
| 404 | not_found_error | not_found |
| 409 | conflict_error | idempotency_key_reuse |
| 409 | conflict_error | idempotency_in_progress |
| 409 | conflict_error | no_series_configured |
| 422 | invalid_request_error | validation_failed |
| 422 | invalid_request_error | issuer_profile_incomplete |
| 422 | invalid_request_error | cius_ro_incomplete |
| 422 | invalid_request_error | cannot_storno_draft |
| 422 | invalid_request_error | nothing_to_storno |
| 422 | invalid_request_error | invalid_json_number |
| 429 | rate_limit_error | rate_limit_exceeded |
| 502 | upstream_error | upstream_error |
| 503 | service_unavailable_error | service_unavailable |
Batas laju
| Ember | Permintaan / menit | Artinya |
|---|---|---|
| read | 120 | GET *, POST /invoices/preview-totals, POST /invoices/{id}/efactura/validate |
| write | 30 | POST /invoices, POST /invoices/{id}/storno, POST|DELETE /invoices/{id}/payments, POST /clients |
| submit | 10 | POST /invoices/{id}/efactura/submit, POST /efactura/submissions/{id}/refresh, POST /efactura/inbox/sync |
- Batas berlaku per kredensial, per menit: 120 untuk baca, 30 untuk tulis, dan 10 untuk operasi faktur elektronik (submit, refresh, inbox/sync).
- X-RateLimit-Limit, X-RateLimit-Remaining, dan X-RateLimit-Reset muncul di SETIAP respons, termasuk 429.
- 429 juga membawa Retry-After dalam detik. Patuhi; jangan mencoba ulang dalam loop ketat.
- Ember 10/menit ada karena di Rumania ANAF sendiri mengizinkan sekitar satu panggilan daftar pesan per menit per CIF.
- Jadwalkan /efactura/inbox/sync dengan cron, bukan dengan polling agresif.
- Perlu batas yang lebih tinggi? Ajukan melalui Kontak dengan perkiraan volume harian Anda.
X-RateLimit-Limit · X-RateLimit-Remaining · X-RateLimit-Reset · Retry-After
http
HTTP/2 429
X-RateLimit-Limit: 30
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1785312000
Retry-After: 17
Content-Type: application/json
{"error":{"type":"rate_limit_error","code":"rate_limit_exceeded",
"message":"...","doc_url":"https://4invoices.net/ro/api-dezvoltatori#errors",
"request_id":"req_..."}}javascript
// Patuhi Retry-After; jangan coba ulang 4xx selain 429.
async function call(url, init, attempt = 0) {
const res = await fetch(url, init);
if (res.status === 429 || res.status >= 500) {
if (attempt >= 5) return res;
const retryAfter = Number(res.headers.get("Retry-After")) || 2 ** attempt;
await new Promise((r) => setTimeout(r, retryAfter * 1000));
return call(url, init, attempt + 1);
}
return res;
}
// Percobaan ulang penulisan HARUS memakai Idempotency-Key yang SAMA, jika tidak Anda menerbitkan
// dokumen fiskal kedua.Panduan berdasarkan topik
Setiap topik memiliki halamannya sendiri dengan endpoint, contoh, dan error yang relevan.
- Autentikasi dengan API 4invoicesTukar client_id dan client_secret dengan token Bearer yang berlaku satu jam, hanya server-ke-server.
- Menerbitkan faktur melalui APIPOST /invoices dengan Idempotency-Key, PPN dalam persen, serta daftar, storno, dan penandaan lunas.
- Klien dan pencarian registri resmiPenyisipan atau pembaruan yang dideduplikasi berdasarkan tax_id, plus pencarian registri resmi (di Rumania: ANAF) agar faktur elektronik tidak ditolak.
- Faktur elektronik nasional melalui APIPemeriksaan awal (CIUS-RO untuk Rumania), pengajuan ke sistem nasional, status ternormalisasi, respons bertanda tangan, dan kotak masuk faktur pemasok.
- Seri penomoran dalam APITanpa seri aktif berjenis fiscale, penerbitan mengembalikan 409 no_series_configured.
- Kode error dan amplop errorSatu bentuk di setiap rute: type, code, message, param, doc_url, request_id, dan errors.
- Batas laju dan percobaan ulang120 baca, 30 tulis, dan 10 operasi faktur elektronik per menit per kredensial, dengan header X-RateLimit-*.
Kesalahan umum
- Mengirim PPN sebagai pecahan (0.19) atau sebagai 1. Keduanya ditolak; kirim 19 atau 21.
- Membuat token di setiap permintaan. Token berlaku satu jam; simpan dalam cache atau Anda akan terkena batas per IP endpoint token.
- Membuat Idempotency-Key baru di setiap percobaan ulang — justru skenario yang menghasilkan faktur ganda.
- Memanggil dari JavaScript browser. CORS memblokir setiap origin, dan secret akan terekspos juga.
- Mengajukan ke sistem faktur elektronik nasional tanpa pemeriksaan awal. Pengajuan yang salah tidak dapat ditarik kembali.
- Melakukan polling /efactura/submissions/{id}/refresh lebih dari 10 kali per menit — ember itu dibagi dengan submit.
- Menerbitkan sebelum profil perusahaan lengkap dan seri fiskal aktif tersedia.
Tanya jawab untuk pengembang
Bagaimana cara mendapatkan kredensial API 4invoices?
Di panel, pada Faktur → Pengaturan → Akses API. Anda mendapatkan client_id dan client_secret; secret hanya ditampilkan sekali dan disimpan sebagai hash.
Berapa lama access_token berlaku?
3600 detik, yaitu satu jam. Simpan dalam cache dan perbarui sebelum kedaluwarsa — endpoint token memiliki batas laju sendiri per IP.
Bagaimana cara mengirim tarif PPN?
Sebagai persen: 21 untuk 21%. Nilai dalam rentang (0, 1] ditolak, sehingga 0,19 dan 1 sama-sama gagal validasi.
Panggilan mana saja yang memerlukan Idempotency-Key?
POST /invoices, POST /invoices/{id}/storno, dan POST /invoices/{id}/efactura/submit. Kunci diingat selama 24 jam, dan pemutaran ulang mengembalikan dokumen asli dengan Idempotency-Replayed: true.
Bisakah saya mengirim faktur ke sistem faktur elektronik nasional langsung dari API?
Bisa. Jalankan pemeriksaan awal dengan /efactura/validate, ajukan dengan /efactura/submit, pantau status ternormalisasi di /efactura/submissions/{id}, dan unduh respons bertanda tangan dari sistem tersebut (di Rumania: ANAF).
Berapa batas lajunya?
Per kredensial, per menit: 120 baca, 30 tulis, dan 10 operasi faktur elektronik. Setiap respons membawa header X-RateLimit-*, dan respons 429 menambahkan Retry-After.
Bisakah saya memanggil API dari frontend saya?
Tidak. API ini hanya server-ke-server: tidak ada origin browser yang lolos CORS, dan client_secret tidak boleh ada di kode yang sampai ke pengunjung.
Mengapa saya mendapat issuer_profile_incomplete pada faktur pertama saya?
Profil perusahaan belum lengkap atau tidak ada seri aktif dengan jenis fiscale. Lengkapi keduanya di panel; API menolak menghasilkan dokumen fiskal yang tidak valid.