Preloader

QRIS Payment Integration

Modern QR-based payment solution for Indonesia

What is QRIS?

QRIS (Quick Response Code Indonesian Standard) is a unified QR code standard in Indonesia that enables customers to make payments by scanning a QR code with their mobile banking apps. It's a modern, fast, and secure payment method supported by all major Indonesian banks.

Overview

The QRIS API allows you to:

  • Generate dynamic QR codes for instant payment requests
  • Accept payments from all banks supported by the QRIS standard
  • Track payment status in real-time with instant updates
  • Receive notifications automatically when payments arrive
  • Secure transactions with RSA 2048-bit encryption

Key Features

Lightning Fast

Customers scan and pay instantly from their mobile banking app

Universal Standard

Works with BRI, BNI, MANDIRI, BCA, PERMATA, CIMB, and all major banks

Real-time Updates

Get instant notifications when customers complete their payments

Secure & Verified

RSA 2048-bit encryption and signature verification for all transactions

Payment Flow

Here's how the QRIS payment process works:

Your App CICIS API Winpay Customer │ │ │ │ ├─POST /checkout────→│ │ │ │ ├─Create Payment──────→│ │ │ │←─QR Generated────────┤ │ │←─{qr_url, ...}────┤ │ │ │ │ │ │ ├─Display QR──────────────────────────────────────────────→│ │ │ │ │ │ │ │ │ │ ├─Scan │ │ │ │ │ QR │ │ │ │ ├─Pay──→│ │ │ │←─Payment──┤ │ │ │←─Update Status───────┤ │ │ │ │ │ │ │ ├──GET /status──────→│ │ │ │ │←─{status:SETTLED}─┤ │ │ │ │ │ │ │ │ ├─Activate Service │ │ │ └─Send Email │ │ │ │

Getting Started

Step 1: Authenticate Your Request

Include your API credentials in every request header:

-H "X-API-Client: your_client_key"
-H "X-API-Secret: your_secret_key"
-H "Content-Type: application/json"
$headers = [
    'X-API-Client' => 'your_client_key',
    'X-API-Secret' => 'your_secret_key',
    'Content-Type' => 'application/json'
];
const headers = {
    'X-API-Client': 'your_client_key',
    'X-API-Secret': 'your_secret_key',
    'Content-Type': 'application/json'
};

Step 2: Create QRIS Payment

Send a POST request to create a new QRIS payment:

curl -X POST https://cicis.online/api/qris/checkout \
  -H "Content-Type: application/json" \
  -H "X-API-Client: your_client_key" \
  -H "X-API-Secret: your_secret_key" \
  -d '{
    "customer_name": "Budi Santoso",
    "customer_email": "budi@example.com",
    "customer_phone": "081234567890",
    "amount": 150000,
    "currency": "IDR",
    "payment_method": "qris",
    "description": "Pembayaran VPN Premium"
  }'

# Response includes:
# {
#   "invoice_id": "GM-1705763403",
#   "qr_url": "https://cicis.online/qr/generate/GM-1705763403"
# }
use Illuminate\Support\Facades\Http;

$response = Http::withHeaders([
    'X-API-Client' => 'your_client_key',
    'X-API-Secret' => 'your_secret_key'
])->post('https://cicis.online/api/qris/checkout', [
    'customer_name' => 'Budi Santoso',
    'customer_email' => 'budi@example.com',
    'amount' => 150000,
    'payment_method' => 'qris'
]);

$data = $response->json();
$invoiceId = $data['invoice_id'];
$qrUrl = "https://cicis.online/qr/generate/{$invoiceId}";
const response = await fetch('https://cicis.online/api/qris/checkout', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-API-Client': 'your_client_key',
    'X-API-Secret': 'your_secret_key'
  },
  body: JSON.stringify({
    customer_name: 'Budi Santoso',
    customer_email: 'budi@example.com',
    amount: 150000,
    payment_method: 'qris'
  })
});

const data = await response.json();
const invoiceId = data.invoice_id;
const qrUrl = `https://cicis.online/qr/generate/${invoiceId}`;

Step 3: Display QR Code

Show the QR code image to your customer. The image is now served from cicis domain:

<img src="https://cicis.online/qr/generate/GM-1705763403" 
     alt="Scan to Pay" 
     style="width: 300px; height: 300px;" />

QR Code URL Format

Endpoint: GET https://cicis.online/qr/generate/{invoice_id}

Parameter: invoice_id - The invoice ID returned from the checkout response

Returns: PNG image (300x300px) - Can be cached and reused

Step 4: Check Payment Status

Poll the API or use webhooks to check if payment was completed:

curl https://cicis.online/api/qris/status/GM-1705763403 \
  -H "X-API-Client: your_client_key" \
  -H "X-API-Secret: your_secret_key"
$response = Http::withHeaders([
    'X-API-Client' => 'your_client_key',
    'X-API-Secret' => 'your_secret_key'
])->get('https://cicis.online/api/qris/status/GM-1705763403');

if ($response->json()['status'] === 'SETTLED') {
    // Payment received - activate service
}
const response = await fetch('https://cicis.online/api/qris/status/GM-1705763403', {
  headers: {
    'X-API-Client': 'your_client_key',
    'X-API-Secret': 'your_secret_key'
  }
});

const data = await response.json();
if (data.status === 'SETTLED') {
    // Payment received - activate service
}

Payment Status Reference

Status Description What to do
PENDING Payment just created, waiting for customer action Display QR code to customer
CREATED QR generated, waiting for payment Awaiting customer scan and payment
PROCESSING Payment is being processed by bank Wait for settlement confirmation
✓ SETTLED Payment received successfully ✅ Activate service immediately
✓ SUCCESS Payment confirmed ✅ Activate service immediately
FAILED Payment failed or rejected Offer customer to retry payment
EXPIRED Payment expired after 24 hours Create new payment request
CANCELLED Payment cancelled by customer Ask customer to retry

Request Parameters

Parameter Type Required Description
customer_name string REQUIRED Full name of customer (max 255 characters)
customer_email string REQUIRED Valid email address for notifications
customer_phone string OPTIONAL Phone number (max 20 characters)
amount decimal REQUIRED Amount in IDR (minimum: 1,000 | maximum: 100,000,000)
currency string OPTIONAL Currency code (default: IDR)
payment_method string REQUIRED Must be exactly 'qris'
description string OPTIONAL Order description or note (max 500 characters)
metadata object OPTIONAL Custom data to pass through the payment (JSON object)

Response Format

Successful QRIS payment creation response:

{
  "success": true,
  "invoice_id": "GM-1705763403",
  "order_id": 12345,
  "customer_name": "Budi Santoso",
  "customer_email": "budi@example.com",
  "amount": 150000,
  "currency": "IDR",
  "payment_method": "qris",
  "qr_url": "https://cicis.online/qr/generate/GM-1705763403",
  "qr_content": "00020126360014ID.CO.BRI.BRIMO...",
  "status": "CREATED",
  "created_at": "2026-01-20T10:30:45Z",
  "expires_at": "2026-01-21T10:30:45Z"
}

Best Practices

Security & Implementation

  • Always validate: Check API responses before proceeding with service activation
  • Use HTTPS only: All API calls must use HTTPS, never HTTP
  • Handle timeouts: Implement proper error handling and retry logic
  • Secure credentials: Store API keys in environment variables, never in code
  • Test first: Test thoroughly with sandbox API before going live
  • Log everything: Keep detailed logs of all transactions for auditing
  • Verify webhooks: Always verify webhook signatures to ensure authenticity
  • Use webhooks: Webhooks are faster and more reliable than polling

Pro Tip

Webhooks are the recommended approach for production systems. They provide instant notifications when payments are received, without the overhead of continuous polling. This results in better performance and lower latency.