| Method | Endpoint | Fungsi |
|---|---|---|
| POST | /api/v1/payments/create | Buat payment |
| GET | /api/v1/payments/:orderId | Detail payment |
| GET | /api/v1/payments/:orderId/status | Cek status payment |
| GET | /api/v1/payments | Daftar payment |
agentCode + merchantCode dari halaman Toko Saya.
Buat payment
POST /api/v1/payments/createorderId, QR Code dinamis, dan status: "pending".
Body
| Parameter | Tipe | Wajib | Deskripsi |
|---|---|---|---|
| agentCode | string | Ya | Agent code toko aktif |
| merchantCode | string | Ya | Merchant code toko aktif |
| amount | number | Ya | Nominal pembayaran dalam Rupiah |
| externalId | string | Tidak | ID order dari sistem Anda |
| channel | string | Tidak | qris, va, atau ewallet (default: qris) |
| dstCode | string | Tidak | QRIS, BCA, DANA, dll. Default sesuai channel. Lihat Daftar Pembayaran |
| fee | object | Tidak | Fee transaksi. Berisi type (fixed atau percentage) dan value (number) |
| feeBearer | string | Tidak | Siapa yang membayar fee: merchant (default) atau customer |
| customerName | string | Tidak | Nama customer |
| customerPhone | string | Tidak | Nomor HP customer |
| customerEmail | string | Tidak | Email customer |
feeBearer
merchant(default): saldo toko dipotong sesuai fee. Customer bayar tanpa tambahan.customer: fee ditambahkan ke total bayaran customer. Saldo toko utuh.
Channel
- QRIS
- Virtual Account
- E-Wallet
| channel | dstCode | Max amount |
|---|---|---|
| qris (default) | QRIS | Rp 10.000.000 |
| channel | dstCode | Max amount |
|---|---|---|
| va | BCA, BNI, BRI, MANDIRI, PERMATA, dll. | Rp 50.000.000 (BCA: Rp 2.000.000) |
| channel | dstCode | Max amount |
|---|---|---|
| ewallet | DANA, OVO, SHOPEEPAY, LINKAJA | Rp 20.000.000 |
Contoh request
curl -X POST http://localhost:5173/api/v1/payments/create \
-H "Content-Type: application/json" \
-d '{
"agentCode": "AGT-187F2398D5A6",
"merchantCode": "MERCHANT-AGT-187F2398D5A6",
"amount": 50000,
"externalId": "INV-001",
"customerName": "John Doe",
"customerPhone": "08123456789",
"customerEmail": "john@example.com",
"channel": "qris",
"dstCode": "QRIS",
"fee": { "type": "fixed", "value": 1000 },
"feeBearer": "merchant"
}'
const response = await fetch("http://localhost:5173/api/v1/payments/create", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
agentCode: "AGT-187F2398D5A6",
merchantCode: "MERCHANT-AGT-187F2398D5A6",
amount: 50000,
externalId: "INV-001",
customerName: "John Doe",
customerPhone: "08123456789",
customerEmail: "john@example.com",
channel: "qris",
dstCode: "QRIS",
fee: { type: "fixed", value: 1000 },
feeBearer: "merchant",
}),
});
const { data } = await response.json();
console.log(data.providerOrderId, data.qrCode);
<?php
$payload = [
"agentCode" => "AGT-187F2398D5A6",
"merchantCode" => "MERCHANT-AGT-187F2398D5A6",
"amount" => 50000,
"externalId" => "INV-001",
"customerName" => "John Doe",
"customerPhone" => "08123456789",
"customerEmail" => "john@example.com",
"channel" => "qris",
"dstCode" => "QRIS",
"fee" => ["type" => "fixed", "value" => 1000],
"feeBearer" => "merchant",
];
$ch = curl_init("http://localhost:5173/api/v1/payments/create");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ["Content-Type: application/json"],
CURLOPT_POSTFIELDS => json_encode($payload),
CURLOPT_RETURNTRANSFER => true,
]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true)["data"];
echo $data["orderId"] . " " . $data["qrCode"];
import axios from "axios";
const { data: res } = await axios.post(
"http://localhost:5173/api/v1/payments/create",
{
agentCode: "AGT-187F2398D5A6",
merchantCode: "MERCHANT-AGT-187F2398D5A6",
amount: 50000,
externalId: "INV-001",
customerName: "John Doe",
customerPhone: "08123456789",
customerEmail: "john@example.com",
channel: "qris",
dstCode: "QRIS",
fee: { type: "fixed", value: 1000 },
feeBearer: "merchant",
}
);
console.log(res.data.orderId, res.data.qrCode);
import requests
payload = {
"agentCode": "AGT-187F2398D5A6",
"merchantCode": "MERCHANT-AGT-187F2398D5A6",
"amount": 50000,
"externalId": "INV-001",
"customerName": "John Doe",
"customerPhone": "08123456789",
"customerEmail": "john@example.com",
"channel": "qris",
"dstCode": "QRIS",
"fee": {"type": "fixed", "value": 1000},
"feeBearer": "merchant",
}
res = requests.post("http://localhost:5173/api/v1/payments/create", json=payload)
data = res.json()["data"]
print(data["orderId"], data["qrCode"])
package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
)
func main() {
payload := map[string]any{
"agentCode": "AGT-187F2398D5A6",
"merchantCode": "MERCHANT-AGT-187F2398D5A6",
"amount": 50000,
"externalId": "INV-001",
"customerName": "John Doe",
"customerPhone": "08123456789",
"customerEmail": "john@example.com",
"channel": "qris",
"dstCode": "QRIS",
"fee": map[string]any{"type": "fixed", "value": 1000},
"feeBearer": "merchant",
}
body, _ := json.Marshal(payload)
resp, err := http.Post(
"http://localhost:5173/api/v1/payments/create",
"application/json",
bytes.NewReader(body),
)
if err != nil {
panic(err)
}
defer resp.Body.Close()
var result map[string]any
json.NewDecoder(resp.Body).Decode(&result)
data := result["data"].(map[string]any)
fmt.Println(data["orderId"], data["qrCode"])
}
// Cargo.toml: reqwest = { version = "0.12", features = ["json"] }, serde_json = "1", tokio = { version = "1", features = ["full"] }
use serde_json::{json, Value};
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let payload = json!({
"agentCode": "AGT-187F2398D5A6",
"merchantCode": "MERCHANT-AGT-187F2398D5A6",
"amount": 50000,
"externalId": "INV-001",
"customerName": "John Doe",
"customerPhone": "08123456789",
"customerEmail": "john@example.com",
"channel": "qris",
"dstCode": "QRIS",
"fee": { "type": "fixed", "value": 1000 },
"feeBearer": "merchant"
});
let res: Value = reqwest::Client::new()
.post("http://localhost:5173/api/v1/payments/create")
.json(&payload)
.send()
.await?
.json()
.await?;
println!("{} {}", res["data"]["orderId"], res["data"]["qrCode"]);
Ok(())
}
Contoh response
200
{
"success": true,
"data": {
"orderId": "P_20260817wN9dsiK545H9uxgk2mXj",
"externalId": "INV-001",
"storeId": "(id internal toko)",
"storeName": "Toko Saya",
"merchantName": "Wati Toto",
"merchantCode": "MERCHANT-AGT-187F2398D5A6",
"amount": 50000,
"fee": { "type": "fixed", "value": 1000 },
"totalAmount": 51000,
"qrisDynamic": "00020101021226...(294 karakter QR dinamis)",
"qrCode": "00020101021226...",
"status": "pending",
"customerName": "John Doe",
"customerEmail": "john@example.com",
"paidAt": null,
"expiredAt": "2026-08-17T14:30:00.000Z",
"createdAt": "2026-08-17T14:15:00.000Z",
"updatedAt": "2026-08-17T14:15:00.000Z",
"providerId": "(id internal DB provider)",
"providerCode": "qris",
"provider": "qris",
"providerOrderId": "P_20260817wN9dsiK545H9uxgk2mXj",
"channel": "qris",
"paymentMethod": "QRIS",
"providerFee": 1500,
"vaNumber": null
}
}
Belum atur webhook? Buka Toko Saya → Webhook Callback. Order Anda tetap diproses meskipun webhook belum diatur. Lihat Webhook Callback.
Detail payment
GET /api/v1/payments/:orderId| Parameter | Lokasi | Tipe | Wajib | Deskripsi |
|---|---|---|---|---|
| orderId | path | string | Ya | orderId dari response create payment |
| agentCode | query | string | Ya | Agent code toko aktif |
| merchantCode | query | string | Ya | Merchant code toko aktif |
Cek status payment
GET /api/v1/payments/:orderId/status| Parameter | Lokasi | Tipe | Wajib | Deskripsi |
|---|---|---|---|---|
| orderId | path | string | Ya | orderId dari response create payment |
| agentCode | query | string | Ya | Agent code toko aktif |
| merchantCode | query | string | Ya | Merchant code toko aktif |
Daftar payment
GET /api/v1/payments| Parameter | Lokasi | Tipe | Wajib | Deskripsi |
|---|---|---|---|---|
| agentCode | query | string | Ya | Agent code toko aktif |
| merchantCode | query | string | Ya | Merchant code toko aktif |
| status | query | string | Tidak | Filter berdasarkan status payment |

