Revo.id
Masuk Buat Toko Gratis
Developer

Dokumentasi API Revo.id

Kelola lisensi software, akses member, dan pembayaran dari website atau aplikasi Anda sendiri. Versi API: v1

Daftar isi
  1. Ringkasan
  2. Mulai dalam 5 menit
  3. Autentikasi & format
  4. A. Jual lisensi software
  5. B. Jual akses website / membership
  6. C. Checkout dari website Anda
  7. Sandbox (mode uji)
  8. Webhook
  9. Referensi endpoint
  10. Objek data
  11. Kode error
  12. Checklist keamanan

Ringkasan

Anda menjual produk di Revo.id — pembayaran QRIS / Virtual Account, invoice, saldo, dan penarikan dana kami urus. API ini menghubungkan transaksi tersebut ke sistem Anda sendiri:

Anda menjual…Yang dipakai
Plugin, tema, template, aplikasi desktop / mobile yang butuh kunci lisensiLisensi otomatis + endpoint /licenses/activate, /validate, /deactivate (tanpa API key)
Akses ke website / SaaS / kelas online Anda (sekali bayar atau langganan bulanan)Webhook order.paid & subscription.expired + endpoint GET /access
Tombol beli di website Anda sendiriPOST /checkouts → arahkan pembeli ke checkout_url → kembali ke return_url

Base URL semua endpoint:

https://revo.id/api/v1

Mulai dalam 5 menit

  1. Buka produk Anda di Dasbor → Produk, centang Lisensi software, dan tentukan batas aktivasi (mis. 1 domain). Catat Product ID-nya.
  2. Buka Dasbor → Developer, klik Buat API key, simpan key rv_live_… di server Anda (variabel lingkungan, jangan di kode publik).
  3. Isi URL webhook (mis. https://aplikasianda.com/webhooks/revo), salin signing secret whsec_…, lalu klik Kirim webhook tes.
  4. Setiap pembelian lunas otomatis membuat kunci lisensi (format XXXXX-XXXXX-XXXXX-XXXXX) yang tampil di halaman akses & email pembeli, dan server Anda menerima webhook order.paid.

Autentikasi & format

API key (endpoint privat)

Kirim API key di header Authorization. Bila hosting Anda menghapus header tersebut, gunakan X-Revo-Key.

curl https://revo.id/api/v1/me \
  -H "Authorization: Bearer rv_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
  • API key memberi akses penuh ke data toko Anda. Hanya pakai dari server — jangan masukkan ke plugin/aplikasi yang dipasang pembeli, aplikasi mobile, atau JavaScript browser.
  • Ada dua jenis key: rv_live_… untuk transaksi asli dan rv_test_… untuk sandbox. Data keduanya terpisah: key uji hanya melihat dan membuat data uji.
  • Maksimal 10 key aktif per toko; key bisa dicabut kapan saja dari dasbor. Key hanya ditampilkan sekali saat dibuat.
  • Batas: 300 permintaan/menit per API key, dan 60 permintaan/menit per IP untuk endpoint lisensi publik. Melewati batas → HTTP 429.

Format

  • Request & response berupa JSON (Content-Type: application/json). Parameter juga boleh dikirim sebagai form / query string.
  • Nominal uang dalam rupiah, bilangan bulat (49000 = Rp 49.000).
  • Waktu dalam ISO 8601 UTC, mis. 2026-10-26T03:15:00Z.
  • Objek tunggal dibungkus {"data": {…}}; daftar dibungkus {"data": […], "meta": {"page", "per_page", "total", "total_pages"}}. Parameter paging: page, per_page (maks. 100).
  • Error berbentuk {code, message, data.status}:
HTTP/1.1 404 Not Found
{
  "code": "license_not_found",
  "message": "Lisensi tidak ditemukan.",
  "data": { "status": 404 }
}

A. Jual lisensi software

Cocok untuk plugin WordPress, tema, aplikasi desktop, bot, atau script. Aplikasi yang dipasang pembeli memanggil endpoint lisensi tanpa API key — kunci lisensi itu sendiri yang menjadi kredensial.

Siklus lisensi

StatusArti
activeSah dipakai.
expiredLisensi produk membership yang langganannya berakhir (otomatis aktif lagi bila diperpanjang).
disabledDinonaktifkan oleh Anda (dasbor atau API). Bisa diaktifkan kembali.
refundedPesanan direfund — permanen.

Instance adalah identitas tempat lisensi dipakai: domain situs (tokoanda.com; https:// dan www. dihapus otomatis) atau ID perangkat. Jumlah instance dibatasi oleh batas aktivasi produk (0 = tanpa batas). Mengaktifkan ulang instance yang sama tidak menambah hitungan. Pembeli bisa melepas perangkat dari halaman aksesnya.

1. Aktivasi — saat pembeli memasukkan kunci

POST https://revo.id/api/v1/licenses/activate
Content-Type: application/json

{
  "license_key": "RV7KD-Q2MXA-9HTPL-WZ3NC",
  "product_id": 123,
  "instance": "tokopembeli.com",
  "label": "Situs utama"
}
200 OK
{
  "activated": true,
  "instance": "tokopembeli.com",
  "license": {
    "key": "RV7KD-Q2MXA-9HTPL-WZ3NC",
    "status": "active",
    "product_id": 123,
    "product": "Plugin Ongkir Pro",
    "store": "budi",
    "max_activations": 1,
    "activations": 1,
    "expires_at": null
  }
}

Gagal: 404 license_not_found, 403 product_mismatch, 403 activation_limit, 403 license_expired / license_disabled / license_refunded, 400 instance_required.

Selalu kirim product_id — tanpa itu, kunci dari produk lain (bahkan dari toko lain) akan dianggap sah oleh aplikasi Anda.

2. Validasi — cek berkala

Panggil saat aplikasi dibuka atau maksimal sekali sehari (simpan hasilnya di cache). Response selalu 200 untuk kunci yang dikenal; lihat field valid.

POST https://revo.id/api/v1/licenses/validate
{ "license_key": "RV7KD-Q2MXA-9HTPL-WZ3NC", "product_id": 123, "instance": "tokopembeli.com" }

200 OK
{
  "valid": false,
  "reason": "instance_not_activated",   // atau license_expired, license_disabled, license_refunded
  "activated": false,
  "license": { "key": "…", "status": "active", "product_id": 123, … }
}

Tanpa instance, valid hanya memeriksa status lisensi.

3. Deaktivasi — saat plugin dinonaktifkan / pindah domain

POST https://revo.id/api/v1/licenses/deactivate
{ "license_key": "RV7KD-Q2MXA-9HTPL-WZ3NC", "product_id": 123, "instance": "tokopembeli.com" }

200 OK
{ "deactivated": true, "license": { … "activations": 0 } }

Contoh: plugin WordPress

<?php
// Di plugin yang Anda jual. Tidak memakai API key.
const MYPLUGIN_REVO_API     = 'https://revo.id/api/v1';
const MYPLUGIN_PRODUCT_ID   = 123;

function myplugin_license_call( $action, $key ) {
	$res = wp_remote_post( MYPLUGIN_REVO_API . '/licenses/' . $action, array(
		'timeout' => 15,
		'headers' => array( 'Content-Type' => 'application/json' ),
		'body'    => wp_json_encode( array(
			'license_key' => trim( $key ),
			'product_id'  => MYPLUGIN_PRODUCT_ID,
			'instance'    => wp_parse_url( home_url(), PHP_URL_HOST ),
			'label'       => get_bloginfo( 'name' ),
		) ),
	) );
	if ( is_wp_error( $res ) ) {
		return $res; // Server tidak terjangkau: jangan langsung matikan fitur.
	}
	return json_decode( wp_remote_retrieve_body( $res ), true );
}

// Saat pengguna menyimpan kunci di halaman pengaturan plugin:
$result = myplugin_license_call( 'activate', $_POST['license_key'] );
if ( ! empty( $result['activated'] ) ) {
	update_option( 'myplugin_license', sanitize_text_field( $_POST['license_key'] ) );
} else {
	$message = $result['message'] ?? 'Lisensi tidak valid';
}

// Cek harian (WP-Cron), dengan toleransi offline 7 hari:
add_action( 'myplugin_daily', function () {
	$r = myplugin_license_call( 'validate', get_option( 'myplugin_license' ) );
	if ( is_wp_error( $r ) ) {
		return; // Coba lagi besok; matikan fitur hanya bila gagal terus > 7 hari.
	}
	update_option( 'myplugin_license_ok', ! empty( $r['valid'] ) );
	update_option( 'myplugin_license_checked', time() );
} );

// Saat plugin dinonaktifkan:
register_deactivation_hook( __FILE__, function () {
	myplugin_license_call( 'deactivate', get_option( 'myplugin_license' ) );
} );

Contoh: aplikasi Node.js / Electron

const REVO = 'https://revo.id/api/v1';

async function activateLicense(key, deviceId) {
  const res = await fetch(`${REVO}/licenses/activate`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ license_key: key, product_id: 123, instance: deviceId, label: os.hostname() }),
  });
  const body = await res.json();
  if (!res.ok) throw new Error(body.message);   // mis. "Batas aktivasi tercapai (1)."
  return body.license;
}

Kelola lisensi dari server Anda (API key)

GET  https://revo.id/api/v1/licenses?email=pembeli@mail.com&product_id=123
GET  https://revo.id/api/v1/licenses/RV7KD-Q2MXA-9HTPL-WZ3NC          // termasuk daftar instance
POST https://revo.id/api/v1/licenses/RV7KD-Q2MXA-9HTPL-WZ3NC
     { "status": "disabled", "note": "Chargeback" }     // atau "active"
     { "max_activations": 3 }                            // ubah batas
     { "reset_activations": true }                       // hapus semua aktivasi

B. Jual akses website / membership

Pembeli membayar di Revo.id, website Anda yang memberi akses. Dua cara yang bisa digabung:

Cara 1 — Webhook (disarankan)

  1. order.paid → buat / aktifkan akun berdasarkan data.customer.email. Untuk produk membership, simpan data.subscription_id.
  2. subscription.renewed → perpanjang akses sampai data.current_period_end.
  3. subscription.expired atau order.refunded → cabut akses.
  4. subscription.cancelled → anggota berhenti; akses tetap sampai current_period_end, lalu menyusul subscription.expired.

Cara 2 — Cek akses saat login

GET https://revo.id/api/v1/access?email=pembeli@mail.com&product_id=456
Authorization: Bearer rv_live_…

200 OK
{
  "data": {
    "access": true,
    "email": "pembeli@mail.com",
    "product_id": 456,
    "source": "subscription",            // "order" untuk produk sekali bayar
    "subscription_id": 88,
    "status": "active",
    "order_number": null,
    "expires_at": "2026-11-26T03:15:00Z"
  }
}

Untuk membership, access tetap true selama masa tenggang perpanjangan. Untuk produk sekali bayar, access bernilai true bila ada pesanan lunas (termasuk sebagai order bump) yang tidak direfund. Simpan hasilnya di sesi beberapa menit — jangan panggil di setiap request halaman.

Contoh: middleware PHP

function revo_has_access( string $email, int $productId ): bool {
    $ch = curl_init( 'https://revo.id/api/v1/access?' . http_build_query( [ 'email' => $email, 'product_id' => $productId ] ) );
    curl_setopt_array( $ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT        => 10,
        CURLOPT_HTTPHEADER     => [ 'Authorization: Bearer ' . getenv( 'REVO_API_KEY' ) ],
    ] );
    $body = json_decode( (string) curl_exec( $ch ), true );
    curl_close( $ch );
    return ! empty( $body['data']['access'] );
}

if ( ! revo_has_access( $_SESSION['email'], 456 ) ) {
    header( 'Location: https://revo.id/budi/kelas-premium' ); // halaman jual produk
    exit;
}

C. Checkout dari website Anda

Buat pesanan dari server, lalu arahkan pembeli ke checkout_url untuk membayar dengan QRIS / Virtual Account. Setelah lunas, halaman sukses menampilkan tombol kembali ke return_url (ditambah ?revo_order=RV-…&status=paid).

POST https://revo.id/api/v1/checkouts
Authorization: Bearer rv_live_…
Content-Type: application/json

{
  "product_id": 123,
  "customer": { "name": "Siti Aminah", "email": "siti@mail.com", "phone": "081234567890" },
  "external_id": "user_9812",                 // ID di sistem Anda (opsional, bisa difilter)
  "metadata": { "plan": "pro", "team": 7 },    // bebas, maks. 2.000 karakter JSON
  "return_url": "https://aplikasianda.com/billing/selesai",
  "coupon": "HEMAT20",                         // opsional
  "amount": 75000,                             // hanya untuk produk "bayar seikhlasnya"
  "bump": false,                               // ikut ambil order bump produk ini
  "affiliate": "username_afiliator"            // opsional, komisi untuk afiliator
}

201 Created
{
  "data": {
    "id": 5012,
    "number": "RV-261026-005012",
    "status": "unpaid",
    "amount": 149000,
    "external_id": "user_9812",
    "metadata": { "plan": "pro", "team": 7 },
    "checkout_url": "https://revo.id/app/?iv=order&t=3f9c…",
    …
  }
}
  • Pesanan belum dibayar otomatis kedaluwarsa. Buat checkout baru setiap kali pembeli menekan tombol beli.
  • Jangan anggap pesanan lunas dari return_url — parameter di URL bisa diubah siapa saja. Konfirmasi lewat webhook order.paid atau GET /orders/{number}.
  • Produk gratis (atau kupon 100%) langsung berstatus paid pada response.
  • Validasi gagal → 422 dengan kode checkout_*, mis. checkout_email, checkout_soldout, checkout_member (email masih berlangganan).

Sandbox (mode uji)

Coba seluruh integrasi tanpa uang sungguhan. Buat API key mode Sandbox di Dasbor → Developer (rv_test_…), lalu pakai endpoint yang sama persis.

  • POST /checkouts dengan key uji membuat pesanan uji dari produk asli Anda (tidak butuh gateway pembayaran). checkout_url menampilkan tombol Bayar berhasil (simulasi) dan Gagal / dibatalkan, tanpa QRIS/VA.
  • Pembayaran simulasi memicu semua efek nyata: lisensi diterbitkan, langganan dimulai, halaman akses terbuka, dan webhook terkirim ke URL webhook yang sama.
  • Tidak ada uang, saldo, komisi afiliasi, email, maupun WhatsApp. Pesanan uji tidak muncul di statistik, daftar pesanan, pembeli, anggota, lisensi, atau ekspor CSV.
  • Semua objek punya field "livemode": false; payload webhook juga, ditambah header Revo-Mode: test. Di server produksi, abaikan event dengan livemode false (atau pakai server terpisah untuk uji).
  • Kunci lisensi uji bisa diaktifkan lewat endpoint lisensi publik seperti biasa; license.livemode bernilai false sehingga aplikasi Anda bisa menolaknya di build produksi.
  • Key live tidak bisa melihat data uji, dan sebaliknya (404).

Simulasi lewat API (key uji saja)

POST https://revo.id/api/v1/sandbox/orders/{id atau nomor}/pay       → order.paid (+ lisensi, langganan)
POST https://revo.id/api/v1/sandbox/orders/{id atau nomor}/fail      → pesanan dibatalkan
POST https://revo.id/api/v1/sandbox/orders/{id atau nomor}/refund    → order.refunded, license.updated
POST https://revo.id/api/v1/sandbox/subscriptions/{id}/renew         → subscription.renewed (+ order.paid perpanjangan)
POST https://revo.id/api/v1/sandbox/subscriptions/{id}/cancel        → subscription.cancelled
POST https://revo.id/api/v1/sandbox/subscriptions/{id}/expire        → subscription.expired
POST https://revo.id/api/v1/sandbox/reset                            → hapus semua data uji toko

Contoh alur uji otomatis:

KEY=rv_test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
ORDER=$(curl -s https://revo.id/api/v1/checkouts -H "Authorization: Bearer $KEY" -H "Content-Type: application/json"   -d '{"product_id":123,"customer":{"name":"Uji","email":"uji@contoh.com"}}' | jq -r .data.number)
curl -s -X POST https://revo.id/api/v1/sandbox/orders/$ORDER/pay -H "Authorization: Bearer $KEY" | jq .data.licenses

Endpoint /sandbox/… dengan key live dijawab 403 sandbox_only. Di Dasbor → Developer ada panel Sandbox untuk melihat pesanan uji, menjalankan simulasi, dan menghapus semua data uji.

Webhook

Kami mengirim POST JSON ke URL webhook toko Anda setiap ada kejadian berikut:

EventKapandata berisi
order.paidPesanan lunas (termasuk perpanjangan membership & produk gratis)Order
order.refundedPesanan direfund — cabut akses pembeliOrder
subscription.createdLangganan membership baru dimulaiSubscription
subscription.renewedLangganan diperpanjang satu periodeSubscription
subscription.cancelledAnggota berhenti (akses tetap sampai akhir periode)Subscription
subscription.expiredLangganan berakhir — cabut aksesSubscription
license.updatedStatus lisensi diubah (dinonaktifkan / diaktifkan / direfund)License
pingTes dari dasbor atau API{ "message" }

Contoh payload

POST /webhooks/revo HTTP/1.1
Content-Type: application/json
Revo-Event: order.paid
Revo-Delivery: evt_5b0c9f2e4a1d7c3b8e6f0a12
Revo-Signature: t=1792984500,v1=6f1c0d…e93a

{
  "id": "evt_5b0c9f2e4a1d7c3b8e6f0a12",
  "type": "order.paid",
  "created_at": "2026-10-26T03:15:00Z",
  "store": "budi",
  "data": {
    "id": 5012,
    "number": "RV-261026-005012",
    "status": "paid",
    "product_id": 123,
    "customer": { "name": "Siti Aminah", "email": "siti@mail.com", "phone": "6281234567890" },
    "paid_amount": 149000,
    "external_id": "user_9812",
    "metadata": { "plan": "pro", "team": 7 },
    "subscription_id": null,
    "licenses": [ { "key": "RV7KD-Q2MXA-9HTPL-WZ3NC", "status": "active", "max_activations": 1, … } ],
    …
  }
}

Verifikasi tanda tangan

Header Revo-Signature berisi t (Unix time) dan v1 = HMAC-SHA256 (hex) dari string "{t}.{raw body}" dengan signing secret whsec_…. Tolak bila tanda tangan tidak cocok atau t lebih dari 5 menit dari sekarang. Gunakan body mentah sebelum di-parse.

PHP

$secret = getenv( 'REVO_WEBHOOK_SECRET' );           // whsec_…
$body   = file_get_contents( 'php://input' );
$header = $_SERVER['HTTP_REVO_SIGNATURE'] ?? '';
parse_str( str_replace( ',', '&', $header ), $sig );  // ['t' => …, 'v1' => …]

$expected = hash_hmac( 'sha256', ( $sig['t'] ?? '' ) . '.' . $body, $secret );
if ( empty( $sig['v1'] ) || ! hash_equals( $expected, $sig['v1'] ) || abs( time() - (int) $sig['t'] ) > 300 ) {
    http_response_code( 401 );
    exit;
}

$event = json_decode( $body, true );
// Idempoten: abaikan bila $event['id'] sudah pernah diproses.
switch ( $event['type'] ) {
    case 'order.paid':
        grant_access( $event['data']['customer']['email'], $event['data']['product_id'] );
        break;
    case 'order.refunded':
    case 'subscription.expired':
        revoke_access( $event['data']['customer']['email'], $event['data']['product_id'] );
        break;
}
http_response_code( 200 );

Node.js (Express)

const crypto = require('crypto');

app.post('/webhooks/revo', express.raw({ type: 'application/json' }), (req, res) => {
  const sig = Object.fromEntries(req.get('Revo-Signature').split(',').map(p => p.split('=')));
  const expected = crypto.createHmac('sha256', process.env.REVO_WEBHOOK_SECRET)
    .update(`${sig.t}.${req.body}`).digest('hex');
  const ok = sig.v1 && crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(sig.v1))
    && Math.abs(Date.now() / 1000 - Number(sig.t)) < 300;
  if (!ok) return res.sendStatus(401);

  const event = JSON.parse(req.body);
  // … proses event.type
  res.sendStatus(200);
});

Pengiriman ulang

  • URL webhook harus alamat publik (alamat internal/privat ditolak) di port 80, 443, atau 8080; sebaiknya https://.
  • Balas dengan HTTP 2xx dalam 10 detik. Proses berat sebaiknya dijalankan di antrean Anda.
  • Selain 2xx (atau timeout), kami mencoba lagi setelah 1 menit, 5 menit, 30 menit, 2 jam, 6 jam, dan 24 jam (7 percobaan). Redirect tidak diikuti.
  • Event yang sama bisa terkirim lebih dari sekali — gunakan id event (juga di header Revo-Delivery) untuk mencegah proses ganda. Urutan event tidak dijamin.
  • Riwayat pengiriman, tombol Kirim ulang, dan Kirim webhook tes ada di Dasbor → Developer. Tes juga bisa lewat POST /webhooks/test.

Referensi endpoint

Metode & pathAuthKegunaan
GET /meAPI keyToko pemilik key.
GET /productsAPI keyDaftar produk (status: active, draft, all).
GET /products/{id}API keyDetail produk.
POST /checkoutsAPI keyBuat pesanan + link pembayaran.
GET /ordersAPI keyFilter: status (paid, unpaid, cancelled, refunded), email, product_id, external_id, page, per_page.
GET /orders/{id atau nomor}API keyDetail pesanan, termasuk lisensinya.
GET /accessAPI keyApakah email punya akses ke product_id.
GET /subscriptionsAPI keyFilter: status, email, product_id.
GET /subscriptions/{id}API keyDetail langganan.
GET /licensesAPI keyFilter: email, product_id.
GET /licenses/{key}API keyDetail lisensi + instance aktif.
POST /licenses/{key}API keystatus, max_activations, reset_activations, note.
POST /webhooks/testAPI keyKirim event ping sekarang.
POST /sandbox/…Key ujiSimulasi bayar, gagal, refund, perpanjang, berhenti, berakhir, reset.
POST /licenses/activateKunci lisensilicense_key, instance, product_id, label.
POST /licenses/validateKunci lisensilicense_key, product_id, instance (opsional).
POST /licenses/deactivateKunci lisensilicense_key, instance, product_id.

Objek data

Order

id, numberID angka dan nomor pesanan (RV-yymmdd-000123).
statusunpaid, paid, cancelled, refunded.
product_id, product_type, titleProduk yang dibeli (digital, link, service, event, membership, support).
customer{name, email, phone}.
amount, paid_amount, discount, coupon, net_amountTagihan, jumlah dibayar, diskon, kode kupon, pendapatan bersih Anda (setelah biaya & komisi afiliasi).
method, sourceCara bayar; checkout atau renewal (perpanjangan membership).
bump{product_id, amount} bila pembeli mengambil order bump.
subscription_idLangganan terkait (membership).
external_id, metadataDari POST /checkouts.
licensesDaftar License pesanan ini.
checkout_urlHalaman bayar / akses pembeli.
created_at, paid_at, refunded_atWaktu (UTC).

License

keyXXXXX-XXXXX-XXXXX-XXXXX (huruf besar & angka, tanpa O/0/I/1).
statusactive, expired, disabled, refunded.
product_id, order_id, order_number, subscription_idAsal lisensi.
customer{name, email} — hanya di endpoint ber-API key & webhook.
max_activations, activationsBatas (0 = tanpa batas) dan jumlah instance aktif.
instances[{id, instance, label, activated_at, last_seen_at}] — di GET /licenses/{key}.
expires_atAkhir periode langganan untuk lisensi membership; null = seumur hidup.

Subscription

id, product_idLangganan dan produk membership-nya.
statusactive, cancelled (berhenti di akhir periode), expired.
accesstrue bila anggota boleh mengakses sekarang (termasuk masa tenggang).
period, price, renewalsmonth/year, harga per periode, jumlah perpanjangan.
current_period_end, cancelled_at, created_atWaktu (UTC).

Kode error

HTTPcodePenyebab
400license_key_required, instance_required, invalid_email, invalid_status, invalid_return_url, metadata_too_largeParameter kurang / salah.
401missing_api_key, invalid_api_keyAPI key tidak dikirim, salah, atau sudah dicabut.
403store_inactive, product_mismatch, activation_limit, license_expired, license_disabled, license_refundedDitolak.
404not_found, product_not_found, license_not_foundData tidak ada atau bukan milik toko Anda.
403sandbox_onlyEndpoint sandbox dipanggil dengan key live.
409license_refunded, webhook_not_configured, sandbox_*Konflik status.
422checkout_*Checkout ditolak; pesan siap ditampilkan ke pembeli.
429rate_limitedTerlalu banyak permintaan; coba lagi setelah 1 menit.

Checklist keamanan

  • API key & signing secret hanya di server (variabel lingkungan), tidak di repo publik, aplikasi pembeli, atau browser. Cabut key yang bocor dari dasbor.
  • Verifikasi Revo-Signature di setiap webhook dan proses tiap id event sekali saja.
  • Kirim product_id di setiap panggilan lisensi.
  • Jangan percaya parameter return_url; konfirmasi pembayaran dari webhook atau API.
  • Toleransi gangguan jaringan: cache hasil validasi lisensi dan beri masa tenggang offline beberapa hari sebelum mematikan fitur.

Pertanyaan teknis? Hubungi info@revo.id.

© 2026 Revo.id · Pembayaran online aman via payment gateway berlisensi. · Blog · Kebijakan Privasi · Syarat & Ketentuan

Bantuan: info@revo.id