4invoices-julkinen API siirtää laskutustietosi järjestelmästäsi 4invoicesiin ja vie laskun kansalliseen sähkölaskujärjestelmään asti (Romaniassa ANAF SPV). Yksi tuotantoisäntä, yksi client_credentials-kulku, idempotentit verotukselliset kirjoitukset ja yksi virhevastausrakenne jokaisessa reitissä.
https://api.4invoices.net/v1 · OpenAPI-määrittely (ei avainta)
Mitä 4invoices-API on
- 4invoicesin julkinen API on REST HTTPS-yhteydellä, JSON sisään ja JSON ulos.
- Yksi tuotantoisäntä: https://api.4invoices.net/v1. Erillistä testiisäntää ei ole.
- OpenAPI 3.1 -määrittely on julkinen ja avaimeton — tuo se suoraan Postmaniin tai asiakasgeneraattoriin.
- Jokaisessa vastauksessa on X-Request-Id-otsikko; mainitse se, kun pyydät tukea.
- Jokainen verotuksellinen kirjoitus on idempotentti: uudelleenyritys aikakatkaisun jälkeen ei koskaan luo toista asiakirjaa.
- Koko kansallisen sähkölaskujärjestelmän kierros API:n kautta (Romaniassa ANAF e-Factura): esitarkistus, lähetys, seuranta, allekirjoitettu vastaus ja saapuva postilaatikko. Yksikään romanialainen kilpailija ei tarjoa tätä.
- SmartBillillä ei ole yhtään päätepistettä laskujen lähettämiseen kansalliseen sähkölaskujärjestelmään (Romaniassa ANAF) — lähetys on pelkkä käyttöliittymän tiliasetus — eikä sillä ole lainkaan laskulistauspäätepistettä.
- Oblio voi luoda asiakkaita ja tuotteita vain asiakirjan laskemisen sivuvaikutuksena, ei ensiluokkaisina resursseina.
- UBL-XML:n luonti (Romaniassa CIUS-RO) ilman lähettämistä: saat laillisen asiakirjan tiedostona koskematta kansalliseen sähkölaskujärjestelmään.
- Idempotenssi verotuksellisissa kirjoituksissa: uudelleenyritys aikakatkaisun jälkeen ei tuota toista laskua eikä polta toista numeroa.
- Ohjelmallisesti luettava toimittajalaskujen postilaatikko — automaattisen täsmäytyksen perusta.
Ensimmäinen lasku 6 vaiheessa
- Luo tunnus paneelissa kohdassa Laskutus → Asetukset → API-käyttöoikeudet ja kopioi client_secret — se näytetään vain kerran.
- Täydennä yritysprofiili ja aktivoi vähintään yksi verotuksellinen sarja (fiscale), muuten laskutus palauttaa issuer_profile_incomplete- tai no_series_configured-virheen.
- Luo tunnus paneelissa kohdassa Laskutus → Asetukset → API-käyttöoikeudet ja kopioi client_secret — se näytetään vain kerran.
- Täydennä yritysprofiili ja aktivoi vähintään yksi verotuksellinen sarja (fiscale), muuten laskutus palauttaa issuer_profile_incomplete- tai no_series_configured-virheen.
- Vaihda tunnus tokeniin: POST /v1/auth/token, grant_type client_credentials. Token on voimassa tunnin — välimuistita se, älä hae uutta jokaiseen pyyntöön.
- Luo lasku: POST /v1/invoices, Idempotency-Key-otsikko mukana ja vat_rate prosenttina (21, ei 0.21).
- Suorita esitarkistus (Romaniassa CIUS-RO) kutsulla POST /v1/invoices/{id}/efactura/validate ja lähetä lasku kansalliseen sähkölaskujärjestelmään kutsulla POST /v1/invoices/{id}/efactura/submit.
- Seuraa tilaa kutsulla GET /v1/efactura/submissions/{id}, kunnes se saavuttaa tilan accepted tai rejected.
bash
# 1 — token (1 tunti, välimuistita se)
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 — myönnä lasku (Idempotency-Key on PAKOLLINEN)
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}",
# Yksi avain LOOGISTA toimintoa kohden — käytä sitä uudelleen yrityksessä, älä luo uutta.
"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}], # prosentti, ei 0.21
"currency": "RON",
}, timeout=60).json()
print(invoice["number"], invoice["totals"])Todennus
- Kulku on client_credentials: vaihdat client_id + client_secret -parit Bearer-access_tokeniin.
- Token vanhenee 3600 sekunnissa. Uusi se ennen vanhenemista, älä joka kutsulla — POST /auth/token -päätepisteellä on oma IP-kohtainen kutsurajoituksensa.
- client_secret tallennetaan vain tiivisteenä eikä sitä voi palauttaa. Jos menetät sen, luo uusi tunnus ja peruuta vanha.
- Vain palvelin-palvelin-yhteys. CORS ei päästä yhtään selaimen alkuperää läpi: sivun JavaScriptistä secret vuotaisi kävijälle.
- Scopet myönnetään tunnuskohtaisesti. Luo erillinen tunnus jokaiselle järjestelmälle ja anna kullekin vähimmät tarvittavat scopet.
Laskutus → Asetukset → API-käyttöoikeudet
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
// Välimuistita token; älä luo uutta jokaiseen pyyntöön.
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;
}ALV-kannat ovat prosentteja
vat_rate: 21 ✓ · vat_rate: 0.19 ✗ · vat_rate: 1 ✗- vat_rate on PROSENTTI: 21 tarkoittaa 21 %.
- Arvot välillä (0, 1] hylätään — 0.19 on murto-osa, ja 1 on epäselvä (1 % vai 100 %).
- 0 on sallittu ja tarkoittaa vapautusta tai käännettyä verovelvollisuutta; kirjoita lakiviite kenttään notes.
- unit_price on NETTO-yksikköhinta, kun laskuttaja on ALV-velvollinen.
- Tarvitsetko summat ennen sitoutumista? POST /v1/invoices/preview-totals suorittaa saman laskennan kuluttamatta verotuksellista numeroa.
Idempotenttisuus verotuksellisissa kirjoituksissa
- Idempotency-Key-otsikko on PAKOLLINEN kutsuissa POST /invoices, POST /invoices/{id}/storno ja POST /invoices/{id}/efactura/submit.
- Avaimet muistetaan 24 tuntia. Saman avaimen toisto samalla rungolla palauttaa alkuperäisen tuloksen ja asettaa Idempotency-Replayed: true.
- Sama avain eri rungolla palauttaa 409 idempotency_key_reuse — jo myönnettyä verotuksellista asiakirjaa ei koskaan ylikirjoiteta.
- Yksi avain LOOGISTA toimintoa kohden, ei HTTP-yritystä kohden: order-10457-invoice, ei uutta UUID:ta jokaisella uudelleenyrityksellä.
- Syy on oikeudellinen, ei tekninen: kulutettua verotuksellista numeroa ja kansalliseen sähkölaskujärjestelmään kirjattua laskua ei voi peruuttaa.
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" }
}'Kaikki päätepisteet
| Metodi | Päätepiste | Scope | Idempotency-Key | Pyyntöjä / minuutti |
|---|---|---|---|---|
| POST | /auth/token Vaihda tunnistetiedot access-tokeniin | — | — | 120 |
| GET | /me Tenant, scopet ja nykyiset rajat | invoices:read | — | 120 |
| POST | /invoices Myönnä lasku tai proformalasku | invoices:write | pakollinen | 30 |
| GET | /invoices Listaa laskut (kursoripohjainen sivutus) | invoices:read | — | 120 |
| POST | /invoices/preview-totals Laske summat luomatta mitään | invoices:read | — | 120 |
| GET | /invoices/{invoice_id} Hae yksi lasku | invoices:read | — | 120 |
| GET | /invoices/{invoice_id}/pdf Lataa laskun PDF | invoices:read | — | 120 |
| GET | /invoices/{invoice_id}/xml Lataa UBL-XML (Romaniassa CIUS-RO) | invoices:read | — | 120 |
| POST | /invoices/{invoice_id}/storno Myönnä hyvityslasku, joka peruu tämän laskun | invoices:write | pakollinen | 30 |
| POST | /invoices/{invoice_id}/payments Merkitse lasku maksetuksi | invoices:write | — | 30 |
| DELETE | /invoices/{invoice_id}/payments Merkitse lasku maksamattomaksi | invoices:write | — | 30 |
| GET | /clients Listaa asiakkaat | clients:read | — | 120 |
| POST | /clients Luo tai päivitä asiakas | clients:write | — | 30 |
| GET | /lookup/company/{tax_id} Validoi CUI Romanian ANAF-rekisteriä vasten | clients:read | — | 120 |
| GET | /series Listaa numerosarjat | invoices:read | — | 120 |
| POST | /invoices/{invoice_id}/efactura/validate Esitarkistus (Romaniassa CIUS-RO) — validoi lähettämättä | efactura:read | — | 120 |
| POST | /invoices/{invoice_id}/efactura/submit Lähetä lasku kansalliseen sähkölaskujärjestelmään | efactura:submit | pakollinen | 10 |
| GET | /efactura/submissions Listaa sähkölaskujärjestelmän lähetykset | efactura:read | — | 120 |
| GET | /efactura/submissions/{submission_id} Hae yksi lähetys | efactura:read | — | 120 |
| POST | /efactura/submissions/{submission_id}/refresh Kysy nykyinen tila sähkölaskujärjestelmästä | efactura:read | — | 10 |
| GET | /efactura/submissions/{submission_id}/download Lataa allekirjoitettu vastausarkisto | efactura:read | — | 120 |
| GET | /efactura/inbox Kansallisen sähkölaskujärjestelmän kautta vastaanotetut toimittajalaskut | efactura:read | — | 120 |
| GET | /efactura/inbox/{inbound_id} Hae yksi saapuva lasku | efactura:read | — | 120 |
| GET | /efactura/inbox/{inbound_id}/download Lataa saapuvan laskun arkisto | efactura:read | — | 120 |
| POST | /efactura/inbox/sync Hae uudet viestit kansallisesta sähkölaskujärjestelmästä postilaatikkoon | efactura:read | — | 10 |
25 endpoints · https://api.4invoices.net/v1/openapi.json
Scopet
- invoices:read
- invoices:write
- clients:read
- clients:write
- efactura:read
- efactura:submit
Kansallinen sähkölaskujärjestelmä
- Todellinen erottuva tekijä: koko kansallisen sähkölaskujärjestelmän kierros (Romaniassa ANAF e-Factura) kulkee API:n kautta, ei pelkkä asiakirjan luonti.
- POST /invoices/{id}/efactura/validate suorittaa esitarkistuksen (Romaniassa CIUS-RO) ja palauttaa täsmälleen ne kentät, jotka kansallinen sähkölaskujärjestelmä hylkäisi, lähettämättä mitään.
- GET /invoices/{id}/xml luo UBL-XML:n (Romaniassa CIUS-RO) ilman lähetystä — hyödyllinen omaan arkistoon tai sisäiseen tarkastukseen.
- POST /invoices/{id}/efactura/submit kirjaa laskun kansalliseen sähkölaskujärjestelmään. Tämä on peruuttamatonta: saman laskun toista kopiota ei voi vetää järjestelmästä pois.
- Elinkaari on normalisoitu: not_sent → validating → queued → sent → processing → accepted | rejected | error. accepted tarkoittaa laillisesti lähetetty; error on meidän puolen siirtovirhe ja sen voi turvallisesti yrittää uudelleen.
- GET /efactura/submissions/{id}/download hakee arkiston kansallisen sähkölaskujärjestelmän allekirjoitetun vastauksen kanssa.
- Saapuva puoli on myös olemassa: POST /efactura/inbox/sync hakee uudet viestit kansallisesta sähkölaskujärjestelmästä ja GET /efactura/inbox listaa toimittajiesi lähettämät laskut.
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)Virheet
- Jokainen 4xx- ja 5xx-vastaus käyttää samaa rakennetta: { "error": { type, code, message, param?, doc_url, request_id, errors? } }.
- type on karkea luokka, jonka mukaan haarautat (”voinko yrittää uudelleen?”), ja code on pysyvä syy, jonka kuvaat omaan järjestelmääsi.
- param on virheellisen kentän pistemerkitty polku, esimerkiksi lines.0.vat_rate.
- errors[] ilmestyy, kun yhdellä pyynnöllä on ongelmia useammassa kuin yhdessä kentässä.
- request_id kirjataan meidän puolellemme. Mainitse se jokaisessa tukipyynnössä — se yksilöi tarkan pyynnön.
- 404 palautetaan myös toisen tenantin tunnisteelle: emme koskaan vahvista, että jonkun muun tiedot ovat olemassa.
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" }
]
}
}| Tila | Tyyppi | Koodi |
|---|---|---|
| 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 |
Kutsurajoitukset
| Ryhmä | Pyyntöjä / minuutti | Mitä se tarkoittaa |
|---|---|---|
| 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 |
- Rajat ovat tunnuskohtaisesti minuutissa: 120 lukua, 30 kirjoitusta, 10 sähkölaskujärjestelmän operaatiota (submit, refresh, inbox/sync).
- X-RateLimit-Limit, X-RateLimit-Remaining ja X-RateLimit-Reset esiintyvät JOKAISESSA vastauksessa, myös 429:ssä.
- 429-vastaus sisältää myös Retry-After-arvon sekunteina. Noudata sitä; älä yritä uudelleen tiukassa silmukassa.
- 10/min-ryhmä on olemassa, koska Romanian ANAF sallii noin yhden viestilistauskutsun minuutissa verotunnistetta (CIF) kohden.
- Aseta /efactura/inbox/sync ajastukseen (cron), älä aggressiiviseen kyselyyn.
- Tarvitsetko korkeampia rajoja? Pyydä Yhteydenotto-sivun kautta ilmoittamalla odotettu päiväkohtainen volyymi.
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
// Noudata Retry-After-arvoa; älä yritä uudelleen mitään 4xx-virhettä paitsi 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;
}
// Kirjoituksen uudelleenyrityksessä on käytettävä SAMAA Idempotency-Keytä, muuten myönnät
// toisen verotuksellisen asiakirjan.Oppaat aiheittain
Jokaisella aiheella on oma sivunsa, jossa ovat siihen liittyvät päätepisteet, esimerkit ja virheet.
- Todennus 4invoices-API:ssaVaihda client_id ja client_secret yhden tunnin Bearer-tokeniin — vain palvelin-palvelin-yhteydessä.
- Laskujen myöntäminen API:n kauttaPOST /invoices Idempotency-Keyllä, ALV prosentteina, sekä listaus, hyvitys ja merkintä maksetuksi.
- Asiakkaat ja haku virallisesta yritysrekisteristätax_id:llä deduplikoitu lisäys tai päivitys (upsert) sekä yritysrekisterihaku (Romaniassa ANAF), jotta sähkölaskua ei hylätä.
- Kansallinen sähkölaskujärjestelmä API:n kauttaEsitarkistus (Romaniassa CIUS-RO), lähetys järjestelmään, normalisoitu tila, allekirjoitettu vastaus ja saapuva toimittajapostilaatikko.
- Numerosarjat API:ssaIlman aktiivista verotuksellista sarjaa (fiscale) laskutus palauttaa 409 no_series_configured.
- Virhekoodit ja virhevastauksen rakenneYksi muoto jokaisessa reitissä: type, code, message, param, doc_url, request_id ja errors.
- Kutsurajoitukset ja uudelleenyritykset120 lukua, 30 kirjoitusta ja 10 sähkölaskujärjestelmän operaatiota minuutissa tunnusta kohden, X-RateLimit-*-otsikoilla.
Yleiset virheet
- ALV lähetetään murto-osana (0.19) tai arvona 1. Molemmat hylätään; lähetä 19 tai 21.
- Tokenin luonti jokaiseen pyyntöön. Token on voimassa tunnin; välimuistita se, muuten osut token-päätepisteen IP-kohtaiseen rajaan.
- Uuden idempotency-avaimen luominen jokaisella uudelleenyrityksellä — juuri se skenaario, joka tuottaa kaksoislaskuja.
- Kutsuminen selaimen JavaScriptistä. CORS estää kaikki alkuperät, ja secret paljastuisi joka tapauksessa.
- Lähettäminen kansalliseen sähkölaskujärjestelmään ilman esitarkistusta. Väärää lähetystä ei voi peruuttaa.
- /efactura/submissions/{id}/refresh-kutsun pollaus useammin kuin 10 kertaa minuutissa — tämä ryhmä on jaettu lähetyksen kanssa.
- Laskutus ennen kuin yritysprofiili on valmis ja aktiivinen verotuksellinen sarja on olemassa.
Kehittäjien kysymykset ja vastaukset
Miten saan 4invoices-API-tunnukset?
Paneelissa kohdassa Laskutus → Asetukset → API-käyttöoikeudet. Saat client_id:n ja client_secretin; secret näytetään kerran ja tallennetaan vain tiivisteenä.
Kuinka pitkään access_token on voimassa?
3600 sekuntia eli yhden tunnin. Välimuistita se ja uusi ennen vanhenemista — tokenin päätepisteellä on oma IP-kohtainen kutsurajoituksensa.
Miten lähetän ALV-kannan?
Prosenttina: 21 tarkoittaa 21 %. Arvot välillä (0, 1] hylätään, joten sekä 0.19 että 1 epäonnistuvat validoinnissa.
Mitkä kutsut vaativat Idempotency-Keyn?
POST /invoices, POST /invoices/{id}/storno ja POST /invoices/{id}/efactura/submit. Avaimet muistetaan 24 tuntia, ja uudelleentoisto palauttaa alkuperäisen asiakirjan sekä otsikon Idempotency-Replayed: true.
Voinko lähettää laskun suoraan kansalliseen sähkölaskujärjestelmään API:n kautta?
Kyllä — Romanian markkinalla ANAF e-Factura -järjestelmään. Suorita esitarkistus kutsulla /efactura/validate, lähetä lasku kutsulla /efactura/submit, kysy normalisoitu tila kohteesta /efactura/submissions/{id} ja lataa järjestelmän allekirjoitettu vastaus.
Mitkä ovat kutsurajoitukset?
Tunnuskohtaisesti minuutissa: 120 lukua, 30 kirjoitusta ja 10 sähkölaskujärjestelmän operaatiota. Jokainen vastaus sisältää X-RateLimit-* -otsikot, ja 429-vastaukseen lisätään Retry-After.
Voinko kutsua API:a frontendistäni?
Ei. Se on pelkästään palvelin-palvelin-yhteyttä varten: mikään selaimen alkuperä ei läpäise CORS:ia, eikä client_secretille ole paikkaa koodissa, joka päätyy kävijälle.
Miksi ensimmäisessä laskussani tulee issuer_profile_incomplete?
Yritysprofiili on puutteellinen tai aktiivista verotuksellista sarjaa ei ole. Täytä molemmat paneelissa; API kieltäytyy tuottamasta virheellistä verotuksellista asiakirjaa.