Konvensi & Format
Aturan request/response, rate limit, format nomor telepon, pagination, dan inkonsistensi naming yang perlu kamu ketahui.
Halaman ini merangkum aturan umum yang berlaku di semua endpoint API Chatera.
Format request
Semua endpoint menerima JSON. Setiap request wajib menyertakan dua header:
Authorization: Bearer chatera_sk_xxxxx
Content-Type: application/jsonBody request (untuk method POST / PATCH) selalu berupa JSON yang
valid. Field yang tidak diketahui akan diabaikan tanpa error.
Format response
Setiap response API memakai envelope yang sama. Tidak ada response
"telanjang" — selalu ada success flag.
Response sukses
{
"success": true,
"data": {
"id": "...",
"name": "..."
}
}Untuk endpoint yang mengembalikan list (GET dengan pagination), struktur tambahan:
{
"success": true,
"data": [
{ "id": "...", "name": "..." }
],
"meta": {
"page": 1,
"per_page": 20,
"total": 142,
"has_more": true
}
}Response error
{
"success": false,
"error": {
"code": "VALIDATION_INVALID_PHONE",
"message": "Format nomor telepon tidak valid",
"details": {
"field": "to",
"hint": "Gunakan format kode negara + nomor (contoh: 628123456789)"
}
}
}Field error.details opsional — beberapa error tidak menyertakannya.
Kode HTTP mengikuti makna umum (400 validasi, 401 auth, 404
tidak ditemukan, 409 konflik, 429 rate limit, 5xx server).
Inkonsistensi naming yang perlu kamu tahu
Field di response API Chatera mencampur camelCase dan snake_case tergantung endpoint. Ini history dari evolusi API — akan distandarkan di v2. Sementara itu, perhatikan polanya:
| Domain | Convention | Contoh |
|---|---|---|
| Pesan WhatsApp | camelCase | messageId, whatsappMessageId, channelId, contentType |
| Kontak | snake_case | custom_fields, created_at, updated_at |
| Webhook payload | camelCase di data, snake_case di top-level | organization_id (top), messageId (data) |
| Pagination meta | snake_case | per_page, has_more |
Tip integrator
Generate type binding (mis. TypeScript interface) per-endpoint —
jangan berasumsi convention global. Atau pakai library transformasi
case di sisi client kamu (mis. humps untuk JavaScript).
Rate limit
Setiap API key memiliki batasan request:
| Batas | Default |
|---|---|
| Per menit | 60 request |
| Per hari | 10.000 request |
Setiap response menyertakan tiga header untuk memantau kuota:
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1708123456Jika kamu melebihi limit, response berikutnya akan mengembalikan
status 429 dengan body:
{
"success": false,
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Batas permintaan tercapai. Silakan coba lagi nanti."
}
}Strategi mengatasi rate limit
- Pantau
X-RateLimit-Remainingsebelum mengirim batch besar. - Implementasikan exponential backoff: tunggu 1s, 2s, 4s, 8s
antar retry saat mendapat
429. - Untuk volume tinggi (broadcast, sync masal), buffer request ke queue dengan worker yang menyebar pengiriman sepanjang waktu.
Butuh limit lebih tinggi?
Kalau bisnis kamu butuh limit lebih tinggi (mis. broadcast jutaan pesan, sync ratusan ribu kontak), hubungi tim sales — limit per-customer dapat di-tune sesuai kontrak.
Format nomor telepon (E.164)
Semua field nomor telepon di API menggunakan format E.164: kode negara + nomor lokal tanpa spasi atau tanda hubung.
| Input | Diterima? | Disimpan sebagai |
|---|---|---|
+628123456789 | ✓ | +628123456789 |
628123456789 | ✓ (otomatis ditambah +) | +628123456789 |
+60112345678 (Malaysia) | ✓ | +60112345678 |
60112345678 (Malaysia) | ✓ | +60112345678 |
08123456789 | ✗ — format lokal, tidak ada kode negara | — |
+62 812-3456-789 | ✗ — mengandung spasi/strip | — |
Jika kamu menyimpan nomor pelanggan di sistem internal dengan format
lokal (08...), normalisasi dulu sebelum dikirim ke API:
function toE164Indonesia(local) {
// "08123456789" → "+628123456789"
if (local.startsWith('0')) return '+62' + local.slice(1);
return local;
}Error yang muncul kalau format salah:
{
"success": false,
"error": {
"code": "VALIDATION_INVALID_PHONE",
"message": "Format nomor telepon tidak valid",
"details": {
"field": "to",
"hint": "Gunakan format kode negara + nomor (contoh: 628123456789)"
}
}
}Pagination
Endpoint list (mis. GET /v1/contacts) selalu mendukung pagination
via query string:
| Parameter | Default | Maks |
|---|---|---|
page | 1 | — |
per_page | 20 | 100 |
Response menyertakan meta.has_more (boolean). Loop pagination yang
aman:
let page = 1;
const all = [];
while (true) {
const res = await fetch(
`https://api.chatera.id/v1/contacts?page=${page}&per_page=100`,
{ headers: { Authorization: 'Bearer chatera_sk_xxx' } }
).then(r => r.json());
all.push(...res.data);
if (!res.meta.has_more) break;
page++;
}Idempotensi
Saat ini API belum mendukung header Idempotency-Key. Untuk
operasi kritikal (mis. mengirim pesan dua kali tidak boleh terjadi),
implementasikan deduplication di sisi client:
- Generate UUID di client per "logical operation".
- Simpan UUID + status di database client kamu.
- Cek status sebelum retry — jangan kirim ulang kalau sudah
sent.
Dukungan idempotensi native akan datang di iterasi berikutnya.