INVOICEKU API v2

Dokumentasi API v2

API v2 dipakai untuk membuat tagihan QRIS, memantau status pembayaran, dan menerima notifikasi webhook. Setiap project punya API key sendiri, sehingga integrasi satu project tidak bercampur dengan project lain.

NominalInteger rupiah, tanpa desimal
WaktuISO-8601 UTC, contoh 2026-10-25T10:43:29Z
TransportHTTPS, JSON, wajib TLS
API v1 tetap berjalan. Dokumentasi v1 ada di /docs/api. Kedua versi memakai jalur terpisah dan key terpisah, jadi perpindahan ke v2 tidak memutus integrasi lama.

1. Persiapan

  1. Buat project di menu Projects bila belum ada. Project menentukan tujuan dana dan slug integrasi.
  2. Buka menu Developers, pilih project, lalu tab API Keys dan tekan Buat API Key. Key hanya ditampilkan sekali, simpan di tempat aman.
  3. Di tab Webhook, isi URL HTTPS server Anda, lalu buat signing secret.
  4. Uji dengan tombol Kirim Webhook Uji sebelum dipakai produksi.
Key v2 berbeda dari key v1. Key v1 di halaman Pengaturan hanya berlaku untuk API v1 dan tidak bisa dipakai di v2.

2. Autentikasi

Setiap permintaan wajib menyertakan header berikut.

HeaderWajibKeterangan
AuthorizationYaBearer <API_KEY>, key diawali ik_live_
Content-TypeUntuk POSTapplication/json
Idempotency-KeyUntuk POSTUUID v4, dibuat baru untuk setiap tagihan baru

Contoh request

GET https://invoiceku.net/api/v2/projects
Authorization: Bearer ik_live_xxxxxxxxxxxxxxxx

Contoh response

HTTP/1.1 200 OK
Content-Type: application/json

{
  "data": [
    {
      "id": "6",
      "slug": "toko-utama",
      "name": "Toko Utama",
      "status": "active"
    }
  ]
}

3. Idempotency

Jaringan bisa gagal di tengah jalan. Dengan Idempotency-Key, permintaan yang diulang dengan key dan body yang sama tidak akan membuat tagihan kedua.

SituasiYang terjadi
Key baruPermintaan diproses normal
Key sama, body samaResponse pertama dikirim ulang, ditandai header Idempotency-Replayed: true
Key sama, body berbeda409 IDEMPOTENCY_CONFLICT
Key sama, masih diproses409 IDEMPOTENCY_IN_PROGRESS
Key disimpan 24 jam. Simpan UUID yang Anda kirim agar bisa dipakai ulang saat retry.

4. Buat invoice

POST /api/v2/invoices

Membuat tagihan QRIS baru untuk project milik API key yang dipakai.

Auth: Header Authorization + Idempotency-Key

Parameter

NamaTipeWajibKeterangan
reference string Tidak Nomor tagihan Anda, maksimal 64 karakter, unik di dalam project. Bila kosong sistem membuat REF-...
amount integer Ya Nominal rupiah tanpa desimal. Isi 0 hanya untuk donasi bersama allow_customer_amount.
allow_customer_amount boolean Tidak Wajib true bila amount bernilai 0.
description string Tidak Keterangan tagihan yang tampil ke pembeli.
customer.name string Tidak Nama pembeli.
customer.email string Tidak Email pembeli. Dipakai untuk mengirim tagihan dan pemberitahuan refund.
customer.phone string Tidak Nomor telepon pembeli.
expires_in integer Tidak Masa berlaku tagihan dalam detik, 300 sampai 86400. Default 3600.
project_slug string Tidak Opsional. Bila diisi harus sama dengan project milik API key.

Contoh request

POST https://invoiceku.net/api/v2/invoices
Authorization: Bearer ik_live_xxxxxxxxxxxxxxxx
Idempotency-Key: 6f1c2b8e-9a4d-4f3b-8c21-1d2e3f4a5b6c
Content-Type: application/json

{
  "reference": "ORD-2026-0001",
  "amount": 50000,
  "description": "Pembelian Paket Premium",
  "customer": {
    "name": "Budi Santoso",
    "email": "budi@example.com"
  },
  "expires_in": 3600
}

Contoh response

HTTP/1.1 201 Created
X-Request-Id: req_01JBQ4A7QY3E1M8V6J2K5N0P9R
Content-Type: application/json

{
  "id": "5509",
  "reference": "ORD-2026-0001",
  "reference_source": "merchant",
  "invoice_code": "INV-0FC6-5158",
  "project": {
    "id": "6",
    "slug": "toko-utama",
    "name": "Toko Utama"
  },
  "status": "pending",
  "amount": 50207,
  "fee": 207,
  "net_amount": 50000,
  "customer": {
    "name": "Budi Santoso",
    "email": "budi@example.com",
    "phone": null
  },
  "description": "Pembelian Paket Premium",
  "payment_url": "https://invoiceku.net/invoice/INV-0FC6-5158",
  "qr_string": "00020101021126610016ID.CO.SHOPEE...",
  "created_at": "2026-10-25T10:43:29Z",
  "expires_at": "2026-10-25T11:43:30Z",
  "paid_at": null,
  "refunded_at": null
}

5. Ambil satu invoice

GET /api/v2/invoices/{reference}

Mengambil detail invoice memakai reference milik Anda atau invoice_code dari InvoiceKu.

Auth: Header Authorization

Contoh request

GET https://invoiceku.net/api/v2/invoices/ORD-2026-0001
Authorization: Bearer ik_live_xxxxxxxxxxxxxxxx

Contoh response

HTTP/1.1 200 OK
Content-Type: application/json

{
  "id": "5509",
  "reference": "ORD-2026-0001",
  "reference_source": "merchant",
  "invoice_code": "INV-0FC6-5158",
  "status": "paid",
  "amount": 50207,
  "fee": 207,
  "net_amount": 50000,
  "payment_url": "https://invoiceku.net/invoice/INV-0FC6-5158",
  "created_at": "2026-10-25T10:43:29Z",
  "expires_at": "2026-10-25T11:43:30Z",
  "paid_at": "2026-10-25T10:45:02Z",
  "refunded_at": null
}

6. Daftar invoice

GET /api/v2/invoices

Menampilkan invoice milik project dengan pagination cursor.

Auth: Header Authorization

Parameter

NamaTipeWajibKeterangan
status query Tidak pending, paid, expired, failed, atau refunded.
project_slug query Tidak Filter project (harus project milik key).
created_from query Tidak Batas awal waktu, format ISO-8601.
created_to query Tidak Batas akhir waktu, format ISO-8601.
limit query Tidak Jumlah data per halaman, 1 sampai 100. Default 20.
cursor query Tidak Nilai next_cursor dari halaman sebelumnya.

Contoh request

GET https://invoiceku.net/api/v2/invoices?status=paid&limit=20
Authorization: Bearer ik_live_xxxxxxxxxxxxxxxx

Contoh response

HTTP/1.1 200 OK
Content-Type: application/json

{
  "data": [
    {
      "id": "5509",
      "reference": "ORD-2026-0001",
      "invoice_code": "INV-0FC6-5158",
      "status": "paid",
      "amount": 50207,
      "net_amount": 50000,
      "paid_at": "2026-10-25T10:45:02Z"
    }
  ],
  "has_more": true,
  "next_cursor": "5460"
}

7. Batalkan invoice

POST /api/v2/invoices/{reference}/cancel

Membatalkan invoice yang masih pending. Invoice yang sudah dibayar tidak dapat dibatalkan.

Auth: Header Authorization + Idempotency-Key

Parameter

NamaTipeWajibKeterangan
reason string Tidak Alasan pembatalan, maksimal 255 karakter.

Contoh request

POST https://invoiceku.net/api/v2/invoices/ORD-2026-0001/cancel
Authorization: Bearer ik_live_xxxxxxxxxxxxxxxx
Idempotency-Key: 9c1b7e44-2f1a-4c8e-9b77-0a1b2c3d4e5f
Content-Type: application/json

{
  "reason": "Pembeli membatalkan pesanan"
}

Contoh response

HTTP/1.1 200 OK
Content-Type: application/json

{
  "id": "5509",
  "reference": "ORD-2026-0001",
  "invoice_code": "INV-0FC6-5158",
  "status": "failed",
  "amount": 50207,
  "net_amount": 50000
}

8. Project milik key

GET /api/v2/projects

Menampilkan project yang terkait dengan API key. Satu key hanya untuk satu project.

Auth: Header Authorization

Contoh request

GET https://invoiceku.net/api/v2/projects
Authorization: Bearer ik_live_xxxxxxxxxxxxxxxx

Contoh response

HTTP/1.1 200 OK
Content-Type: application/json

{
  "data": [
    {
      "id": "6",
      "slug": "toko-utama",
      "name": "Toko Utama",
      "status": "active",
      "callback_url": null,
      "webhook_url": "https://toko.example.com/webhook/invoiceku"
    }
  ]
}

9. Webhook

Webhook dikirim ke URL yang Anda isi di menu Developers, tab Webhook. Setiap project punya URL dan secret sendiri.

Event

EventKapan dikirim
invoice.paidPembayaran diterima
invoice.expiredTagihan melewati batas waktu
invoice.failedTagihan dibatalkan atau gagal
invoice.refundedTagihan direfund ke customer
webhook.testUji koneksi dari halaman Developers

Header

POST /webhook/invoiceku HTTP/1.1
Content-Type: application/json
X-InvoiceKu-Event: invoice.paid
X-InvoiceKu-Event-Signature: t=1793000000,v1=6f1c2b8e9a4d4f3b8c211d2e3f4a5b6c7d8e9f0a1b2c3d4e5f60718293a4b5c6
X-InvoiceKu-Signature: 9b2d...47
X-InvoiceKu-Timestamp: 1793000000

Contoh payload

{
  "event": "invoice.paid",
  "delivery_id": null,
  "invoice": {
    "id": "5509",
    "reference": "ORD-2026-0001",
    "reference_source": "merchant",
    "invoice_code": "INV-0FC6-5158",
    "project": {
      "id": "6",
      "slug": "toko-utama",
      "name": "Toko Utama"
    },
    "status": "paid",
    "amount": 50207,
    "fee": 207,
    "net_amount": 50000,
    "customer": {
      "name": "Budi Santoso",
      "email": "budi@example.com",
      "phone": null
    },
    "payment_url": "https://invoiceku.net/invoice/INV-0FC6-5158",
    "created_at": "2026-10-25T10:43:29Z",
    "expires_at": "2026-10-25T11:43:30Z",
    "paid_at": "2026-10-25T10:45:02Z",
    "refunded_at": null
  }
}

Verifikasi tanda tangan

Ambil nilai t dan v1 dari header, lalu bandingkan hasil HMAC berikut.

<?php
$rawBody = file_get_contents('php://input');
$header  = $_SERVER['HTTP_X_INVOICEKU_EVENT_SIGNATURE'] ?? '';
$secret  = 'secret_dari_halaman_developers';

if (!preg_match('/t=(\d+),v1=([a-f0-9]{64})/', $header, $m)) {
    http_response_code(400);
    exit('signature tidak valid');
}

$timestamp = (int) $m[1];

if (abs(time() - $timestamp) > 300) {
    http_response_code(400);
    exit('timestamp kedaluwarsa');
}

$expected = hash_hmac('sha256', $timestamp . '.' . $rawBody, $secret);

if (!hash_equals($expected, $m[2])) {
    http_response_code(400);
    exit('signature tidak cocok');
}

http_response_code(200);
echo 'ok';

Kebijakan pengiriman

AturanNilai
Dianggap berhasilBalasan HTTP 2xx dalam 10 detik
Percobaan ulangMaksimal 8 kali: 1m, 5m, 15m, 1j, 3j, 6j, 12j, 24j
DuplikatMungkin terjadi, proses secara idempoten memakai invoice.invoice_code
RiwayatMenu Developers, tab Event Log

10. Alur aman di sisi Anda

  1. Simpan reference tagihan di database Anda sebelum mengirim permintaan.
  2. Buat Idempotency-Key baru (UUID v4) saat pertama kali membuat tagihan.
  3. Bila permintaan gagal karena timeout, ulangi dengan key yang sama, bukan key baru.
  4. Jangan mengandalkan webhook saja. Saat pembeli kembali ke halaman sukses, panggil endpoint ambil invoice untuk memastikan status.
  5. Pada webhook, balas 200 segera setelah validasi tanda tangan, lalu proses di belakang.

11. Kode error

Semua error memakai bentuk yang sama.

HTTP/1.1 422 Unprocessable Entity
Content-Type: application/json

{
  "error": {
    "code": "AMOUNT_BELOW_MINIMUM",
    "message": "Nominal minimal Rp 1.000.",
    "request_id": "req_01JBQ4A7QY3E1M8V6J2K5N0P9R"
  }
}

Sertakan request_id ketika menghubungi support agar penelusuran cepat.

HTTPCodeArti
400INVALID_JSONBody bukan JSON yang sah
400INVALID_IDEMPOTENCY_KEYHeader Idempotency-Key bukan UUID v4
401UNAUTHORIZEDHeader Authorization tidak ada atau format salah
401INVALID_API_KEYAPI key tidak terdaftar
401KEY_REVOKEDAPI key sudah dicabut
403PROJECT_FORBIDDENProject pada body bukan milik key
403PROJECT_INACTIVEProject terkait key tidak aktif
404INVOICE_NOT_FOUNDInvoice tidak ditemukan
404PROJECT_NOT_FOUNDProject tidak ditemukan
405METHOD_NOT_ALLOWEDMetode HTTP tidak didukung
409IDEMPOTENCY_CONFLICTIdempotency-Key sudah dipakai untuk body berbeda
409IDEMPOTENCY_IN_PROGRESSPermintaan dengan key yang sama masih diproses
409INVOICE_STATE_CONFLICTStatus invoice tidak mengizinkan aksi
409REFERENCE_DUPLICATEReference sudah dipakai di project ini
422AMOUNT_REQUIREDField amount tidak diisi
422AMOUNT_BELOW_MINIMUMNominal di bawah batas minimum
422AMOUNT_ABOVE_MAXIMUMNominal melebihi batas maksimum
422DONATION_FLAG_REQUIREDamount bernilai 0 tanpa allow_customer_amount
422VALIDATION_FAILEDFormat field lain tidak sah
429RATE_LIMITEDMelebihi kuota permintaan
500INTERNAL_ERRORKesalahan pada server
503GATEWAY_UNAVAILABLEGateway pembayaran sedang sibuk

12. Rate limit

120 permintaan per menit untuk setiap API key project.

Header responKeterangan
X-Request-IdID permintaan untuk penelusuran
X-RateLimit-LimitBatas permintaan per menit
X-RateLimit-RemainingSisa kuota pada menit berjalan
X-RateLimit-ResetWaktu pengisian ulang kuota (epoch detik)
Retry-AfterHanya pada 429, jumlah detik untuk menunggu

13. Riwayat perubahan

VersiTanggalIsi
2.0 25 Oktober 2026 Rilis awal: API key per project, Idempotency-Key, rate limit, cursor pagination, webhook bertanda tangan.

API v1 tetap tersedia di /docs/api. Butuh bantuan? Buka menu Bantuan & Tiket di dashboard.