Autentikasi dengan API 4invoices

Tukar client_id dan client_secret dengan token Bearer yang berlaku satu jam, hanya server-ke-server.

Tukar client_id dan client_secret dengan token Bearer yang berlaku satu jam, hanya server-ke-server.

← Kembali ke dokumentasi API

Faktur pertama Anda dalam 6 langkah

  1. Buat kredensial di panel pada Faktur → Pengaturan → Akses API, lalu salin client_secret segera — secret hanya ditampilkan sekali.
  2. Kirim POST /v1/auth/token dengan grant_type client_credentials, client_id, dan client_secret.
  3. Anda menerima access_token, token_type Bearer, expires_in 3600, dan daftar scope yang diberikan.
  4. Tempatkan token di header Authorization: Bearer <access_token> pada setiap panggilan lainnya.
  5. Periksa apa yang sebenarnya Anda terima dengan GET /v1/me: tenant, scope, dan batas laju saat ini.

Semua endpoint

MetodeEndpointScopeIdempotency-KeyPermintaan / menit
POST/auth/token
Tukar kredensial dengan access token
——120
GET/me
Tenant, scope, dan batas saat ini
invoices:read—120

Apa itu API 4invoices

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"}
bash
curl -sS https://api.4invoices.net/v1/me \
  -H "Authorization: Bearer $ACCESS_TOKEN"

# → tenant, scope yang diberikan, dan ember batas laju saat ini
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;
}

https://api.4invoices.net/v1 · https://api.4invoices.net/v1/openapi.json

Scope

  • invoices:read
  • invoices:write
  • clients:read
  • clients:write
  • efactura:read
  • efactura:submit
Hanya server-ke-server. Jangan pernah memanggil API dari JavaScript browser: client_secret akan sampai ke pengunjung, dan CORS memblokir setiap origin.

Error

StatusTipeKode
401authentication_errorinvalid_client
401authentication_errortoken_expired
401authentication_errorinvalid_token
403permission_errorinsufficient_scope

Kesalahan umum

  • Endpoint token memiliki batas per IP sendiri. Satu token per proses, diperbarui sebelum kedaluwarsa — bukan satu per permintaan.
  • client_secret hanya disimpan sebagai hash; jika hilang, buat kredensial baru dan cabut yang lama.
  • Terbitkan kredensial terpisah untuk ERP, toko, dan skrip internal, masing-masing dengan scope minimal. Mencabut satu tidak memengaruhi yang lain.
  • CORS tidak mengizinkan origin browser: API ini server-ke-server sesuai desain.

Tanya jawab untuk pengembang

Apa yang terjadi jika client_secret salah?

Anda mendapat 401 dengan kode invalid_client. Secret yang terlalu pendek gagal lebih awal, saat validasi, dengan 422 validation_failed dan param client_secret.

Apakah ada sandbox terpisah?

Tidak. Hanya ada satu host produksi. Uji dengan proforma (document_kind proforma) dan dengan /invoices/preview-totals, yang tidak menggunakan nomor fiskal.

Bisakah saya mempersempit scope kredensial yang sudah ada?

Bisa, dari panel. Token yang sudah diterbitkan tetap memakai scope saat dibuat hingga kedaluwarsa, dalam satu jam.