Lewati ke konten
Integrasi API QRIS

API QRIS untuk Aplikasi Kasir dan POS

Kasir tidak perlu lagi melirik HP untuk memastikan pembayaran masuk.

Halaman ini bagian dari layanan API QRIS gratis APIQris: pakai QRIS milik Anda sendiri, tanpa potongan dari kami, dana langsung ke rekening Anda.

  • 0% fee APIQris
  • Dana langsung ke Anda
  • Webhook HMAC

Jawaban singkatAPI QRIS untuk POS membuat aplikasi kasir menampilkan QRIS dengan nominal belanja di layar pelanggan atau mencetaknya di struk. Saat pelanggan membayar, POS menerima status lunas lewat webhook atau polling sehingga transaksi otomatis tertutup.

Ingin tahu gambaran besarnya dulu? Baca juga pengertian QRIS API dan bagaimana API QRIS gratis APIQris menghubungkan QRIS Anda ke website, aplikasi, dan chatbot.

Rp0potongan dari APIQris
24/7konfirmasi otomatis
100%dana ke rekening Anda
Masalah

Tanpa API QRIS kasir POS, ini yang biasa terjadi

Pesanan menumpuk malam hari

Pembeli bayar jam 11 malam, pesanan baru diproses pagi karena menunggu admin.

Plugin gateway mahal

Biaya per transaksi plus biaya penarikan menggerus margin yang sudah tipis.

Konfirmasi manual di chat

Admin harus membalas "sudah masuk kak" satu per satu.

Data tersebar

Status bayar ada di aplikasi merchant, pesanan ada di sistem, rekap jadi kerja dua kali.

Solusinya: API QRIS kasir POS dari APIQris mengotomatiskan semuanya, tanpa mengganti QRIS yang sudah Anda punya.

Panduan

Memahami API QRIS kasir POS secara lengkap

01

Masalah kasir dengan QRIS statis

Pelanggan salah ketik nominal, kasir harus membuka HP untuk cek notifikasi, antrean menumpuk saat jam sibuk. QRIS dinamis menyelesaikan ketiganya.

02

Pilihan tampilan

Beberapa cara menampilkan QR di toko fisik:

  • Layar kedua menghadap pelanggan
  • Tablet di meja kasir
  • Cetak di printer thermal 58/80 mm
  • Halaman kasir web di browser
03

Tetap jalan di banyak cabang

Setiap cabang dapat memakai QRIS dan HP pendeteksinya sendiri, dengan laporan terpusat di satu dashboard.

Cara kerja

Alur API QRIS kasir POS dari scan sampai lunas

Dana dan data berjalan di jalur berbeda. Uang pembeli langsung ke QRIS Anda, APIQris hanya mengurus QRIS dinamis, pencocokan, dan webhook.

Infografis cara kerja API QRIS APIQris Dana pembeli mengalir dari pembeli ke penyedia QRIS lalu langsung ke rekening Anda. Jalur data terpisah: notifikasi dari HP merchant Anda dibaca APIQris lalu dikirim sebagai webhook ke website atau bot Anda. Rp Rp bayar dana langsung notifikasi kirim mutasi webhook buat tagihan → tampilkan QRIS dinamis ke pembeli Pembeli Scan & bayar Penyedia QRISAnda Bank / e-wallet Rekening Anda Langsung ke Anda HP MerchantAnda Notif dana masuk APIQris Cocokkan tagihan Website /Bot Anda Webhook lunas APIQris tidak menyentuh dana
Jalur dana: pembeli → penyedia QRIS → rekening Anda Jalur data: notifikasi → APIQris → webhook ke sistem Anda
  1. 1

    Daftar gratis

    Buat akun APIQris dengan email, tanpa biaya dan tanpa dokumen perusahaan.

  2. 2

    Upload QRIS Anda

    Unggah gambar QRIS merchant dari bank atau e-wallet Anda. Sistem membaca data QRIS secara otomatis.

  3. 3

    Pasang aplikasi pendamping

    Pasang aplikasi APIQris di HP Android yang menerima notifikasi dana masuk, lalu pindai kode pairing.

  4. 4

    Pakai API key

    Salin API key, buat tagihan QRIS dinamis dari website atau chatbot, dan terima webhook saat lunas.

Contoh skenario

Sebelum dan sesudah memakai API QRIS kasir POS

UMKM kuliner yang menerima pesanan lewat website dan WhatsApp. Ilustrasi alur kerja, bukan testimoni pelanggan.

Sebelum

Pembeli mengirim foto bukti bayar, admin mengecek mutasi, lalu mengubah status pesanan secara manual.

Sesudah

Lewat API QRIS kasir POS, QRIS bernominal dikirim otomatis. Status berubah lunas sendiri dan dapur langsung menerima pesanan.

Perbandingan

QRIS statis manual vs API QRIS kasir POS vs payment gateway

AspekQRIS statis manualAPI QRIS kasir POS (APIQris)Payment gateway
NominalDiketik pembeliTerkunci otomatisTerkunci otomatis
Konfirmasi bayarCek mutasi manualWebhook otomatisWebhook otomatis
Penerima danaRekening AndaRekening AndaRekening gateway
Potongan perantaraRp0Rp0±0,7% + biaya tarik
Bekerja 24 jamTergantung adminYaYa
Contoh kode

Buat tagihan dengan API QRIS kasir POS

Kirim nominal dan order ID, terima QR dan total yang sudah ditambah kode unik.

Buat tagihan QRIS
curl -X POST https://api.apiqris.com/v1/invoices \
  -H "Authorization: Bearer AQ_LIVE_xxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"amount":50000,"order_id":"INV-1024"}'
<?php
$ch = curl_init('https://api.apiqris.com/v1/invoices');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('APIQRIS_KEY'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'amount'   => 50000,
        'order_id' => 'INV-1024',
    ]),
]);
$qris = json_decode(curl_exec($ch), true);
echo $qris['qr_image_url']; // tampilkan ke pembeli
use Illuminate\Support\Facades\Http;

$qris = Http::withToken(config('services.apiqris.key'))
    ->post('https://api.apiqris.com/v1/invoices', [
        'amount'   => $order->total,
        'order_id' => $order->number,
    ])
    ->throw()
    ->json();

return view('checkout.qris', ['qris' => $qris]);
const res = await fetch('https://api.apiqris.com/v1/invoices', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.APIQRIS_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ amount: 50000, order_id: 'INV-1024' }),
});
const qris = await res.json();
console.log(qris.total_amount, qris.qr_image_url);
import os, requests

r = requests.post(
    "https://api.apiqris.com/v1/invoices",
    headers={"Authorization": f"Bearer {os.environ['APIQRIS_KEY']}"},
    json={"amount": 50000, "order_id": "INV-1024"},
    timeout=15,
)
r.raise_for_status()
qris = r.json()
print(qris["total_amount"], qris["qr_image_url"])
body := strings.NewReader(`{"amount":50000,"order_id":"INV-1024"}`)
req, _ := http.NewRequest("POST", "https://api.apiqris.com/v1/invoices", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("APIQRIS_KEY"))
req.Header.Set("Content-Type", "application/json")

res, err := http.DefaultClient.Do(req)
if err != nil {
    log.Fatal(err)
}
defer res.Body.Close()
Webhook

Verifikasi kabar lunas

Hitung HMAC SHA-256 dari timestamp dan body mentah, bandingkan secara constant-time.

Verifikasi webhook
# Header yang dikirim APIQris ke callback_url Anda
X-APIQris-Signature: t=1760670000,v1=5f2b...e9
Content-Type: application/json

{"event":"invoice.paid","id":"qr_9KX2T7","order_id":"INV-1024","total_amount":50123,"status":"paid"}
<?php
$body = file_get_contents('php://input');
parse_str(str_replace(',', '&', $_SERVER['HTTP_X_APIQRIS_SIGNATURE'] ?? ''), $sig);
$expected = hash_hmac('sha256', $sig['t'] . '.' . $body, getenv('APIQRIS_SECRET'));

if (!hash_equals($expected, $sig['v1'] ?? '') || abs(time() - (int) $sig['t']) > 300) {
    http_response_code(401);
    exit;
}
$event = json_decode($body, true);
if ($event['event'] === 'invoice.paid') {
    tandai_lunas($event['order_id']); // fungsi milik aplikasi Anda
}
http_response_code(200);
Route::post('/webhook/qris', function (Request $request) {
    parse_str(str_replace(',', '&', $request->header('X-APIQris-Signature')), $sig);
    $expected = hash_hmac('sha256', $sig['t'].'.'.$request->getContent(), config('services.apiqris.secret'));
    abort_unless(hash_equals($expected, $sig['v1'] ?? ''), 401);

    if ($request->input('event') === 'invoice.paid') {
        Order::where('number', $request->input('order_id'))->update(['status' => 'paid']);
    }
    return response()->noContent();
});
import crypto from 'node:crypto';
import express from 'express';

const app = express();
app.post('/webhook/qris', express.raw({ type: 'application/json' }), (req, res) => {
  const sig = Object.fromEntries(req.get('X-APIQris-Signature').split(',').map((p) => p.split('=')));
  const expected = crypto.createHmac('sha256', process.env.APIQRIS_SECRET)
    .update(`${sig.t}.${req.body}`).digest('hex');
  if (!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(sig.v1 ?? ''))) return res.sendStatus(401);

  const event = JSON.parse(req.body);
  if (event.event === 'invoice.paid') markPaid(event.order_id);
  res.sendStatus(200);
});
import hmac, hashlib, os
from flask import Flask, request, abort

app = Flask(__name__)

@app.post("/webhook/qris")
def webhook():
    sig = dict(p.split("=", 1) for p in request.headers["X-APIQris-Signature"].split(","))
    msg = f"{sig['t']}.".encode() + request.get_data()
    expected = hmac.new(os.environ["APIQRIS_SECRET"].encode(), msg, hashlib.sha256).hexdigest()
    if not hmac.compare_digest(expected, sig.get("v1", "")):
        abort(401)
    event = request.get_json()
    if event["event"] == "invoice.paid":
        mark_paid(event["order_id"])
    return "", 200
func webhook(w http.ResponseWriter, r *http.Request) {
    body, _ := io.ReadAll(r.Body)
    sig := map[string]string{}
    for _, p := range strings.Split(r.Header.Get("X-APIQris-Signature"), ",") {
        if k, v, ok := strings.Cut(p, "="); ok {
            sig[k] = v
        }
    }
    mac := hmac.New(sha256.New, []byte(os.Getenv("APIQRIS_SECRET")))
    mac.Write([]byte(sig["t"] + "." + string(body)))
    if !hmac.Equal([]byte(hex.EncodeToString(mac.Sum(nil))), []byte(sig["v1"])) {
        http.Error(w, "invalid signature", http.StatusUnauthorized)
        return
    }
    w.WriteHeader(http.StatusOK)
}
Keamanan

Aman sejak baris kode pertama

HTTPS di semua endpoint

Data tagihan dan API key selalu terenkripsi saat dikirim.

API key bisa dirotasi

Kunci bocor? Buat kunci baru dari dashboard, kunci lama langsung mati.

Webhook HMAC SHA-256

Setiap callback ditandatangani agar server Anda bisa menolak yang palsu.

Dana tidak lewat kami

Tidak ada saldo yang bisa dibekukan, karena uang langsung ke QRIS Anda.

Sebelum go-live

Checklist API QRIS kasir POS

  • QRIS merchant resmi sudah diupload dan terbaca benar
  • Aplikasi pendamping di HP Android berstatus online
  • Optimasi baterai dimatikan untuk aplikasi merchant & pendamping
  • Uji bayar Rp1.000 berhasil terdeteksi lunas
  • URL webhook memakai HTTPS dan membalas 200
  • Tanda tangan HMAC diverifikasi sebelum memproses pesanan
  • Proses webhook idempoten berdasarkan order_id
  • API key disimpan di server, tidak di frontend
Istilah

Glosarium singkat

QRIS
Quick Response Code Indonesian Standard, standar QR pembayaran nasional dari Bank Indonesia.
QRIS dinamis
QRIS yang membawa nominal untuk satu transaksi, berbeda dengan QRIS statis tanpa nominal.
NMID
National Merchant ID, nomor identitas merchant yang tertanam di QRIS Anda.
MDR
Merchant Discount Rate, biaya yang dipotong penyedia QRIS atas transaksi sesuai ketentuan.
Kode unik
Angka kecil yang ditambahkan ke nominal agar setiap tagihan bisa dibedakan.
Webhook
HTTP POST otomatis dari APIQris ke server Anda saat status tagihan berubah.
FAQ

Pertanyaan umum tentang API QRIS kasir POS

Apakah POS harus online?

Ya, pembuatan tagihan dan penerimaan status lunas membutuhkan koneksi internet.

Bisakah polling saja tanpa webhook?

Bisa. Panggil endpoint status tagihan setiap 2 sampai 3 detik selama QR tampil.

Apakah dana dari API QRIS kasir POS ditampung APIQris?

Tidak. Pembeli membayar ke QRIS milik Anda sendiri, sehingga dana langsung masuk ke rekening atau saldo merchant Anda.

Berapa biaya memakai APIQris?

Daftar gratis dan APIQris tidak memotong fee per transaksi. MDR dari penyedia QRIS Anda (bila ada) mengikuti ketentuan penyedia.

Apakah perlu HP khusus?

Cukup satu HP Android yang terpasang aplikasi merchant penerbit QRIS Anda dan aplikasi pendamping APIQris. HP lama pun bisa selama notifikasinya stabil.

Mulai API QRIS kasir POS hari ini

Gratis, tanpa potongan per transaksi, dana langsung ke rekening Anda. Pelajari dulu API QRIS selengkapnya atau langsung daftar.