Get started with Cutiezy API in minutes!
# Base URLhttps://cutiezy.id/zy-pay/api/v1/# Authentication HeaderX-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"}' API Keys All API requests require authentication via API Key.
X-API-Key: ak_7d8f9e1a2b3c4d5e6f7a8b9c0d1e2f3
Settings ā API KeysAPI 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 |
All endpoints | 100 requests | 1 minute | Global rate limit |
Create a new QRIS payment request.
{ "amount": 10000, "description": "Payment for order #123", "webhook_url": "https://your-webhook.com/callback"} | 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 |
{ "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/qris/QRIS20241230123045ABCDEF.png", "qris_string": "00020101021126670014...", "expired_at": "2024-12-30 12:45:45", "status": "pending", "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 = 0.5% of amount (rounded down)fee = Math.floor(amount * 0.5 / 100);// Total = Amount + Feetotal_amount = amount + fee;
Check payment status by transaction ID. Supports both URL path and query parameter.
OR: GET /check-payment?transaction_id={transaction_id}
OR: GET /check-payment?id={reference_id}
{ "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" }} Cancel a pending payment before it expires or gets paid.
{ "transaction_id": "QRIS20241230123045ABCDEF"} OR:
{ "id": 12345} { "success": true, "message": "Payment cancelled successfully", "data": { "transaction_id": "QRIS20241230123045ABCDEF", "reference_id": 12345, "status": "cancelled", "cancelled_at": "2024-12-30 12:35:10" }} Get transaction history with filtering, pagination, and date range.
| 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) |
GET /mutations?start_date=2024-12-01&end_date=2024-12-31&status=paid&page=1&limit=20
{ "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" }} Get user profile information, balance, and transaction statistics.
{ "success": true, "data": { "user": { "user_id": 1, "username": "johndoe", "email": "john@example.com", "role": "user" }, "balance": { "available": 1500000.00, "currency": "IDR" }, "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 } }} Real-time notifications for payment events sent to your webhook URL.
Profile ā Webhook Settingswebhook_url parameter in create-payment request// Verify webhook signatureconst 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) );} { "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"} | 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 |
| 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 |
<?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";}?> 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}`); } }}// Usageconst api = new CutiezyAPI('your_api_key_here');const payment = await api.createPayment(10000, 'Test payment'); from flask import Flask, request, jsonifyimport hmacimport hashlibimport jsonfrom datetime import datetimeapp = 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'}), 500if __name__ == '__main__': app.run(port=5000, debug=True) #!/bin/bashAPI_KEY="your_api_key_here"BASE_URL="https://cutiezy.id/zy-pay/api/v1"# 1. Create Paymentecho "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 secondsdone# 3. Get Transaction Historyecho -e "\nGetting transaction history..."curl -s -X GET "$BASE_URL/mutations?limit=5" \ -H "X-API-Key: $API_KEY" | jq '.' | 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 |
{ "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" }}