Dokumentasi API

DITOPUP by Ditnov API v1.0 · Base URL https://ditnov.com/api/v1

Mulai

DITOPUP by Ditnov API memungkinkan website, bot, atau aplikasi kamu menjual produk DITOPUP by Ditnov secara otomatis (H2H). Saldo yang dipakai adalah saldo akun kamu di DITOPUP by Ditnov, dengan harga reseller.

  1. Aktifkan langganan reseller di halaman Akun → Reseller.
  2. Buka Akun → API, klik Buat API Key, simpan API key dan callback secret.
  3. Daftarkan IP server kamu di whitelist (wajib), dan isi Callback URL untuk menerima update status.
  4. Isi saldo, ambil daftar produk, lalu kirim pesanan.
Base URLhttps://ditnov.com/api/v1
FormatJSON (UTF-8), request body application/json
Mata uangIDR (Rupiah, bilangan bulat)
WaktuISO 8601 UTC
Batas request120 request / menit / API key

Autentikasi

Kirim API key di header X-API-Key pada setiap request. Header Authorization: Bearer <key> juga diterima.

HTTP
GET /v1/balance HTTP/1.1
Host: ditnov.com
X-API-Key: dk_live_xxxxxxxxxxxxxxxxxxxxxxxx
Accept: application/json
Jaga kerahasiaan API key. Simpan hanya di server, jangan di aplikasi mobile atau JavaScript browser. API key hanya ditampilkan sekali saat dibuat. Bila bocor, buat key baru dari halaman Akun dan key lama langsung tidak berlaku.

Format Respons

Semua respons memakai pola yang sama.

JSON — sukses
{
  "success": true,
  "data": { ... }
}
JSON — gagal
{
  "success": false,
  "error": {
    "code": "insufficient_balance",
    "message": "Saldo tidak mencukupi. Silakan deposit terlebih dahulu."
  }
}

Daftar Endpoint

GET/balanceCek saldo
GET/categoriesDaftar kategori
GET/productsDaftar produk & harga
POST/validateCek nama akun tujuan
POST/orderBuat transaksi
GET/order/{ref_id}Cek status transaksi
GET/ordersRiwayat transaksi

Cek Saldo

GET/balance
cURL
curl https://ditnov.com/api/v1/balance \
  -H "X-API-Key: $API_KEY"
JSON
{
  "success": true,
  "data": {
    "balance": 500000,
    "currency": "IDR",
    "tier": "reseller",
    "reseller_until": "2026-11-23T03:00:00+00:00"
  }
}

Daftar Produk

GET/products
ParameterKeterangan
categoryOpsional. Nama kategori persis, mis. Game.
qOpsional. Kata kunci nama produk.
codeOpsional. Satu kode produk.
cURL
curl "https://ditnov.com/api/v1/products?category=Game" \
  -H "X-API-Key: $API_KEY"
JSON
{
  "success": true,
  "data": [
    {
      "code": "TIK1",
      "product": "Tiktok",
      "name": "TikTok Saves (100/20k) {5k-10k/day} [R30]",
      "category": "SMM",
      "price": 19500,
      "normal_price": 19500,
      "promo": false,
      "status": "available",
      "stock": null,
      "max_qty": 1,
      "fields": [
        { "key": "target", "label": "User ID", "required": true },
        { "key": "zone", "label": "Server / Zone ID", "required": true }
      ],
      "validate": true,
      "image": null
    }
  ]
}
  • code dipakai saat order. Kode bersifat tetap, tapi produk bisa nonaktif sewaktu-waktu.
  • price adalah harga yang dipotong dari saldo kamu per unit (sudah termasuk promo bila ada).
  • fields menunjukkan data yang wajib dikirim saat order: target (ID/nomor tujuan) dan zone (server/zone).
  • stock berisi angka untuk produk berstok terbatas, null berarti tidak dibatasi.
  • Harga bisa berubah. Ambil ulang daftar produk secara berkala (mis. tiap 15–60 menit) dan simpan di cache kamu.

Cek Nama Akun

POST/validate

Untuk produk dengan "validate": true, cek nama akun tujuan sebelum order. Opsional, tidak memotong saldo.

cURL
curl -X POST https://ditnov.com/api/v1/validate \
  -H "X-API-Key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"product":"TIK1","target":"12345678","zone":"1234"}'
JSON
{
  "success": true,
  "data": { "product": "TIK1", "target": "12345678", "zone": "1234", "name": "NamaPemain" }
}

Buat Transaksi

POST/order
FieldKeterangan
ref_idWajib. ID transaksi dari sistem kamu, unik, 4–64 karakter (huruf, angka, . - _).
productWajib. Kode produk dari /products.
targetID / nomor / email tujuan (sesuai fields).
zoneServer / Zone ID bila diperlukan.
qtyOpsional, default 1. Maksimal sesuai max_qty.
cURL
curl -X POST https://ditnov.com/api/v1/order \
  -H "X-API-Key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"ref_id":"INV-20261024-0001","product":"TIK1","target":"12345678","zone":"1234"}'
JSON — 201 Created
{
  "success": true,
  "data": {
    "ref_id": "INV-20261024-0001",
    "trx_id": "TS2610241030451234",
    "product": "TIK1",
    "product_name": "Tiktok TikTok Saves (100/20k) {5k-10k/day} [R30]",
    "item_name": "TikTok Saves (100/20k) {5k-10k/day} [R30]",
    "qty": 1,
    "target": "12345678",
    "zone": "1234",
    "price": 19500,
    "total": 19500,
    "refunded": 0,
    "status": "processing",
    "message": "",
    "sn": null,
    "data": [],
    "note": null,
    "created_at": "2026-10-24T03:30:45+00:00",
    "updated_at": "2026-10-24T03:30:46+00:00",
    "balance": 480500
  }
}
Aman dikirim ulang. Bila koneksi putus atau timeout, kirim ulang request dengan ref_id yang sama. Sistem tidak akan membuat transaksi dobel, dan mengembalikan transaksi yang sudah ada dengan "duplicate": true.

Saldo langsung dipotong saat transaksi dibuat. Bila transaksi gagal, dana dikembalikan otomatis ke saldo (lihat field refunded).

Status Transaksi

GET/order/{ref_id}

Isi {ref_id} dengan ref_id kamu atau trx_id.

cURL
curl https://ditnov.com/api/v1/order/INV-20261024-0001 \
  -H "X-API-Key: $API_KEY"
statusArtiFinal
pendingTransaksi diterima, menunggu diprosesTidak
processingSedang diprosesTidak
successBerhasil. Cek sn (nomor seri/bukti) atau data (akun/lisensi/voucher)Ya
failedGagal, dana dikembalikan ke saldoYa
canceledDibatalkan, dana dikembalikan ke saldoYa

Untuk produk berisi akun/lisensi (mis. aplikasi premium), data dikirim di array data dan petunjuk tambahan di note.

Riwayat Transaksi

GET/orders
ParameterKeterangan
statusOpsional: pending, processing, success, failed, canceled
from / toOpsional, format YYYY-MM-DD
page / per_pageDefault 1 / 50, maksimal 100 per halaman

Callback (Webhook)

Setiap status transaksi berubah, sistem mengirim POST ke Callback URL kamu. Callback URL wajib https://.

HTTP
POST /callback HTTP/1.1
Content-Type: application/json
X-Event: order.updated
X-Timestamp: 1761276650
X-Signature: 5f2b...c91e
JSON
{
  "event": "order.updated",
  "data": { ...sama dengan respons /order/{ref_id}... }
}
  • Verifikasi setiap callback: X-Signature = HMAC-SHA256 dari raw body dengan callback secret kamu (hex).
  • Balas dengan HTTP 2xx dalam 10 detik. Selain itu dianggap gagal dan dikirim ulang hingga 5 kali (1, 5, 15, 30, 60 menit).
  • Callback bisa datang lebih dari sekali atau tidak berurutan. Proses berdasarkan ref_id + status, dan abaikan bila status di sistem kamu sudah final.
  • Tetap sediakan pengecekan berkala lewat /order/{ref_id} sebagai cadangan.
  • Tombol Tes Callback di Akun → API mengirim event ping.
PHP — verifikasi callback
<?php
$secret = 'whsec_xxxxxxxxxxxxxxxx';
$raw    = file_get_contents('php://input');
$sig    = $_SERVER['HTTP_X_SIGNATURE'] ?? '';

if (!hash_equals(hash_hmac('sha256', $raw, $secret), $sig)) {
    http_response_code(401);
    exit('invalid signature');
}
$event = json_decode($raw, true);
if ($event['event'] === 'order.updated') {
    $o = $event['data'];
    // update transaksi $o['ref_id'] di database kamu menjadi $o['status']
}
http_response_code(200);
echo 'OK';
Node.js (Express) — verifikasi callback
const crypto = require('crypto');
app.post('/callback', express.raw({ type: 'application/json' }), (req, res) => {
  const sig = crypto.createHmac('sha256', process.env.CALLBACK_SECRET).update(req.body).digest('hex');
  if (sig !== req.get('X-Signature')) return res.status(401).send('invalid signature');
  const event = JSON.parse(req.body);
  // proses event.data.ref_id & event.data.status
  res.send('OK');
});

Contoh Kode

PHP
<?php
function api($method, $path, $body = null) {
    $ch = curl_init('https://ditnov.com/api/v1' . $path);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_CUSTOMREQUEST  => $method,
        CURLOPT_TIMEOUT        => 60,
        CURLOPT_HTTPHEADER     => ['X-API-Key: ' . getenv('API_KEY'), 'Content-Type: application/json'],
    ]);
    if ($body) curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body));
    $res = json_decode(curl_exec($ch), true);
    curl_close($ch);
    return $res;
}

$order = api('POST', '/order', [
    'ref_id'  => 'INV-' . time(),
    'product' => 'TIK1',
    'target'  => '12345678',
    'zone'    => '1234',
]);
if ($order['success']) {
    echo $order['data']['status'];
} else {
    echo $order['error']['code'] . ': ' . $order['error']['message'];
}
Node.js
const BASE = 'https://ditnov.com/api/v1';
async function api(method, path, body) {
  const r = await fetch(BASE + path, {
    method,
    headers: { 'X-API-Key': process.env.API_KEY, 'Content-Type': 'application/json' },
    body: body ? JSON.stringify(body) : undefined,
  });
  return r.json();
}

const order = await api('POST', '/order', {
  ref_id: 'INV-' + Date.now(),
  product: 'TIK1',
  target: '12345678',
  zone: '1234',
});
console.log(order.success ? order.data.status : order.error);
Python
import os, time, requests
BASE = 'https://ditnov.com/api/v1'
H = {'X-API-Key': os.environ['API_KEY']}

r = requests.post(BASE + '/order', headers=H, timeout=60, json={
    'ref_id': f'INV-{int(time.time())}',
    'product': 'TIK1',
    'target': '12345678',
    'zone': '1234',
}).json()
print(r['data']['status'] if r['success'] else r['error'])

Kode Error

HTTPcodeArti
400invalid_requestParameter kurang atau salah format
401unauthorizedAPI key tidak dikirim atau salah
402insufficient_balanceSaldo tidak mencukupi
403ip_not_whitelistedIP server belum didaftarkan
403reseller_requiredLangganan reseller tidak aktif
403key_disabled / account_disabledAkses dicabut admin
404product_unavailableKode produk salah, nonaktif, atau stok habis
404order_not_foundref_id tidak ditemukan
409duplicate_ref_idref_id sedang diproses bersamaan
422order_rejectedTransaksi ditolak. Dana sudah dikembalikan, detail ada di data
422target_not_foundID tujuan tidak ditemukan saat cek nama
429rate_limitedTerlalu banyak request, ulangi setelah header Retry-After
503api_disabled / service_unavailableLayanan sedang tidak tersedia

Untuk error 5xx atau timeout saat membuat transaksi, jangan langsung anggap gagal. Cek dulu lewat /order/{ref_id} atau kirim ulang dengan ref_id yang sama.

Ketentuan Pemakaian

  • API hanya untuk reseller aktif dan dipakai untuk menjual kembali ke pelanggan kamu sendiri.
  • Kamu bertanggung jawab atas data tujuan yang dikirim. Transaksi yang sudah sukses ke tujuan yang salah tidak bisa dibatalkan.
  • Dilarang membebani sistem secara berlebihan, menguji celah keamanan, atau membagikan API key ke pihak lain.
  • Akses API bisa dicabut bila terjadi penyalahgunaan. Ketentuan lain mengikuti Syarat & Ketentuan.