Payment ยท QRIS ยท PPOB ยท H2H โ€” API Zy-Pay
Diagnostic Tool

โšก Tes Koneksi & Cek IP Terblokir Server

Gunakan alat ini untuk mengecek apakah IP perangkat/server Anda dapat menjangkau server Cutiezy atau terblokir firewall. Masukkan IP yang ingin dicek di bawah.

*Jika dikosongkan, sistem otomatis menguji IP yang saat ini digunakan untuk menembak API (koneksi browser/perangkat Anda).
Status Blokir Server
Menunggu Pengujian...
IP Penembak (Caller)
-
IP penembak request API
IP yang Dicek (Target)
-
Target verifikasi
Latency / HTTP Code
-
PENTING UNTUK INTEGRASI BOT / VPS / WEBSITE:

Tes interaktif di atas mengecek koneksi dari browser Anda. Jika bot atau website Anda dihosting di VPS / cPanel Hosting / Cloud Server, alamat IP yang mengakses Cutiezy adalah IP publik server VPS Anda (bukan IP browser Anda). Jika script bot/toko Anda gagal terhubung (timeout / 403), kemungkinan IP VPS Anda yang terblokir firewall server. Lakukan pengujian langsung dari server VPS Anda menggunakan panduan di bawah.

๐Ÿ“ก Cara Tes Koneksi dari Terminal VPS / Hosting

Jalankan perintah cURL berikut di terminal SSH VPS atau server Anda untuk memastikan IP server Anda tidak terblokir:

curl -i -s "https://cutiezy.id/zy-pay/api/ping.php"

๐Ÿ’ป Skrip Tes PHP cURL (Upload ke Hosting / VPS Anda)

<?php
// Simpan sebagai test-koneksi.php di hosting/VPS Anda lalu akses via browser
$ch = curl_init("https://cutiezy.id/zy-pay/api/ping.php");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT        => 15,
    CURLOPT_SSL_VERIFYPEER => true
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$curlErr  = curl_error($ch);
curl_close($ch);

if ($curlErr) {
    echo "<h2 style='color:red'>โŒ KONEKSI GAGAL / TIMEOUT</h2>";
    echo "<p>Error cURL: " . htmlspecialchars($curlErr) . "</p>";
    echo "<p>Segera hubungi Admin WhatsApp Cutiezy untuk unblock IP server Anda.</p>";
} elseif ($httpCode === 403 || $httpCode >= 400) {
    echo "<h2 style='color:red'>โŒ KONEKSI DITOLAK / TERBLOKIR FIREWALL SERVER (HTTP $httpCode)</h2>";
    echo "<p>IP server Anda terblokir oleh firewall server Cutiezy. Segera salin respon berikut dan kirim ke Admin WhatsApp:</p>";
    echo "<pre>" . htmlspecialchars($response) . "</pre>";
} else {
    echo "<h2 style='color:green'>โœ… KONEKSI BERHASIL (HTTP $httpCode)</h2>";
    echo "<pre>" . htmlspecialchars($response) . "</pre>";
}
?>

๐Ÿ Skrip Tes Python

import requests

try:
    res = requests.get("https://cutiezy.id/zy-pay/api/ping.php", timeout=15)
    print(f"Status HTTP: {res.status_code}")
    print(res.json())
except requests.exceptions.RequestException as e:
    print(f"โŒ KONEKSI GAGAL / IP TERBLOKIR: {e}")
    print("Hubungi Admin WhatsApp Cutiezy untuk unblock IP server Anda.")

โšก Skrip Tes JavaScript / Node.js (Panel Pterodactyl, Bot WA, Discord, VPS)

// Skrip tes koneksi Node.js (Untuk Bot Panel Pterodactyl, Baileys, Discord, VPS)
// Pilihan A: Menggunakan Fetch (Node.js 18+ bawaan tanpa library luar)
async function testZyPayPing() {
    try {
        const res = await fetch("https://cutiezy.id/zy-pay/api/ping.php", {
            headers: { "Accept": "application/json" },
            signal: AbortSignal.timeout(15000)
        });
        const data = await res.json();
        console.log("โœ… KONEKSI BERHASIL (HTTP " + res.status + "):", data);
        console.log("๐Ÿ‘‰ IP Penembak Bot / Node Pterodactyl Anda:", data.ip_penembak || data.client_ip);
        console.log("๐Ÿ‘‰ Status Proteksi Server:", data.status_ip);
    } catch (err) {
        console.error("โŒ KONEKSI GAGAL / IP BOT DIBLOKIR FIREWALL:", err.message);
        console.error("๐Ÿ‘‰ Jika pakai Panel Pterodactyl, IP yang diblokir adalah IP Node server Pterodactyl Anda.");
        console.error("๐Ÿ‘‰ Segera kirimkan IP ke Admin WhatsApp Cutiezy untuk di-unblock.");
    }
}
testZyPayPing();

/* Pilihan B: Menggunakan Axios (npm i axios)
const axios = require('axios');
axios.get("https://cutiezy.id/zy-pay/api/ping.php", { timeout: 15000 })
    .then(res => console.log("โœ… KONEKSI SUKSES:", res.data))
    .catch(err => console.error("โŒ KONEKSI GAGAL / IP TERBLOKIR:", err.message));
*/

๐Ÿšจ Ciri-Ciri IP Terblokir Firewall Server & Solusinya

Gejala / Pesan Error Penyebab Solusi
cURL error 28: Operation timed out IP diblokir firewall (CSF/iptables) Hubungi Admin untuk unblock IP
cURL error 7: Failed to connect Koneksi ditolak oleh firewall / port tertutup Hubungi Admin untuk unblock IP
ETIMEDOUT / ECONNREFUSED / AxiosError IP Node server Pterodactyl / VPS diblokir firewall Hubungi Admin WA untuk unblock IP Node bot
HTTP 403 Forbidden / Access Denied ModSecurity / WAF / Proteksi bot mendeteksi anomali Kirim IP ke Admin untuk dibuatkan whitelist
IP Anda Terblokir? Kami Siap Bantu 24/7!

Salin IP Anda (cek via command curl -s ifconfig.me di VPS) dan hubungi Admin Cutiezy untuk pembukaan blokir seketika.

๐Ÿ’ฌ Chat Admin WhatsApp Unblock
Butuh Integrasi Siap Pakai Tanpa Koding Ulang?

Tersedia panduan resmi & script siap copy-paste untuk platform populer:

Panduan WordPress & WooCommerce → Panduan Apps Script & Sheets →

๐Ÿš€ Quick Start

Get started with Cutiezy API in minutes!

# Base URL
https://cutiezy.id/zy-pay/api/v1/

# Authentication Header
X-API-Key: ak_7d8f9e1a2b3c4d5e6f7a8b9c0d1e2f3

# First API Call (Create Payment)
curl -X POST "https://cutiezy.id/zy-pay/api/v1/create-payment" \
  -H "X-API-Key: your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"amount": 10000, "description": "Test payment"}'
๐Ÿ“Œ Note: Get your API key from Dashboard โ†’ API Keys

๐Ÿ” Authentication

All API requests require authentication via API Key.

X-API-Key: ak_7d8f9e1a2b3c4d5e6f7a8b9c0d1e2f3

Getting Your API Key:

  1. Login to Dashboard
  2. Navigate to Settings โ†’ API Keys
  3. Click "Generate New API Key"
  4. โš ๏ธ IMPORTANT: Save your API Secret immediately! (shown only once)
โš ๏ธ Security Note:
  • Never expose your API key in client-side code
  • Use environment variables in production
  • Rotate keys regularly

โฑ๏ธ Rate Limits

API rate limits to ensure service stability.

Endpoint Limit Window Description
POST /create-payment 1 request 3 seconds Prevent duplicate payments
GET /check-payment 10 requests 1 second Status checking
GET /mutations 5 requests 10 seconds History retrieval
GET /balance 10 requests 1 second Check Cutiezy balance
All endpoints 100 requests 1 minute Global rate limit

๐Ÿ’ณ 1. Create Payment

Create a new QRIS payment request.

POST /create-payment
โšก Real Implementation: This endpoint uses advisory locks and retry mechanisms to handle concurrent requests safely.

Request Body:

{
  "amount": 10000,
  "description": "Payment for order #123",
  "webhook_url": "https://your-webhook.com/callback",
  "public_theme": "theme2"
}

Parameters:

Parameter Type Required Description Constraints
amount Required integer โœ… Payment amount in IDR 1,000 - 10,000,000
description Optional string โŒ Payment description Max 255 characters
webhook_url Optional string โŒ Webhook URL for notifications Valid HTTPS URL
public_theme Optional string โŒ Theme for the public payment page theme1, theme2, or theme3 (default: theme1)

Response (Success - 201 Created):

{
  "success": true,
  "message": "Payment created successfully",
  "data": {
    "transaction_id": "QRIS20241230123045ABCDEF",
    "reference_id": 12345,
    "amount": 10000,
    "fee": 50,
    "total_amount": 10075,
    "payment_method": "QRIS",
    "qris_image_url": "https://cutiezy.id/zy-pay/dashboard/qris/temp/qris_example.jpg",
    "qris_image_base64": "data:image/jpeg;base64,...",
    "qris_string": "00020101021126670014...",
    "expired_at": "2024-12-30 12:45:45",
    "status": "pending",
    "public_payment_url": "https://cutiezy.id/zy-pay/pay.php?id=HASHED_123",
    "public_theme": "theme2",
    "check_status_url": "https://cutiezy.id/zy-pay/api/v1/check-payment/QRIS20241230123045ABCDEF",
    "webhook_url": "https://your-webhook.com/callback",
    "created_at": "2024-12-30 12:30:45"
  }
}

Fee Calculation:

// Fee = 0.5% of amount (rounded down)
fee = Math.floor(amount * 0.5 / 100);

// Total = Amount + Fee
total_amount = amount + fee;

๐Ÿ” 2. Check Payment Status

Check payment status by transaction ID. Supports both URL path and query parameter.

GET /check-payment/{transaction_id}

OR: GET /check-payment?transaction_id={transaction_id}

OR: GET /check-payment?id={reference_id}

Response (Success - 200 OK):

{
  "success": true,
  "data": {
    "transaction_id": "QRIS20241230123045ABCDEF",
    "reference_id": 12345,
    "amount": 10000,
    "fee": 50,
    "total_amount": 10075,
    "status": "paid",
    "payment_method": "QRIS",
    "qris_image_url": "https://cutiezy.id/qris/QRIS20241230123045ABCDEF.png",
    "expired_at": "2024-12-30 12:45:45",
    "paid_at": "2024-12-30 12:33:20",
    "settlement_at": "2024-12-30 20:33:20",
    "description": "Payment for order #123",
    "created_at": "2024-12-30 12:30:45",
    "updated_at": "2024-12-30 12:33:20"
  }
}

Status Values:

pending - Waiting for payment - Payment received expired - Payment expired (30 minutes) cancel - Payment cancelled

โŒ 3. Cancel Payment

Cancel a pending payment before it expires or gets paid.

POST /cancel-payment

Request Body:

{
  "transaction_id": "QRIS20241230123045ABCDEF"
}

OR:

{
  "id": 12345
}

Response (Success - 200 OK):

{
  "success": true,
  "message": "Payment cancelled successfully",
  "data": {
    "transaction_id": "QRIS20241230123045ABCDEF",
    "reference_id": 12345,
    "status": "cancelled",
    "cancelled_at": "2024-12-30 12:35:10"
  }
}
โš ๏ธ Restrictions:
  • Only pending payments can be cancelled
  • Cannot cancel paid or expired payments
  • Cancellation is permanent and irreversible

๐Ÿ“Š 4. Transaction History (Mutations)

Get transaction history with filtering, pagination, and date range.

GET /mutations

Parameters:

Parameter Type Default Description
start_date string Current month 1st Format: YYYY-MM-DD
end_date string Today Format: YYYY-MM-DD
status string (all) Filter by status
page integer 1 Page number (โ‰ฅ1)
limit integer 50 Items per page (max 100)

Example Request:

GET /mutations?start_date=2024-12-01&end_date=2024-12-31&status=paid&page=1&limit=20

Response (Success - 200 OK):

{
  "success": true,
  "data": [
    {
      "transaction_id": "QRIS20241230123045ABCDEF",
      "reference_id": 12345,
      "amount": 10000,
      "fee": 50,
      "total_amount": 10075,
      "status": "paid",
      "payment_method": "QRIS",
      "qris_image_url": "https://cutiezy.id/qris/QRIS20241230123045ABCDEF.png",
      "expired_at": "2024-12-30 12:45:45",
      "paid_at": "2024-12-30 12:33:20",
      "description": "Payment for order #123",
      "created_at": "2024-12-30 12:30:45"
    }
  ],
  "pagination": {
    "total": 45,
    "page": 1,
    "limit": 20,
    "pages": 3
  },
  "filters": {
    "start_date": "2024-12-01",
    "end_date": "2024-12-31",
    "status": "paid"
  }
}

๐Ÿ‘ค 5. User Profile & Statistics

Get user profile information, balance, and transaction statistics.

GET /profile

Response (Success - 200 OK):

{
  "success": true,
  "data": {
    "user": {
      "user_id": 1,
      "username": "johndoe",
      "email": "[email protected]",
      "role": "user"
    },
    "balance": {
      "available": 1500000.00,
      "currency": "IDR"
    },
    "cutiezy": {
      "connected": true,
      "card": "41680512",
      "username": "cutiezy_user",
      "name": "John Doe",
      "level": "Basic",
      "balance": 150000,
      "balance_formatted": "Rp 150.000"
    },
    "stats": {
      "total": {
        "pending": 2,
        "paid": 45,
        "expired": 3,
        "cancelled": 1,
        "total_amount": 4500000
      },
      "today": {
        "transactions": 5,
        "paid_amount": 250000
      }
    },
    "settings": {
      "fee_percentage": 0.5,
      "min_amount": 1000,
      "max_amount": 10000000
    }
  }
}

๐Ÿ’ฐ 6. Cek Saldo Cutiezy (Balance API)

Memeriksa saldo dan status akun Cutiezy yang terhubung dengan akun Zy-Pay Anda (berdasarkan ID Card member).

GET /balance
GET /v1/balance
POST /balance
๐Ÿ’ก Info: Endpoint ini mendukung metode GET dan POST. API Key dapat dikirimkan melalui header X-API-Key, Authorization: Bearer, ataupun query parameter ?api_key=....

Header Autentikasi:

X-API-Key: ak_your_api_key_here

Contoh Request (cURL):

curl -X GET "https://cutiezy.id/zy-pay/api/v1/balance" \
  -H "X-API-Key: ak_your_api_key_here"

Contoh Request (PHP):

<?php
$apiKey = "ak_your_api_key_here";
$ch = curl_init("https://cutiezy.id/zy-pay/api/v1/balance");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        "X-API-Key: " . $apiKey,
        "Accept: application/json"
    ],
    CURLOPT_TIMEOUT => 30
]);
$response = curl_exec($ch);
curl_close($ch);
$result = json_decode($response, true);
echo "Saldo Cutiezy: " . $result['data']['balance_formatted'];
?>

Response Berhasil (200 OK):

{
  "success": true,
  "status": true,
  "message": "OK",
  "data": {
    "user_id": 1,
    "username": "johndoe",
    "cutiezy_connected": true,
    "cutiezy_card": "41680512",
    "cutiezy_username": "cutiezy_user",
    "cutiezy_name": "John Doe",
    "cutiezy_level": "Basic",
    "balance": 150000,
    "balance_formatted": "Rp 150.000",
    "currency": "IDR",
    "settlement_balance": 25000,
    "settlement_balance_formatted": "Rp 25.000"
  },
  "timestamp": "2026-09-15 05:30:00"
}

Response Jika ID Card Belum Terhubung (400 Bad Request):

{
  "success": false,
  "status": false,
  "error": "ID Card Cutiezy belum dihubungkan pada akun ini. Hubungkan ID Card di menu Profile.",
  "data": {
    "cutiezy_connected": false,
    "user_id": 1,
    "username": "johndoe",
    "balance": 0,
    "settlement_balance": 25000
  },
  "timestamp": "2026-09-15 05:30:00"
}

๐Ÿ”„ 7. Webhook Notifications

Real-time notifications for payment events sent to your webhook URL.

Setup:

  1. Dashboard โ†’ Profile โ†’ Webhook Settings
  2. Enter your webhook URL and secret key
  3. Enable webhook notifications
  4. Or use webhook_url parameter in create-payment request

Signature Verification:

// Verify webhook signature
const crypto = require('crypto');

function verifySignature(payload, signature, secret) {
    const expected = crypto
        .createHmac('sha256', secret)
        .update(payload)
        .digest('hex');
    
    return crypto.timingSafeEqual(
        Buffer.from(signature),
        Buffer.from(expected)
    );
}

Webhook Payload:

{
  "event": "payment.paid",
  "data": {
    "transaction_id": "QRIS20241230123045ABCDEF",
    "reference_id": 12345,
    "amount": 10000,
    "fee": 50,
    "total_amount": 10075,
    "status": "paid",
    "payment_method": "QRIS",
    "description": "Payment for order #123",
    "paid_at": "2024-12-30 12:33:20",
    "expired_at": "2024-12-30 12:45:45",
    "settlement_at": "2024-12-30 20:33:20",
    "created_at": "2024-12-30 12:30:45"
  },
  "timestamp": "2024-12-30 12:33:21"
}

Webhook Headers:

Header Description Example
X-Webhook-Signature HMAC SHA256 signature sha256=abc123...
X-Webhook-Event Event type payment.paid
Content-Type Payload format application/json
User-Agent Sender identifier ZyPay-Webhook/1.0

Webhook Events:

Event Description Trigger Condition
payment.pending Payment created When user creates payment via API
payment.paid Payment successful When QRIS is scanned & paid
payment.expired Payment expired 30 minutes after creation (no payment)
payment.cancelled Payment cancelled User cancels via API or dashboard
๐Ÿ’ก Best Practices:
  • Always verify the signature
  • Respond with 200 OK within 5 seconds
  • Implement retry logic on your side
  • Log all webhook events

โšก 8. Code Examples

PHP - Create Payment:

<?php
$apiKey = "ak_7d8f9e1a2b3c4d5e6f7a8b9c0d1e2f3";
$url = "https://cutiezy.id/zy-pay/api/v1/create-payment";

$data = [
    "amount" => 10000,
    "description" => "Order #123",
    "webhook_url" => "https://your-store.com/webhook/payment"
];

$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => json_encode($data),
    CURLOPT_HTTPHEADER => [
        "X-API-Key: $apiKey",
        "Content-Type: application/json",
        "Accept: application/json"
    ]
]);

$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);
curl_close($ch);

if ($httpCode === 201) {
    $result = json_decode($response, true);
    if ($result['success']) {
        echo "QRIS Image: " . $result['data']['qris_image_url'];
        echo "Transaction ID: " . $result['data']['transaction_id'];
    }
} else {
    echo "Error $httpCode: $error";
}
?>

JavaScript/Node.js - Check Payment:

const axios = require('axios');

class CutiezyAPI {
    constructor(apiKey) {
        this.apiKey = apiKey;
        this.baseURL = 'https://cutiezy.id/zy-pay/api/v1';
    }
    
    async createPayment(amount, description, webhookUrl) {
        try {
            const response = await axios.post(
                `${this.baseURL}/create-payment`,
                { amount, description, webhook_url: webhookUrl },
                {
                    headers: {
                        'X-API-Key': this.apiKey,
                        'Content-Type': 'application/json'
                    }
                }
            );
            return response.data;
        } catch (error) {
            throw new Error(`Create payment failed: ${error.response?.data?.error || error.message}`);
        }
    }
    
    async checkPayment(transactionId) {
        try {
            const response = await axios.get(
                `${this.baseURL}/check-payment/${transactionId}`,
                {
                    headers: {
                        'X-API-Key': this.apiKey
                    }
                }
            );
            return response.data.data;
        } catch (error) {
            throw new Error(`Check payment failed: ${error.response?.data?.error || error.message}`);
        }
    }
    
    async getMutations(options = {}) {
        const params = new URLSearchParams({
            start_date: options.startDate || new Date().toISOString().split('T')[0],
            end_date: options.endDate || new Date().toISOString().split('T')[0],
            status: options.status || '',
            page: options.page || 1,
            limit: options.limit || 50
        });
        
        try {
            const response = await axios.get(
                `${this.baseURL}/mutations?${params}`,
                {
                    headers: {
                        'X-API-Key': this.apiKey
                    }
                }
            );
            return response.data;
        } catch (error) {
            throw new Error(`Get mutations failed: ${error.response?.data?.error || error.message}`);
        }
    }
}

// Usage
const api = new CutiezyAPI('your_api_key_here');
const payment = await api.createPayment(10000, 'Test payment');

Python - Webhook Handler:

from flask import Flask, request, jsonify
import hmac
import hashlib
import json
from datetime import datetime

app = Flask(__name__)
WEBHOOK_SECRET = "your_webhook_secret_here"

def verify_signature(payload, signature):
    """Verify webhook signature"""
    expected = hmac.new(
        WEBHOOK_SECRET.encode('utf-8'),
        payload,
        hashlib.sha256
    ).hexdigest()
    
    return hmac.compare_digest(signature, expected)

@app.route('/webhook/payment', methods=['POST'])
def payment_webhook():
    try:
        # Get headers and payload
        signature = request.headers.get('X-Webhook-Signature', '')
        event = request.headers.get('X-Webhook-Event', '')
        payload = request.get_data()
        
        # Verify signature
        if not verify_signature(payload, signature):
            return jsonify({'error': 'Invalid signature'}), 401
        
        data = json.loads(payload)
        
        # Process based on event type
        if event == 'payment.paid':
            transaction_id = data['data']['transaction_id']
            amount = data['data']['amount']
            
            # Update your database
            print(f"[{datetime.now()}] Payment received: {transaction_id} - Rp {amount:,}")
            
            # Return success response
            return jsonify({'status': 'success'}), 200
            
        elif event == 'payment.expired':
            # Handle expired payment
            pass
            
        elif event == 'payment.cancelled':
            # Handle cancelled payment
            pass
        
        return jsonify({'status': 'processed'}), 200
        
    except Exception as e:
        print(f"Webhook error: {str(e)}")
        return jsonify({'error': 'Processing failed'}), 500

if __name__ == '__main__':
    app.run(port=5000, debug=True)

cURL - Complete Flow:

#!/bin/bash

API_KEY="your_api_key_here"
BASE_URL="https://cutiezy.id/zy-pay/api/v1"

# 1. Create Payment
echo "Creating payment..."
CREATE_RESPONSE=$(curl -s -X POST "$BASE_URL/create-payment" \
  -H "X-API-Key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 10000,
    "description": "Test payment"
  }')

TRANSACTION_ID=$(echo $CREATE_RESPONSE | jq -r '.data.transaction_id')
echo "Transaction ID: $TRANSACTION_ID"
echo "QRIS URL: $(echo $CREATE_RESPONSE | jq -r '.data.qris_image_url')"

# 2. Check Payment Status (polling example)
echo -e "\nChecking payment status..."
for i in {1..30}; do
    STATUS_RESPONSE=$(curl -s -X GET "$BASE_URL/check-payment/$TRANSACTION_ID" \
      -H "X-API-Key: $API_KEY")
    
    STATUS=$(echo $STATUS_RESPONSE | jq -r '.data.status')
    echo "Attempt $i: Status = $STATUS"
    
    if [ "$STATUS" = "paid" ]; then
        echo "โœ… Payment successful!"
        break
    elif [ "$STATUS" = "expired" ] || [ "$STATUS" = "cancel" ]; then
        echo "โŒ Payment failed: $STATUS"
        break
    fi
    
    sleep 10  # Check every 10 seconds
done

# 3. Get Transaction History
echo -e "\nGetting transaction history..."
curl -s -X GET "$BASE_URL/mutations?limit=5" \
  -H "X-API-Key: $API_KEY" | jq '.'

โš ๏ธ 9. Error Codes

HTTP Code Error Code Description Solution
400 INVALID_REQUEST Invalid JSON format or missing required fields Check request body format
400 INVALID_AMOUNT Amount outside valid range (1,000-10,000,000) Adjust amount
401 UNAUTHORIZED Invalid or missing API key Check API key
403 FORBIDDEN Insufficient permissions Check user role
404 NOT_FOUND Transaction not found Check transaction ID
409 ALREADY_PROCESSED Transaction already paid/expired/cancelled Check transaction status
429 RATE_LIMIT_EXCEEDED Too many requests Wait and retry
500 INTERNAL_ERROR Internal server error Contact support
503 SERVICE_UNAVAILABLE Service temporarily unavailable Retry later

Error Response Format:

{
  "success": false,
  "error": "RATE_LIMIT_EXCEEDED",
  "message": "Too many requests. Please wait 3 seconds before trying again.",
  "timestamp": "2024-12-30 12:30:45",
  "details": {
    "cooldown_seconds": 3,
    "endpoint": "create-payment"
  }
}

๐Ÿ“ 10. Changelog

v1.1.0 (Latest) - 2026-09-15

v1.0.0 - 2024-12-30

Planned Features: