# piv.day API Reference Full reference for the piv.day REST API: every endpoint, request body, response shape, error code and webhook. Exported from https://piv.day/api/docs for use with AI assistants. --- ## Getting started REST API pada paket Business. Token Bearer, JSON, endpoint idempoten, kode error yang dapat diprediksi. Setiap endpoint dilengkapi contoh permintaan dan respons. ### Base URL ``` https://app.piv.day/api/v1 ``` Semua endpoint berada di bawah awalan ini. Satu lingkungan — tidak ada host staging terpisah. ### Autentikasi ``` Authorization: Bearer YOUR_API_KEY ``` Kunci dibuat di dashboard pada bagian `Pengaturan → API Keys`. Setiap kunci memiliki izin granular (membaca nomor, mengirim SMS, membeli proxy, dll.). Token yang bocor dirotasi dengan satu klik — tidak perlu onboard ulang tim. ### Akun **200 OK** ``` curl https://app.piv.day/api/v1/account \ -H "Authorization: Bearer YOUR_API_KEY" ``` **Satu endpoint utilitas — saldo dan email akun saat ini. Berguna untuk memastikan kunci berfungsi dan autentikasi terkonfigurasi dengan benar.** ``` { "success": true, "data": { "user_id": "usr-uuid-...", "balance": 150.50, "email": "u***@example.com", "team_id": null, "is_team_member": false } } ``` GET /api/v1/account ### Format respons ``` { "success": true, "data": { ... } } ``` Semua respons berformat JSON. Saat error, `success` = `false` dan body berisi `error.code` dan `error.message`. ### Rate limits **100 permintaan per menit per API key. Batas ini berlaku bersama untuk semua endpoint. Butuh kapasitas lebih untuk lonjakan trafik? Hubungi dukungan Telegram dan kami akan menaikkan batasnya. Saat melampaui batas, Anda mendapat `429 RATE_LIMITED` dan header `Retry-After` — berapa detik menunggu sebelum permintaan berikutnya.** ``` HTTP/1.1 429 Too Many Requests Retry-After: 12 { "success": false, "error": { "code": "RATE_LIMITED", "message": "Rate limit exceeded, retry in 12s" } } ``` 429 Too Many Requests ## Nomor Beli, perpanjang, dan pulihkan nomor. Terima dan kirim SMS. Mulai verifikasi Google QR. Berlangganan acara melalui webhook. ### Daftar negara dan harga `GET /api/v1/numbers/countries` Mengembalikan negara yang tersedia untuk dibeli dengan harga terkini dan kemampuan SMS. Semua harga sudah termasuk diskon langganan Anda. **Response fields** | Field | Type | Description | | --- | --- | --- | | `country_code` | string | Kode negara ISO dua huruf (contoh: `SE`). | | `price_per_month` | number | Harga akhir untuk paket Anda — yang benar-benar dikenakan saat pembelian. Diskon Premium / Business sudah diterapkan. | | `base_price` | number | Harga tanpa diskon (paket Free). Dikembalikan untuk perbandingan agar Anda dapat melihat berapa banyak yang dihemat dengan langganan. | | `can_send_sms` | boolean | Apakah SMS keluar didukung dari nomor ini. | | `can_receive_sms` | boolean | Apakah SMS masuk didukung. | | `sms_send_price` | number\|null | Harga SMS keluar, juga dengan diskon paket yang diterapkan. `null` ketika pengiriman tidak didukung dari negara ini. | **curl** ```bash curl https://app.piv.day/api/v1/numbers/countries \ -H "Authorization: Bearer YOUR_API_KEY" ``` **200 OK** ```json { "success": true, "data": [ { "country_code": "SE", "price_per_month": 4.00, "base_price": 5.00, "can_send_sms": true, "can_receive_sms": true, "sms_send_price": 0.25 }, { "country_code": "GB", "price_per_month": 3.00, "base_price": 3.00, "can_send_sms": true, "can_receive_sms": true, "sms_send_price": 0.20 } ] } ``` ### Daftar nomor akun `GET /api/v1/numbers` Mengembalikan halaman nomor akun dengan filter berdasarkan negara, status, dan pencarian berdasarkan nomor atau nama kustom. **Query parameters** | Field | Type | Description | | --- | --- | --- | | `limit` | integer | Ukuran halaman (default 50, maksimum 200). | | `offset` | integer | Offset paginasi. | | `country` | string | Filter kode negara ISO. | | `status` | string | Salah satu dari `active`, `expired`, `pending_restore`. | | `search` | string | Pencarian substring berdasarkan nomor telepon atau nama kustom. | **curl** ```bash curl "https://app.piv.day/api/v1/numbers?country=SE&status=active&limit=10" \ -H "Authorization: Bearer YOUR_API_KEY" ``` **200 OK** ```json { "success": true, "data": { "numbers": [ { "piv_num_id": "vzPA1-kHKSg-EAL7e-Jqd3o", "phone_number": "+46764794425", "country_code": "SE", "status": "active", "created_at": "2026-05-01T10:00:00Z", "expires_at": "2026-05-31T10:00:00Z", "auto_renew": false, "custom_name": "Office line", "purchased_at": "2026-05-01T10:00:00Z", "next_renewal_date": "2026-05-31T10:00:00Z", "tags": ["support"], "can_send_sms": true, "can_receive_sms": true } ], "pagination": { "total": 1, "limit": 10, "offset": 0 } } } ``` ### Satu nomor berdasarkan ID `GET /api/v1/numbers/{piv_num_id}` Rekaman lengkap nomor: status, tanggal, perpanjangan otomatis, tag, arah SMS yang diizinkan. **Errors** | Code | HTTP | When it fires | | --- | --- | --- | | `NUMBER_NOT_FOUND` | 404 | Nomor tidak ada atau tidak milik akun. | **curl** ```bash curl https://app.piv.day/api/v1/numbers/vzPA1-kHKSg-EAL7e-Jqd3o \ -H "Authorization: Bearer YOUR_API_KEY" ``` **200 OK** ```json { "success": true, "data": { "piv_num_id": "vzPA1-kHKSg-EAL7e-Jqd3o", "phone_number": "+46764794425", "country_code": "SE", "status": "active", "created_at": "2026-05-01T10:00:00Z", "expires_at": "2026-05-31T10:00:00Z", "auto_renew": false, "custom_name": "Office line", "purchased_at": "2026-05-01T10:00:00Z", "next_renewal_date": "2026-05-31T10:00:00Z", "tags": ["support"], "can_send_sms": true, "can_receive_sms": true } } ``` ### Beli nomor `POST /api/v1/numbers/purchase` Membeli satu nomor di negara yang dipilih untuk periode yang ditentukan. Biaya didebit dari saldo akun. Mengembalikan `piv_num_id` yang digunakan dalam semua operasi nomor selanjutnya. **Request body** | Field | Type | Description | | --- | --- | --- | | `country_code` * | string | Kode negara ISO. | | `duration_months` * | integer | Periode sewa dalam bulan (minimum 1). | | `auto_renew` * | boolean | Aktifkan perpanjangan otomatis segera setelah pembelian. | | `custom_name` | string | Nama opsional yang mudah dibaca untuk nomor. | **Errors** | Code | HTTP | When it fires | | --- | --- | --- | | `COUNTRY_NOT_AVAILABLE` | 400 | Negara tidak tersedia atau tidak ada harga. | | `NO_NUMBERS_AVAILABLE` | 400 | Tidak ada nomor yang tersedia di negara yang diminta saat ini. | | `INSUFFICIENT_BALANCE` | 402 | Saldo tidak cukup untuk pembelian. | | `VALIDATION_ERROR` | 400 | Kolom tidak valid dalam isi permintaan. | **curl** ```bash curl -X POST https://app.piv.day/api/v1/numbers/purchase \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "country_code": "SE", "duration_months": 1, "auto_renew": false, "custom_name": "My Sweden Number" }' ``` **200 OK** ```json { "success": true, "cost": 5.00, "numbers": [ { "piv_num_id": "vzPA1-kHKSg-EAL7e-Jqd3o", "country_code": "SE", "phone_number": "+46764794425", "created_at": "2026-05-01T10:00:00Z", "expires_at": "2026-05-31T10:00:00Z", "auto_renew": false, "custom_name": "My Sweden Number" } ] } ``` ### Perpanjang nomor `POST /api/v1/numbers/{piv_num_id}/renew` Memperpanjang nomor aktif untuk periode yang ditentukan. Biaya didebit saat pemanggilan. **Request body** | Field | Type | Description | | --- | --- | --- | | `duration_months` * | integer | Jumlah bulan yang akan ditambahkan. | **Errors** | Code | HTTP | When it fires | | --- | --- | --- | | `NUMBER_NOT_FOUND` | 404 | Nomor tidak ada atau tidak milik akun. | | `COUNTRY_NOT_AVAILABLE` | 400 | Tidak ada harga yang ditemukan untuk negara nomor. | | `INSUFFICIENT_BALANCE` | 402 | Dana tidak cukup untuk perpanjangan. | **curl** ```bash curl -X POST https://app.piv.day/api/v1/numbers/vzPA1-kHKSg-EAL7e-Jqd3o/renew \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "duration_months": 1 }' ``` **200 OK** ```json { "success": true, "data": { "piv_num_id": "vzPA1-kHKSg-EAL7e-Jqd3o", "phone_number": "+46764794425", "old_expires_at": "2026-05-31T10:00:00Z", "new_expires_at": "2026-06-30T10:00:00Z", "cost": 5.00 } } ``` ### Perbarui nomor `PATCH /api/v1/numbers/{piv_num_id}` Saat ini hanya nama kustom yang dapat diperbarui. **Request body** | Field | Type | Description | | --- | --- | --- | | `custom_name` * | string | Nama baru untuk nomor. | **Errors** | Code | HTTP | When it fires | | --- | --- | --- | | `NUMBER_NOT_FOUND` | 404 | Nomor tidak ada atau tidak milik akun. | | `VALIDATION_ERROR` | 400 | Nilai tidak valid dalam isi permintaan. | **curl** ```bash curl -X PATCH https://app.piv.day/api/v1/numbers/vzPA1-kHKSg-EAL7e-Jqd3o \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "custom_name": "Support line" }' ``` **200 OK** ```json { "success": true, "data": { "piv_num_id": "vzPA1-kHKSg-EAL7e-Jqd3o", "phone_number": "+46764794425", "country_code": "SE", "status": "active", "custom_name": "Support line", "auto_renew": false, "expires_at": "2026-05-31T10:00:00Z", "tags": [] } } ``` ### Kelola perpanjangan otomatis `PATCH /api/v1/numbers/{piv_num_id}/auto-renewal` Mengaktifkan atau menonaktifkan perpanjangan otomatis nomor. Ketika diaktifkan, perpanjangan didebit secara otomatis 24 jam sebelum kedaluwarsa. Jika saldo kurang, nomor akan kedaluwarsa; Anda dapat mengklaimnya kembali melalui `POST /numbers/restore` dalam 7 hari. **Request body** | Field | Type | Description | | --- | --- | --- | | `auto_renew` * | boolean | Nilai flag perpanjangan otomatis baru. | **curl** ```bash curl -X PATCH https://app.piv.day/api/v1/numbers/vzPA1-kHKSg-EAL7e-Jqd3o/auto-renewal \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "auto_renew": true }' ``` **200 OK** ```json { "success": true, "data": { "piv_num_id": "vzPA1-kHKSg-EAL7e-Jqd3o", "phone_number": "+46764794425", "auto_renew": true } } ``` ### Pulihkan nomor yang kedaluwarsa `POST /api/v1/numbers/restore` Mengklaim kembali nomor yang kedaluwarsa dalam jendela 7 hari. Kirim array `piv_num_id` — nomor kembali dengan riwayat SMS dan pengaturan yang dipertahankan. Biaya pemulihan lebih mahal dari membeli nomor baru (termasuk pengali pemulihan) — angka tepat ditampilkan di dashboard sebelum konfirmasi. Status akhir setiap nomor tiba melalui webhook `number.restore_completed`; pengembalian dana untuk nomor yang gagal dikreditkan secara otomatis. **Request body** | Field | Type | Description | | --- | --- | --- | | `piv_num_ids` * | string[] | Array ID nomor yang akan dipulihkan. | **Errors** | Code | HTTP | When it fires | | --- | --- | --- | | `NO_RESTORABLE_NUMBERS` | 404 | Tidak ada nomor yang diberikan yang dapat dipulihkan (jendela 7 hari telah berlalu atau bukan milik Anda). | | `INSUFFICIENT_BALANCE` | 402 | Dana tidak cukup untuk menutup biaya pemulihan. | **curl** ```bash curl -X POST https://app.piv.day/api/v1/numbers/restore \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "piv_num_ids": [ "vzPA1-kHKSg-EAL7e-Jqd3o", "abc12-defgh-ijklm-nopqr" ] }' ``` **200 OK** ```json { "success": true, "queued": 2, "skipped": 0, "total_charged": 9.00, "numbers": [ { "piv_num_id": "vzPA1-kHKSg-EAL7e-Jqd3o", "phone_number": "+46764794425", "status": "pending" } ] } ``` ### Riwayat SMS nomor `GET /api/v1/numbers/{piv_num_id}/sms` Mengembalikan pesan masuk dan keluar untuk nomor dalam urutan kronologis terbalik. **Query parameters** | Field | Type | Description | | --- | --- | --- | | `limit` | integer | Berapa banyak pesan yang akan dikembalikan (default 50, maksimum 200). | | `offset` | integer | Offset paginasi. | **curl** ```bash curl "https://app.piv.day/api/v1/numbers/vzPA1-kHKSg-EAL7e-Jqd3o/sms?limit=20" \ -H "Authorization: Bearer YOUR_API_KEY" ``` **200 OK** ```json { "success": true, "data": { "messages": [ { "id": "42", "from_number": "+46764794425", "to_number": "+14155551234", "message_body": "Hello from piv.day", "direction": "outbound", "status": "delivered", "received_at": "2026-05-22T11:30:00Z" }, { "id": "41", "from_number": "+14155551234", "to_number": "+46764794425", "message_body": "Hey, got your message!", "direction": "inbound", "status": "received", "received_at": "2026-05-22T11:35:00Z" } ], "pagination": { "total": 2, "limit": 20, "offset": 0 } } } ``` ### Kirim SMS `POST /api/v1/numbers/{piv_num_id}/sms/send` Tersedia untuk negara yang mengizinkan pengiriman keluar (mis. CA, GB, SE). Biaya pesan didebit saat pengiriman. **Request body** | Field | Type | Description | | --- | --- | --- | | `to_number` * | string | Nomor penerima dalam format internasional (E.164). | | `message_body` * | string | Teks pesan. GSM-7 dan UCS-2 didukung. | **Errors** | Code | HTTP | When it fires | | --- | --- | --- | | `NUMBER_NOT_FOUND` | 404 | Nomor tidak ada atau tidak milik akun. | | `NUMBER_EXPIRED` | 403 | Nomor sudah kedaluwarsa. | | `NUMBER_NOT_ACTIVE` | 400 | Nomor berada dalam status yang tidak mengizinkan pengiriman. | | `INSUFFICIENT_BALANCE` | 402 | Dana tidak cukup untuk mengirim. | | `INVALID_MESSAGE_FORMAT` | 400 | Isi pesan melebihi panjang yang diizinkan atau mengandung karakter yang dilarang. | **curl** ```bash curl -X POST https://app.piv.day/api/v1/numbers/vzPA1-kHKSg-EAL7e-Jqd3o/sms/send \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "to_number": "+14155551234", "message_body": "Hello from piv.day" }' ``` **200 OK** ```json { "success": true, "data": { "message_id": "42", "from_number": "+46764794425", "to_number": "+14155551234", "message_body": "Hello from piv.day", "status": "queued", "created_at": "2026-05-22T11:30:00Z" } } ``` ### Jalankan verifikasi Google QR `POST /api/v1/numbers/{piv_num_id}/verify` Memulai verifikasi Google QR menggunakan URL yang diberikan. Hasilnya — sukses atau gagal — tiba melalui webhook verify.completed atau verify.failed. Biaya didebit saat tugas antri. **Request body** | Field | Type | Description | | --- | --- | --- | | `gv_url` * | string | URL verifikasi Google lengkap (diambil dari halaman Google). | **Errors** | Code | HTTP | When it fires | | --- | --- | --- | | `NUMBER_NOT_FOUND` | 404 | Nomor tidak ada atau bukan milik Anda. | | `NUMBER_NOT_ACTIVE` | 400 | Nomor tidak aktif. | | `SMS_DISABLED` | 400 | Pengiriman SMS dinonaktifkan untuk nomor ini. | | `INSUFFICIENT_BALANCE` | 402 | Dana tidak cukup untuk verifikasi. | | `PROXY_DEAD` | 502 | Proxy tidak tersedia — saldo dikembalikan. | | `QUEUE_FULL` | 503 | Antrean penuh, coba lagi nanti — saldo dikembalikan. | | `SERVER_UNAVAILABLE` | 503 | Server otomasi tidak tersedia — saldo dikembalikan. | **curl** ```bash curl -X POST https://app.piv.day/api/v1/numbers/vzPA1-kHKSg-EAL7e-Jqd3o/verify \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "gv_url": "https://gv.google.com/..." }' ``` **202 Accepted** ```json { "success": true, "message": "Verification initiated" } ``` ## Proxy IPv6 residensial di puluhan negara. Pembelian massal, perpanjangan, Restore yang mempertahankan login dan password yang sama, ekspor dalam format yang dibutuhkan. ### Daftar server `GET /api/v1/proxy/servers` Server proxy yang tersedia beserta harganya. **curl** ```bash curl https://app.piv.day/api/v1/proxy/servers \ -H "Authorization: Bearer YOUR_API_KEY" ``` **200 OK** ```json { "success": true, "data": { "servers": [ { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "name": "EU-DE-01", "country": "DE", "socks5_port": 1080, "http_port": 3128, "price_per_proxy": 0.50 }, { "id": "b2c3d4e5-f6a7-8901-bcde-f12345678901", "name": "EU-NL-01", "country": "NL", "socks5_port": 1080, "http_port": 3128, "price_per_proxy": 0.45 } ] } } ``` ### Daftar pesanan `GET /api/v1/proxy/orders` Daftar pesanan proxy Anda dengan filter berdasarkan status atau pencarian. **Query parameters** | Field | Type | Description | | --- | --- | --- | | `limit` | integer | Ukuran halaman. Default 100, maksimum 500. | | `offset` | integer | Offset paginasi. | | `status` | string | Filter status: `active`, `expired`. | | `search` | string | Pencarian dalam pesanan. | **curl** ```bash curl "https://app.piv.day/api/v1/proxy/orders?status=active&limit=20" \ -H "Authorization: Bearer YOUR_API_KEY" ``` **200 OK** ```json { "success": true, "data": { "orders": [ { "id": "ord-uuid-...", "country": "DE", "quantity": 10, "price_per_proxy": 0.50, "price_total": 5.00, "status": "active", "purchased_at": "2026-01-01T00:00:00Z", "expires_at": "2026-02-01T00:00:00Z" } ], "pagination": { "total": 1, "limit": 20, "offset": 0 } } } ``` ### Ambil satu pesanan `GET /api/v1/proxy/orders/{id}` Dapatkan detail pesanan tertentu, termasuk daftar kredensial proxy. **curl** ```bash curl https://app.piv.day/api/v1/proxy/orders/ord-uuid-... \ -H "Authorization: Bearer YOUR_API_KEY" ``` **200 OK** ```json { "success": true, "data": { "order": { "id": "ord-uuid-...", "country": "DE", "quantity": 10, "price_per_proxy": 0.50, "price_total": 5.00, "status": "active", "purchased_at": "2026-01-01T00:00:00Z", "expires_at": "2026-02-01T00:00:00Z", "created_at": "2026-01-01T00:00:00Z", "items": [ { "login": "user1", "password": "pass1", "host": "185.1.2.3", "socks5_port": 1080, "http_port": 3128, "ipv6": "2a00:1:2:3::1" } ] } } } ``` ### Beli proxy `POST /api/v1/proxy/purchase` Beli proxy di server yang dipilih. Satu permintaan membuat satu pesanan dengan N proxy (hingga 500). Tidak ada pesanan massal — panggil method ini lagi jika membutuhkan lebih banyak. **Request body** | Field | Type | Description | | --- | --- | --- | | `server_id` * | string | ID server dari `GET /proxy/servers`. | | `quantity` * | integer | Berapa banyak proxy yang akan dibeli (1–500). | | `months` * | integer | Periode sewa dalam bulan (1–12). | **Errors** | Code | HTTP | When it fires | | --- | --- | --- | | `INSUFFICIENT_BALANCE` | 402 | Dana tidak mencukupi. | | `NOT_FOUND` | 404 | Server proxy tidak ditemukan atau tidak aktif. | | `VALIDATION_ERROR` | 400 | Isi permintaan tidak valid. | **curl** ```bash curl -X POST https://app.piv.day/api/v1/proxy/purchase \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "server_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "quantity": 5, "months": 1 }' ``` **200 OK** ```json { "success": true, "data": { "order": { "id": "ord-uuid-...", "country": "DE", "quantity": 5, "price_total": 2.50, "status": "active", "expires_at": "2026-02-01T00:00:00Z", "created_at": "2026-01-01T00:00:00Z", "items": [ { "login": "user1", "password": "pass1", "host": "185.1.2.3", "socks5_port": 1080, "http_port": 3128, "ipv6": "2a00:1:2:3::1" }, { "login": "user2", "password": "pass2", "host": "185.1.2.3", "socks5_port": 1080, "http_port": 3128, "ipv6": "2a00:1:2:3::2" } ] } } } ``` ### Perpanjang pesanan `POST /api/v1/proxy/orders/{id}/renew` Perpanjang pesanan proxy aktif selama beberapa bulan. **Request body** | Field | Type | Description | | --- | --- | --- | | `months` * | integer | Bulan yang akan ditambahkan. | **curl** ```bash curl -X POST https://app.piv.day/api/v1/proxy/orders/ord-uuid-.../renew \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "months": 1 }' ``` **200 OK** ```json { "success": true, "data": { "order_id": "ord-uuid-...", "cost": 5.00, "new_expires_at": "2026-03-01T00:00:00Z" } } ``` ### Restore pesanan kedaluwarsa `POST /api/v1/proxy/orders/{id}/restore` Memulihkan pesanan proksi yang kedaluwarsa tanpa beli ulang. Login, password, alamat IPv6, negara, dan binding — semuanya sama. Masa berlaku diperpanjang 1 bulan. Tidak perlu mengkonfigurasi ulang antidetect. **curl** ```bash curl -X POST https://app.piv.day/api/v1/proxy/orders/ord-uuid-.../restore \ -H "Authorization: Bearer YOUR_API_KEY" ``` **200 OK** ```json { "success": true, "data": { "order_id": "ord-uuid-...", "quantity": 10, "total_cost": 5.00, "expires_at": "2026-03-01T00:00:00Z" } } ``` ### Ekspor proxy `GET /api/v1/proxy/orders/{id}/export` Ekspor kredensial proxy pesanan sebagai daftar teks (login:password@host:port). **Query parameters** | Field | Type | Description | | --- | --- | --- | | `format` | string | Format ekspor: `socks5`, `http` atau `both` (default `socks5`). | **curl** ```bash curl "https://app.piv.day/api/v1/proxy/orders/ord-uuid-.../export?format=socks5" \ -H "Authorization: Bearer YOUR_API_KEY" ``` **200 OK** ```json { "success": true, "data": { "content": "user1:pass1@1.2.3.4:1080\nuser2:pass2@1.2.3.4:1080", "filename": "piv-day-proxy-ord-uuid--socks5.txt", "format": "socks5", "count": 2 } } ``` ## Domain Pencarian dan pendaftaran tanpa KYC, Cloudflare dan SSL otomatis, pengelolaan DNS records dan NS server melalui API. ### Cek ketersediaan `GET /api/v1/domains/search` Periksa apakah domain tersedia dan berapa biaya pendaftarannya. **Query parameters** | Field | Type | Description | | --- | --- | --- | | `q` * | string | Nama domain yang ingin dicari, misalnya `mysite.com`. | **curl** ```bash curl "https://app.piv.day/api/v1/domains/search?q=mysite.com" \ -H "Authorization: Bearer YOUR_API_KEY" ``` **200 OK** ```json { "success": true, "data": { "domain": "mysite.com", "available": true, "create_price": 12.50, "renew_price": 12.50, "currency": "USD" } } ``` ### Daftar domain `GET /api/v1/domains` Daftar domain yang sudah Anda daftarkan dengan opsi filter. **Query parameters** | Field | Type | Description | | --- | --- | --- | | `limit` | integer | Jumlah data per halaman. Default 100, maksimum 500. | | `offset` | integer | Offset untuk paginasi. | | `status` | string | Status domain: `active`, `pending`, `expired`. | | `cloudflare` | string | Filter berdasarkan status Cloudflare: `true` atau `false`. | | `auto_renew` | string | Filter berdasarkan auto-renew: `true` atau `false`. | | `search` | string | Cari berdasarkan nama domain. | **curl** ```bash curl "https://app.piv.day/api/v1/domains?status=active&limit=20" \ -H "Authorization: Bearer YOUR_API_KEY" ``` **200 OK** ```json { "success": true, "data": { "domains": [ { "id": "dom-uuid-...", "domain_name": "mysite.com", "status": "active", "registered_at": "2026-01-01T00:00:00Z", "expires_at": "2027-01-01T00:00:00Z", "auto_renew": true, "cloudflare_enabled": true, "cloudflare_status": "active", "ssl_type": "lets_encrypt", "ssl_status": "active", "ssl_mode": "full", "ssl_expires_at": "2026-04-01T00:00:00Z", "created_at": "2026-01-01T00:00:00Z", "updated_at": "2026-01-01T00:00:00Z" } ], "pagination": { "total": 1, "limit": 20, "offset": 0 } } } ``` ### Daftarkan domain `POST /api/v1/domains` Mendaftarkan domain baru. Permintaan bersifat asinkron — mengembalikan `queue_id` untuk pelacakan. Cloudflare AKTIF: jangan kirimkan `nameservers`; opsional dapat mengirimkan `dns_records` dan `ssl_mode`. Cloudflare NONAKTIF: jangan kirimkan `dns_records` atau `ssl_mode`; `nameservers` wajib diisi (minimal 2). Kami tidak pernah mengungkapkan nameserver Cloudflare. **Request body** | Field | Type | Description | | --- | --- | --- | | `domain` * | string | Nama domain yang ingin didaftarkan, misalnya `mysite.com`. | | `period` * | integer | Periode pendaftaran dalam tahun (1–10). | | `cloudflare` * | boolean | Hubungkan domain ke Cloudflare secara otomatis. | | `auto_renew` * | boolean | Aktifkan perpanjangan otomatis. | | `ssl_mode` | string | `flexible` \| `full` \| `strict`. Hanya dengan `cloudflare: true`. | | `nameservers` | string[] | Wajib diisi dengan `cloudflare: false` (≥2 NS). Dilarang dengan `cloudflare: true`. | | `dns_records` | object[] | DNS records awal. Hanya dengan `cloudflare: true`. | **Errors** | Code | HTTP | When it fires | | --- | --- | --- | | `DOMAIN_NOT_AVAILABLE` | 400 | Domain tidak tersedia untuk didaftarkan. | | `INSUFFICIENT_BALANCE` | 402 | Saldo tidak mencukupi. | | `VALIDATION_ERROR` | 400 | Body permintaan tidak valid. | **Cloudflare AKTIF** ```bash curl -X POST https://app.piv.day/api/v1/domains \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "domain": "mysite.com", "period": 1, "cloudflare": true, "auto_renew": true, "ssl_mode": "full", "dns_records": [ { "type": "A", "name": "@", "content": "1.2.3.4", "proxied": true } ] }' ``` **Cloudflare NONAKTIF — NS sendiri** ```bash curl -X POST https://app.piv.day/api/v1/domains \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "domain": "mysite.com", "period": 1, "cloudflare": false, "auto_renew": false, "nameservers": ["ns1.myhost.com", "ns2.myhost.com"] }' ``` **202 Accepted** ```json { "success": true, "data": { "queue_id": "que-uuid-...", "domain": { "id": "dom-uuid-...", "domain_name": "mysite.com", "status": "purchasing", "period": 1, "cloudflare_enabled": true, "auto_renew": true, "ssl_mode": "full", "created_at": "2026-01-01T00:00:00Z" } } } ``` ### Status antrian pendaftaran `GET /api/v1/domains/queue/{id}` Periksa status entri antrian pendaftaran atau perpanjangan domain. Pada status `completed`, respons sudah memuat kartu domain lengkap — tidak perlu panggilan terpisah ke `/domains/{id}`. **curl** ```bash curl https://app.piv.day/api/v1/domains/queue/que-uuid-... \ -H "Authorization: Bearer YOUR_API_KEY" ``` **pending / processing** ```json { "success": true, "data": { "queue_id": "que-uuid-...", "domain": "mysite.com", "status": "pending" } } ``` **completed — kartu lengkap** ```json { "success": true, "data": { "queue_id": "que-uuid-...", "status": "completed", "domain": { "id": "dom-uuid-...", "domain_name": "mysite.com", "status": "active", "registered_at": "2026-01-01T12:00:00Z", "expires_at": "2027-01-01T12:00:00Z", "auto_renew": true, "cloudflare_enabled": true, "cloudflare_status": "active", "ssl_type": "lets_encrypt", "ssl_status": "active", "ssl_mode": "full", "ssl_expires_at": "2026-04-01T00:00:00Z", "created_at": "2026-01-01T00:00:00Z", "updated_at": "2026-01-01T12:00:00Z", "dns_records": [ { "name": "@", "type": "A", "content": "1.2.3.4", "ttl": 1, "priority": null, "proxied": true } ] } } } ``` ### Ambil satu domain `GET /api/v1/domains/{id}` Dapatkan informasi lengkap tentang domain yang sudah terdaftar. Field `nameservers` hanya ada jika `cloudflare_enabled: false`. **curl** ```bash curl https://app.piv.day/api/v1/domains/dom-uuid-... \ -H "Authorization: Bearer YOUR_API_KEY" ``` **200 OK** ```json { "success": true, "data": { "domain": { "id": "dom-uuid-...", "domain_name": "mysite.com", "status": "active", "registered_at": "2026-01-01T12:00:00Z", "expires_at": "2027-01-01T12:00:00Z", "auto_renew": true, "cloudflare_enabled": true, "cloudflare_status": "active", "ssl_type": "lets_encrypt", "ssl_status": "active", "ssl_mode": "full", "ssl_expires_at": "2026-04-01T00:00:00Z", "created_at": "2026-01-01T00:00:00Z", "updated_at": "2026-01-01T12:00:00Z", "dns_records": [ { "name": "@", "type": "A", "content": "1.2.3.4", "ttl": 1, "priority": null, "proxied": true }, { "name": "www", "type": "CNAME", "content": "mysite.com", "ttl": 1, "priority": null, "proxied": true } ] } } } ``` ### Perpanjang domain `POST /api/v1/domains/{id}/renew` Perpanjang pendaftaran domain. Mengembalikan `queue_id` untuk pelacakan. **Request body** | Field | Type | Description | | --- | --- | --- | | `period` * | integer | Jumlah tahun untuk diperpanjang. | **curl** ```bash curl -X POST https://app.piv.day/api/v1/domains/dom-uuid-.../renew \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "period": 1 }' ``` **202 Accepted** ```json { "success": true, "data": { "queue_id": "que-uuid-...", "domain_id": "dom-uuid-...", "expires_at": "2027-01-01T12:00:00Z" } } ``` ### Toggle perpanjangan otomatis `POST /api/v1/domains/{id}/auto-renew` Aktifkan atau nonaktifkan perpanjangan otomatis domain. **Request body** | Field | Type | Description | | --- | --- | --- | | `auto_renew` * | boolean | Nilai flag baru. | **curl** ```bash curl -X POST https://app.piv.day/api/v1/domains/dom-uuid-.../auto-renew \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "auto_renew": true }' ``` **200 OK** ```json { "success": true, "data": { "id": "dom-uuid-...", "auto_renew": true } } ``` ### DNS records domain `GET /api/v1/domains/{id}/dns` Daftar DNS records domain (via Cloudflare). **curl** ```bash curl https://app.piv.day/api/v1/domains/dom-uuid-.../dns \ -H "Authorization: Bearer YOUR_API_KEY" ``` **200 OK** ```json { "success": true, "data": { "records": [ { "id": "rec-uuid-...", "type": "A", "name": "@", "content": "1.2.3.4", "ttl": 1, "priority": null, "proxied": true } ] } } ``` ### Tambah DNS record `POST /api/v1/domains/{id}/dns` Buat DNS record baru. **Request body** | Field | Type | Description | | --- | --- | --- | | `type` * | string | Tipe record: `A`, `AAAA`, `CNAME`, `MX`, `TXT`, dll. | | `name` * | string | Nama record, misalnya `@` atau `subdomain`. | | `content` * | string | Nilai record. | | `ttl` | integer | TTL dalam detik (`1` = otomatis). | | `proxied` | boolean | Proxy melalui Cloudflare. | **curl** ```bash curl -X POST https://app.piv.day/api/v1/domains/dom-uuid-.../dns \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "type": "A", "name": "@", "content": "1.2.3.4", "ttl": 1, "proxied": true }' ``` **201 Created** ```json { "success": true, "data": { "record": { "id": "rec-uuid-...", "type": "A", "name": "@", "content": "1.2.3.4", "ttl": 1, "priority": null, "proxied": true } } } ``` ### Perbarui DNS record `PUT /api/v1/domains/{id}/dns/{recordId}` Perbarui DNS record yang sudah ada berdasarkan ID. Hanya field yang dikirimkan yang akan ditimpa. **curl** ```bash curl -X PUT https://app.piv.day/api/v1/domains/dom-uuid-.../dns/rec-uuid-... \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "content": "5.6.7.8" }' ``` ### Hapus DNS record `DELETE /api/v1/domains/{id}/dns/{recordId}` Hapus DNS record berdasarkan ID. **curl** ```bash curl -X DELETE https://app.piv.day/api/v1/domains/dom-uuid-.../dns/rec-uuid-... \ -H "Authorization: Bearer YOUR_API_KEY" ``` ### Aktifkan Cloudflare `POST /api/v1/domains/{id}/cloudflare` Aktifkan Cloudflare untuk domain. Kami tidak mengembalikan nameserver Cloudflare — delegasi dikonfigurasi dari sisi kami. Menonaktifkan Cloudflare melalui endpoint ini tidak didukung. **curl** ```bash curl -X POST https://app.piv.day/api/v1/domains/dom-uuid-.../cloudflare \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "enabled": true }' ``` **200 OK** ```json { "success": true, "data": { "domain_id": "dom-uuid-...", "ssl_mode": "flexible" } } ``` ### Atur nameserver `POST /api/v1/domains/{id}/ns-servers` Atur nameserver kustom untuk domain. **curl** ```bash curl -X POST https://app.piv.day/api/v1/domains/dom-uuid-.../ns-servers \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "nameservers": ["ns1.example.com", "ns2.example.com"] }' ``` **200 OK** ```json { "success": true, "data": { "nameservers": [ { "nameserver": "ns1.example.com", "order_index": 1 }, { "nameserver": "ns2.example.com", "order_index": 2 } ] } } ``` ## Whites Generasi white-page berdasarkan niche dan tier. Setiap situs bersifat unik. Ganti domain dan kontak tanpa regenerasi. ### Daftar tier `GET /api/v1/whites/tiers` Tier generasi yang tersedia beserta harga. `price` adalah harga per generasi yang sudah disesuaikan dengan akun Anda (langganan diterapkan), satu angka. `quality: "premium"` lebih mahal (dihitung saat membuat). Blog hanya di `v2_tier3`: 3 artikel pertama sudah termasuk, setiap artikel tambahan (hingga 20) dikenai biaya `extra_article_price`. **curl** ```bash curl https://app.piv.day/api/v1/whites/tiers \ -H "Authorization: Bearer YOUR_API_KEY" ``` **200 OK** ```json { "success": true, "data": { "tiers": [ { "tier_key": "v2_tier1", "name": "Landing", "generator_version": "v2", "min_articles": 0, "max_articles": 0, "price": 3.00, "extra_article_price": null }, { "tier_key": "v2_tier2", "name": "Multi-page", "generator_version": "v2", "min_articles": 0, "max_articles": 0, "price": 6.00, "extra_article_price": null }, { "tier_key": "v2_tier3", "name": "Full + Blog", "generator_version": "v2", "min_articles": 3, "max_articles": 20, "price": 10.00, "extra_article_price": 1.50 } ] } } ``` ### Daftar whites `GET /api/v1/whites` Daftar job generasi Anda dengan fitur filter. **Query parameters** | Field | Type | Description | | --- | --- | --- | | `limit` | integer | Ukuran halaman. Default 100, maks 500. | | `offset` | integer | Offset paginasi. | | `status` | string | `queued` \| `processing` \| `done` \| `failed`. | | `tier_key` | string | `v2_tier1` \| `v2_tier2` \| `v2_tier3`. | **curl** ```bash curl "https://app.piv.day/api/v1/whites?status=done&limit=20" \ -H "Authorization: Bearer YOUR_API_KEY" ``` **200 OK** ```json { "success": true, "data": { "whites": [ { "id": "job-uuid-...", "name": "My White", "status": 10, "tier_key": "v2_tier3", "quality": "standard", "niche": "IT Consulting", "country": "DE", "language": "de", "domain": "mysite.com", "result_url": null, "created_at": "2026-01-01T00:00:00Z" } ], "pagination": { "total": 1, "limit": 20, "offset": 0 } } } ``` ### Mulai generasi `POST /api/v1/whites` Tambahkan job generasi white-page ke antrean. Pembayaran langsung dipotong. Status akhir dikirim melalui webhook `white.completed` / `white.failed` atau dapat dicek via `GET /whites/{id}`. **Request body** | Field | Type | Description | | --- | --- | --- | | `name` * | string | Nama job (2–20 karakter). | | `tier_key` * | string | `v2_tier1` \| `v2_tier2` \| `v2_tier3`. | | `niche` * | string | Niche situs (hingga 25 karakter). | | `country` * | string | Kode negara (ISO 3166-1 alpha-2). | | `language` * | string | Bahasa utama situs (ISO 639-1). | | `quality` | string | `standard` \| `premium` (default `standard`). | | `languages` | string[] | Daftar bahasa. Bahasa pertama sudah termasuk dalam harga; setiap bahasa tambahan dikenai biaya extra. | | `domain` | string | Domain lengkap (contoh: `example.com`). Tanpa auto-completion. | | `email` | string | Email lengkap (contoh: `info@example.com`). Tanpa auto-completion. | | `phone` | string | Telepon kontak. | | `address` | string | Alamat perusahaan. | | `legal_name` | string | Nama legal. | | `style_hint` | string | Gaya desain (Random, Minimalis, Korporat, dll.). | | `keywords` | string[] | Kata kunci SEO. | | `banned_words` | string[] | Kata-kata yang dilarang dalam konten. | | `blog_count` | integer | Jumlah artikel blog 3–20. Hanya untuk `v2_tier3`. Artikel lebih dari 3 dikenai biaya tambahan. | | `contacts_mode` | string | `same` \| `template`. | | `contacts_template` | string | Template halaman kontak (saat `contacts_mode=template`). | | `facebook` | string | URL lengkap halaman Facebook. | | `instagram` | string | URL lengkap profil Instagram. | | `linkedin` | string | URL lengkap profil LinkedIn. | | `youtube` | string | URL lengkap channel YouTube. | | `tiktok` | string | URL lengkap profil TikTok. | **Errors** | Code | HTTP | When it fires | | --- | --- | --- | | `INSUFFICIENT_BALANCE` | 402 | Saldo tidak mencukupi. | | `INVALID_TIER` | 400 | Tidak ada tier dengan key tersebut. | | `VALIDATION_ERROR` | 400 | Body request tidak valid. | **curl** ```bash curl -X POST https://app.piv.day/api/v1/whites \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Tech Blog DE", "tier_key": "v2_tier3", "niche": "IT Consulting", "country": "DE", "language": "de", "quality": "premium", "languages": ["de", "en"], "domain": "techblog-de.com", "email": "info@techblog-de.com", "phone": "+49 30 123456", "address": "Berliner Str. 1, 10115 Berlin", "legal_name": "TechBlog GmbH", "style_hint": "Корпоративный", "keywords": ["IT", "consulting", "cloud"], "banned_words": ["cheap", "free"], "blog_count": 8, "contacts_mode": "same", "facebook": "https://facebook.com/techblogde", "instagram": "https://instagram.com/techblogde", "linkedin": "https://linkedin.com/company/techblogde" }' ``` **200 OK** ```json { "success": true, "data": { "status": "queued", "white": { "id": "job-uuid-...", "name": "Tech Blog DE", "status": 0, "tier_key": "v2_tier3", "quality": "premium", "niche": "IT Consulting", "country": "DE", "language": "de", "domain": "techblog-de.com", "result_url": null, "created_at": "2026-01-01T00:00:00Z" } } } ``` ### Ambil satu white `GET /api/v1/whites/{id}` Ambil status terkini dari job generasi. **curl** ```bash curl https://app.piv.day/api/v1/whites/job-uuid-... \ -H "Authorization: Bearer YOUR_API_KEY" ``` **200 OK** ```json { "success": true, "data": { "white": { "id": "job-uuid-...", "name": "Tech Blog DE", "status": 10, "tier_key": "v2_tier3", "quality": "premium", "niche": "IT Consulting", "country": "DE", "language": "de", "domain": "techblog-de.com", "result_url": null, "created_at": "2026-01-01T00:00:00Z" } } } ``` ### Unduh arsip `GET /api/v1/whites/{id}/download` Dapatkan link bertanda tangan berumur pendek ke arsip white-page yang sudah selesai. Link berlaku selama ~5 menit (lihat `expires_at`). Jika sudah kedaluwarsa — panggil `/download` lagi, kami akan menerbitkan yang baru. Jika white page belum digenerate, mengembalikan `409 NOT_READY`. **Query parameters** | Field | Type | Description | | --- | --- | --- | | `format` | string | Format arsip. Default `php`. | **Errors** | Code | HTTP | When it fires | | --- | --- | --- | | `NOT_READY` | 409 | White page masih dalam proses generasi — coba lagi setelah `white.completed`. | **curl** ```bash curl "https://app.piv.day/api/v1/whites/job-uuid-.../download?format=php" \ -H "Authorization: Bearer YOUR_API_KEY" ``` **200 OK** ```json { "success": true, "data": { "url": "https://strg.piv.day/download//?format=php&token=&filename=.zip", "filename": "example.com_2026-05-28_DE_en.zip", "format": "php", "expires_at": "2026-05-28T14:46:00Z" } } ``` ### Ganti domain dan kontak `POST /api/v1/whites/{id}/config` Perbarui data kontak perusahaan di white-page tanpa regenerasi. **curl** ```bash curl -X POST https://app.piv.day/api/v1/whites/job-uuid-.../config \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "company": "My Brand", "domain": "newdomain.com", "email": "info@newdomain.com", "phone": "+49 30 123456", "address": "Berliner Str. 1, Berlin", "legal": "My Brand GmbH" }' ``` ## Webhooks Kami mengirimkan POST biasa dengan body JSON ke URL Anda. Formatnya sama untuk semua event: `event_type`, `timestamp`, dan blok `data`. Server Anda harus merespons dengan 2xx apa pun dalam 5 detik. ``` POST Content-Type: application/json User-Agent: piv.day-webhook/1.0 { "event_type": "", "timestamp": "2026-05-22T12:34:56Z", "data": { ... } } ``` **Retries.** Pada non-2xx atau timeout — hingga 3 percobaan ulang dengan backoff 1s / 2s / 4s. Riwayat pengiriman lengkap tersedia di halaman kunci API di dashboard. Jika ketiganya gagal, event ditandai sebagai failed dan dapat dikirim ulang secara manual. **Security.** Gunakan endpoint HTTPS. Setiap permintaan datang dengan header `User-Agent: piv.day-webhook/1.0`. URL webhook dikonfigurasi di profil kunci API. ### All events | Event | When it fires | | --- | --- | | `sms.received` | Pengirim tepercaya baru saja mengirim SMS ke salah satu nomor Anda. | | `sms.status_updated` | SMS keluar mengubah status — terkirim, gagal, dll. | | `number.restore_completed` | Batch Restore selesai — ringkasan akhir tiba di sini. | | `verify.completed` | Verifikasi akun Google selesai dengan sukses. | | `verify.failed` | Sesuatu berjalan salah — Google tidak menerimanya. | | `proxy.expires_soon` | Sekitar tiga hari tersisa pada pesanan proxy. | | `domain.registered` | Pesanan registrasi berhasil selesai — domain sudah aktif. | | `domain.failed` | Pesanan tidak berhasil — penyebab umum: nama baru saja diambil orang lain. | | `domain.expires_soon` | Sekitar satu minggu tersisa sebelum domain kedaluwarsa. | | `white.completed` | Tugas pembuatan White selesai dengan sukses. | | `white.failed` | Tugas gagal — dana dikembalikan ke saldo. | ### SMS masuk ke nomor Anda **`sms.received`** Paling sering ini adalah kode verifikasi dari jaringan iklan. Payload menyertakan teks mentah dan kode yang terdeteksi otomatis (jika ada) sehingga Anda bisa langsung meneruskannya ke workflow tanpa parsing. Pesan dari pengirim spam yang dikenal tidak diteruskan. ```json { "event_type": "sms.received", "timestamp": "2026-05-22T12:34:56Z", "data": { "piv_num_id": "vzPA1-kHKSg-EAL7e-Jqd3o", "text": "Your verification code is 123456", "code": "123456", "country": "SE", "received_at": "2026-05-22T12:34:56Z" } } ``` ### Status SMS keluar berubah **`sms.status_updated`** Berguna saat Anda mengirim konfirmasi dari nomor Anda sendiri dan perlu tahu apakah benar-benar terkirim. Jika statusnya failed, kode error dan pesan dari operator ada di payload. ```json { "event_type": "sms.status_updated", "timestamp": "2026-05-22T12:34:56Z", "data": { "piv_num_id": "vzPA1-kHKSg-EAL7e-Jqd3o", "message_id": "42", "old_status": "sent", "new_status": "delivered", "error_code": null, "error_message": null } } ``` ### Pemulihan nomor selesai **`number.restore_completed`** Berisi dua daftar — nomor mana yang berhasil dipulihkan dan mana yang tidak. Jumlah yang dikembalikan untuk yang gagal juga ada di payload. Berguna untuk skrip yang melakukan retry secara cerdas. ```json { "event_type": "number.restore_completed", "timestamp": "2026-05-22T12:34:56Z", "data": { "restored": [ { "piv_num_id": "vzPA1-kHKSg-EAL7e-Jqd3o", "phone_number": "+46764794425", "country": "SE" } ], "failed": [ { "piv_num_id": "abc12-defgh-ijklm-nopqr", "phone_number": "+46123456789", "country": "SE", "refunded": 7.50 } ], "total_restored": 1, "total_failed": 1, "total_refunded": 7.50 } } ``` ### Verifikasi Google QR berhasil **`verify.completed`** Jika SMS dengan kode tiba selama proses, itu sudah ada di sini — tidak perlu fetch tambahan. captured_phone dan captured_message berisi apa yang dikirim Google. ```json { "event_type": "verify.completed", "timestamp": "2026-05-22T12:34:56Z", "data": { "task_id": 12, "piv_num_id": "vzPA1-kHKSg-EAL7e-Jqd3o", "status": "sms_sent", "captured_phone": "+14155551234", "captured_message": "Your Google verification code is 123456", "sms_message_id": 42, "sms_status": "queued" } } ``` ### Verifikasi Google QR gagal **`verify.failed`** error_code memberitahu Anda apa yang terjadi — timeout, penolakan, URL tidak valid. Verifikasi yang gagal dikembalikan ke saldo secara otomatis. ```json { "event_type": "verify.failed", "timestamp": "2026-05-22T12:34:56Z", "data": { "task_id": 12, "piv_num_id": "vzPA1-kHKSg-EAL7e-Jqd3o", "status": "failed", "error_code": "VERIFY_TIMEOUT", "error_message": "Verification timed out" } } ``` ### Proxy segera kedaluwarsa **`proxy.expires_soon`** Dirancang untuk yang tidak memperbarui otomatis: Anda melihatnya lebih awal dan memutuskan — perpanjang atau akhiri kampanye. Hubungkan ke POST /proxy/orders/{id}/renew untuk perpanjangan otomatis penuh. ```json { "event_type": "proxy.expires_soon", "timestamp": "2026-05-22T12:34:56Z", "data": { "order_id": "ord-uuid-...", "country": "DE", "quantity": 10, "expires_at": "2026-05-25T00:00:00Z" } } ``` ### Domain terdaftar **`domain.registered`** Jika Anda meminta Cloudflare dan SSL saat pembelian, keduanya sudah aktif — cloudflare_enabled mencerminkan statusnya. Anda bisa langsung menambahkan catatan DNS atau men-deploy situs. ```json { "event_type": "domain.registered", "timestamp": "2026-05-22T12:34:56Z", "data": { "domain_id": "dom-uuid-...", "domain_name": "mysite.com", "registered_at": "2026-05-22T12:34:56Z", "expires_at": "2027-05-22T12:34:56Z", "cloudflare_enabled": true } } ``` ### Pendaftaran domain gagal **`domain.failed`** Kolom error berisi alasan yang dapat dibaca manusia. Biaya dikembalikan ke saldo. Pilih nama lain dan coba lagi. ```json { "event_type": "domain.failed", "timestamp": "2026-05-22T12:34:56Z", "data": { "domain_id": "dom-uuid-...", "domain_name": "mysite.com", "error": "Domain is no longer available" } } ``` ### Domain segera kedaluwarsa **`domain.expires_soon`** Berguna saat perpanjangan otomatis dinonaktifkan: Anda punya waktu untuk memperpanjang secara manual sebelum domain masuk fase redemption. Flag auto_renew memberi tahu apakah intervensi diperlukan. ```json { "event_type": "domain.expires_soon", "timestamp": "2026-05-22T12:34:56Z", "data": { "domain_id": "dom-uuid-...", "domain_name": "mysite.com", "expires_at": "2026-05-29T00:00:00Z", "auto_renew": false } } ``` ### White telah dibuat **`white.completed`** Arsip tersedia melalui GET /whites/{id}/download. Jika White memiliki domain yang ditetapkan, sitemap dan kontak sudah terkonfigurasi — siap untuk di-deploy. ```json { "event_type": "white.completed", "timestamp": "2026-05-22T12:34:56Z", "data": { "job_id": "job-uuid-...", "name": "My White", "tier_key": "t1", "country": "DE" } } ``` ### Pembuatan White gagal **`white.failed`** Kolom error menjelaskan alasannya. Mulai tugas baru melalui POST /whites — tanpa kehilangan uang. ```json { "event_type": "white.failed", "timestamp": "2026-05-22T12:34:56Z", "data": { "job_id": "job-uuid-...", "name": "My White", "error": "Generation failed" } } ``` ## Error codes Semua error dikembalikan dalam format yang sama: HTTP status + field `error.code` + pesan yang dapat dibaca manusia di `error.message`. ```json { "success": false, "error": { "code": "INSUFFICIENT_BALANCE", "message": "Not enough balance: required $5.00, available $1.20" } } ``` | Code | HTTP | When it fires | | --- | --- | --- | | `UNAUTHORIZED` | 401 | Key tidak ada, sudah kedaluwarsa, atau telah dicabut. | | `INSUFFICIENT_PERMISSIONS` | 403 | Key tidak memiliki scope yang diperlukan untuk tindakan ini. | | `PERMISSION_DENIED` | 403 | Akses level akun tidak mengizinkan tindakan ini (mis. fitur dinonaktifkan). | | `VALIDATION_ERROR` | 400 | Body request tidak valid. Pesan menjelaskan field mana yang bermasalah dan alasannya. | | `NUMBER_NOT_FOUND` | 404 | Nomor tidak ada atau tidak milik akun ini. | | `NUMBER_EXPIRED` | 403 | Nomor telah kedaluwarsa — gunakan Restore (dalam 7 hari) atau beli nomor baru. | | `NUMBER_NOT_ACTIVE` | 400 | Nomor berada dalam status yang tidak mengizinkan operasi ini. | | `INSUFFICIENT_BALANCE` | 402 | Dana tidak cukup untuk operasi ini. | | `INVALID_MESSAGE_FORMAT` | 400 | Isi SMS terlalu panjang atau mengandung karakter yang tidak diizinkan. | | `COUNTRY_NOT_AVAILABLE` | 400 | Negara tidak tersedia untuk pembelian atau perpanjangan. | | `NO_NUMBERS_AVAILABLE` | 400 | Tidak ada nomor yang tersedia di negara yang dipilih saat ini. | | `NO_RESTORABLE_NUMBERS` | 404 | Tidak ada nomor yang diberikan yang dapat dipulihkan lagi. | | `RATE_LIMITED` | 429 | Rate limit terlampaui. Tunggu waktu yang ditentukan di header `Retry-After`. | | `INTERNAL_ERROR` | 500 | Ada yang salah di pihak kami. Jika terus terjadi — hubungi support. |