Pengantar
API Hootmix memungkinkan kamu membuat, mengubah, dan mengukur link pendek dari kode kamu sendiri. Ini adalah REST API berformat JSON, dan setiap request milik satu workspace.
https://www.hootmix.com/api/v1Versi menjadi bagian dari path. Satu versi tidak pernah berubah secara breaking. Perilaku baru dirilis di versi baru, dan versi lama tetap tersedia sampai ditandai usang.
- Autentikasi dengan API key workspace di header Authorization.
- Semua response berupa JSON, kecuali response 204 yang tidak punya isi.
- Request dan response memakai nama field camelCase dan tanggal ISO 8601.
Mulai cepat
Buat key, lalu pendekkan link pertama kamu dalam satu request. Ganti key dengan milikmu.
curl -X POST "https://www.hootmix.com/api/v1/links" \
-H "Authorization: Bearer $HOOTMIX_API_KEY" \
-H "Content-Type: application/json" \
-d '{"target":{"type":"REDIRECT","url":"https://example.com/hello"},"slug":"hello"}'Response-nya adalah link. Bagikan url-nya, dan baca kliknya dengan Ambil analitik link.
{
"id": "6650f1c2a1b2c3d4e5f60718",
"slug": "hello",
"url": "https://hoot.mx/hello",
"status": "active"
}Autentikasi
Buat key di workspace kamu pada menu API key. Setiap key milik satu workspace dan hanya melihat data workspace itu. Pilih scope yang dibutuhkan dan tanggal kedaluwarsa.
Kirim key sebagai bearer token di setiap request:
Authorization: Bearer hmx_live_ab12cd34_<secret>Key lengkap hanya ditampilkan sekali, saat dibuat. Hootmix menyimpan sidik jari, bukan key-nya, jadi key yang hilang tidak bisa dipulihkan. Buat yang baru dan cabut yang lama.
- links.read: baca link.
- links.write: buat dan ubah link.
- links.delete: nonaktifkan dan hapus link.
- analytics.read: baca statistik link.
- events.read: baca event klik dan tag.
- events.write: beri tag pada event klik.
- folders.read: lihat daftar folder.
- domains.read: lihat daftar domain.
Sebuah key hanya bisa memiliki scope yang dimiliki pembuatnya di workspace. Key bisa memiliki tanggal kedaluwarsa, dan key yang dicabut atau kedaluwarsa mengembalikan 401.
Memberi tag pada event
Tag memberi label pada klik tunggal, bukan link. Pakai untuk mencatat apa yang terjadi setelah klik, seperti converted, vip atau refund, lalu lihat klik itu di analitik.
- Pengunjung mengeklik link pendek. Hootmix mencatat event klik dan, jika kamu memakai webhook, mengirim request link.clicked ke server kamu.
- Request berisi id event di data.event.id.
- Server kamu memanggil PUT /v1/events/{id}/tags dengan tag yang ingin ditetapkan.
- Tag muncul di bawah klik pada kunjungan terbaru link, di halaman Tag, dan di analitik. Filter berdasarkan tag dengan parameter tag.
{
"id": "9d2f6c1e-...",
"event": "link.clicked",
"createdAt": "2026-10-19T08:31:12.000Z",
"data": {
"link": { "id": "6650f1c2a1b2c3d4e5f60718", "slug": "spring-sale" },
"event": { "id": "b1f2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d", "countryCode": "ID", "device": "Mobile" }
}
}curl -X PUT "https://www.hootmix.com/api/v1/events/b1f2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d/tags" \
-H "Authorization: Bearer $HOOTMIX_API_KEY" \
-H "Content-Type: application/json" \
-d '{"tags":["converted"]}'Kamu juga bisa memberi tag secara manual: buka link, masuk ke Kunjungan terbaru, lalu pakai tombol tag di bawah klik. Buat, ganti nama, dan hapus nama tag di halaman Tag.
Batas request
Setiap API key dapat melakukan sejumlah request dalam satu jendela waktu. Batas ditetapkan oleh administrator Hootmix dan berlaku sama untuk semua key. Setiap response memberi tahu posisi kamu:
- X-RateLimit-Limit: request yang diizinkan per jendela.
- X-RateLimit-Remaining: sisa request di jendela ini.
- X-RateLimit-Reset: detik sampai jendela di-reset.
Jika habis, API menjawab 429 dengan header Retry-After berisi detik yang harus ditunggu. Tunggu lalu coba lagi.
Error
Error memakai kode status HTTP dan body JSON dengan code yang stabil serta pesan yang mudah dibaca. Cocokkan berdasarkan code, bukan pesannya.
{
"error": {
"code": "not_found",
"message": "Link not found"
}
}- invalid_request: ada field yang hilang atau salah format.
- folder_ambiguous: kamu mengirim folderId dan folderName sekaligus.
- invalid_api_key: key hilang, salah, kedaluwarsa, atau dicabut.
- insufficient_scope: key tidak punya scope yang dibutuhkan endpoint ini.
- not_found / folder_not_found: link atau folder tidak ada di workspace ini.
- folder_name_ambiguous / slug_taken: request bentrok dengan data yang ada.
- unprocessable: batas paket atau aturan menahan request.
- rate_limited: perlambat dan coba lagi.
Paginasi
Endpoint daftar mengembalikan item terbaru lebih dulu. Pakai limit (1 sampai 100, bawaan 20) dan kirim cursor.next dari satu response sebagai cursor di request berikutnya. Jika cursor.next bernilai null, tidak ada item lagi.
{
"data": [ ... ],
"cursor": { "next": "6650f1c2a1b2c3d4e5f60718" }
}/v1/linksBuat link
Membuat link pendek. Kosongkan domain untuk memakai domain aktif pertama dan slug untuk mendapat slug acak.
Isi request
targetobjectWajibTujuan link. Wajib. Pilih tipe dan isi propertinya.
typestringWajibCara pengunjung diarahkan. Pilih salah satu tipe redirect di bawah.
Salah satuREDIRECTDEVICESMARTSPLIT
Jika type bernilai REDIRECT. Mengarahkan semua pengunjung ke satu URL.
urlstringURLWajibTujuan. URL HTTP atau HTTPS.
statusCodeintegerOpsionalStatus HTTP untuk redirect. 301 dan 308 permanen, 302 dan 307 sementara.
Salah satu301302307308Bawaan302domainIdstringIDOpsionalDomain untuk membuat link. Lihat Daftar domain. Bawaannya domain aktif pertama.
slugstringSlugOpsionalPath link pendek. Huruf kecil, angka, dan tanda hubung. Dibuat acak jika tidak diisi.
Maks64folderIdstringIDOpsionalId folder. Kirim folderId atau folderName, jangan keduanya.
folderobjectOpsionalnamestringWajibMaks60
Response
201Isi response:
idstringIDId unik link.
workspaceIdstringIDWorkspace pemilik link.
domainIdstringIDDomain tempat link berada.
domainobjectDomain tempat link berada.
hostnamestringHostname, misalnya hoot.mx.
userIdstringIDopsionalPengguna yang membuat link, jika diketahui.
folderIdstringIDopsionalnullableFolder tempat link berada, atau null.
slugstringSlugPath setelah domain.
statusstringLink active akan mengalihkan. Link disabled berhenti mengalihkan tetapi analitiknya tetap ada.
Salah satuactivedisabledcreatedAtstringISO 8601Waktu link dibuat.
modestringTipe redirect. Sama dengan target.type dan tidak bisa diubah.
Salah satuREDIRECTDEVICESMARTSPLITROTATORtargetobjectTujuan link. Berupa objek yang type-nya menentukan properti lainnya.
typestringCara pengunjung diarahkan. Pilih salah satu tipe redirect di bawah.
Salah satuREDIRECTDEVICESMARTSPLIT
Jika type bernilai REDIRECT. Mengarahkan semua pengunjung ke satu URL.
urlstringURLTujuan. URL HTTP atau HTTPS.
statusCodeintegerStatus HTTP untuk redirect.
Salah satu301302307308configurationobjectPengaturan tambahan link. Bisa dibaca di sini; perubahannya dilakukan di dashboard.
forwardingobjectMeneruskan parameter query link pendek ke tujuan.
isActivebooleanApakah penerusan aktif.
modestringALL meneruskan semua parameter. ALLOWLIST hanya meneruskan key di bawah.
Salah satuALLALLOWLISTkeysarray<string>Parameter yang diteruskan pada mode ALLOWLIST.
overwritebooleanApakah parameter yang diteruskan menggantikan parameter yang sudah ada di tujuan.
rulesobjectAturan redirect.
timezonestringlistarray<object>idstringId unik link.
destinationstringURL
protectionobjectPerlindungan akses.
passwordbooleanApakah link meminta password. Password tidak pernah dikembalikan.
cloakingobjectopsionalPengaturan pratinjau link, ada jika dikonfigurasi.
isActivebooleanApakah pratinjau kustom aktif.
urlstringURLLink pendek lengkap, siap dibagikan.
Catatan
- Kirim folderId atau folderName, jangan keduanya. Nama folder yang tidak ada mengembalikan 404, dan nama yang dipakai beberapa folder mengembalikan 409.
- Tipe redirect dan jumlah link harus sesuai paket, jika tidak API mengembalikan 422.
Error
- 400Request salah format, atau folderId dan folderName dikirim bersamaan.
- 401API key hilang, tidak valid, kedaluwarsa, atau dicabut.
- 403API key tidak punya scope yang dibutuhkan endpoint ini.
- 404Link atau folder tidak ditemukan di workspace ini.
- 409Slug sudah dipakai, atau nama folder cocok dengan lebih dari satu folder.
- 422Batas paket atau aturan menahan request.
- 429Key melewati batas request. Tunggu selama Retry-After detik.
POST /v1/linkscurl -X POST "https://www.hootmix.com/api/v1/links" \
-H "Authorization: Bearer $HOOTMIX_API_KEY" \
-H "Content-Type: application/json" \
-d '{"target":{"type":"REDIRECT","url":"https://example.com/spring-sale"},"slug":"spring-sale","folder":{"name":"Campaigns"}}'201 Created
{
"id": "6650f1c2a1b2c3d4e5f60718",
"workspaceId": "6650f0aaa1b2c3d4e5f60001",
"domainId": "6650f0bbb1b2c3d4e5f60002",
"domain": {
"hostname": "hoot.mx"
},
"folderId": "6650f0ccc1b2c3d4e5f60003",
"slug": "spring-sale",
"status": "active",
"createdAt": "2026-10-19T08:30:00.000Z",
"mode": "REDIRECT",
"target": {
"type": "REDIRECT",
"url": "https://example.com/spring-sale"
},
"statusCode": 302,
"configuration": {
"forwarding": {
"isActive": false,
"mode": "ALL",
"keys": [],
"overwrite": false
},
"rules": {
"list": [],
"timezone": "Asia/Jakarta"
},
"protection": {
"password": false
}
},
"url": "https://hoot.mx/spring-sale"
}/v1/linksDaftar link
Mengembalikan link kamu, terbaru lebih dulu, satu halaman sekali.
Parameter query
limitintegerOpsionalJumlah link yang dikembalikan.
Bawaan20Min1Maks100cursorstringIDOpsionalcursor.next dari halaman sebelumnya.
folderIdstringIDOpsionalHanya link di folder ini. Kirim folderId atau folderName, jangan keduanya.
folderNamestringOpsionalHanya link di folder dengan nama ini. Kirim folderId atau folderName, jangan keduanya.
Maks60
Response
200Isi response:
dataarray<object>idstringIDId unik link.
workspaceIdstringIDWorkspace pemilik link.
domainIdstringIDDomain tempat link berada.
domainobjectDomain tempat link berada.
hostnamestringHostname, misalnya hoot.mx.
userIdstringIDopsionalPengguna yang membuat link, jika diketahui.
folderIdstringIDopsionalnullableFolder tempat link berada, atau null.
slugstringSlugPath setelah domain.
statusstringLink active akan mengalihkan. Link disabled berhenti mengalihkan tetapi analitiknya tetap ada.
Salah satuactivedisabledcreatedAtstringISO 8601Waktu link dibuat.
modestringTipe redirect. Sama dengan target.type dan tidak bisa diubah.
Salah satuREDIRECTDEVICESMARTSPLITROTATORtargetobjectTujuan link. Berupa objek yang type-nya menentukan properti lainnya.
typestringCara pengunjung diarahkan. Pilih salah satu tipe redirect di bawah.
Salah satuREDIRECTDEVICESMARTSPLIT
Jika type bernilai REDIRECT. Mengarahkan semua pengunjung ke satu URL.
urlstringURLTujuan. URL HTTP atau HTTPS.
statusCodeintegerStatus HTTP untuk redirect.
Salah satu301302307308configurationobjectPengaturan tambahan link. Bisa dibaca di sini; perubahannya dilakukan di dashboard.
forwardingobjectMeneruskan parameter query link pendek ke tujuan.
isActivebooleanApakah penerusan aktif.
modestringALL meneruskan semua parameter. ALLOWLIST hanya meneruskan key di bawah.
Salah satuALLALLOWLISTkeysarray<string>Parameter yang diteruskan pada mode ALLOWLIST.
overwritebooleanApakah parameter yang diteruskan menggantikan parameter yang sudah ada di tujuan.
rulesobjectAturan redirect.
timezonestringlistarray<object>idstringId unik link.
destinationstringURL
protectionobjectPerlindungan akses.
passwordbooleanApakah link meminta password. Password tidak pernah dikembalikan.
cloakingobjectopsionalPengaturan pratinjau link, ada jika dikonfigurasi.
isActivebooleanApakah pratinjau kustom aktif.
urlstringURLLink pendek lengkap, siap dibagikan.
nextCursorstringnullable
Catatan
- Kirim cursor.next sebagai cursor untuk halaman berikutnya. Nilainya null di halaman terakhir.
Error
- 400Request salah format, atau folderId dan folderName dikirim bersamaan.
- 401API key hilang, tidak valid, kedaluwarsa, atau dicabut.
- 403API key tidak punya scope yang dibutuhkan endpoint ini.
- 404Link atau folder tidak ditemukan di workspace ini.
- 409Slug sudah dipakai, atau nama folder cocok dengan lebih dari satu folder.
- 429Key melewati batas request. Tunggu selama Retry-After detik.
GET /v1/linkscurl -X GET "https://www.hootmix.com/api/v1/links?limit=20" \
-H "Authorization: Bearer $HOOTMIX_API_KEY"200 OK
{
"data": [
{
"id": "6650f1c2a1b2c3d4e5f60718",
"workspaceId": "6650f0aaa1b2c3d4e5f60001",
"domainId": "6650f0bbb1b2c3d4e5f60002",
"domain": {
"hostname": "hoot.mx"
},
"folderId": "6650f0ccc1b2c3d4e5f60003",
"slug": "spring-sale",
"status": "active",
"createdAt": "2026-10-19T08:30:00.000Z",
"mode": "REDIRECT",
"target": {
"type": "REDIRECT",
"url": "https://example.com/spring-sale"
},
"statusCode": 302,
"configuration": {
"forwarding": {
"isActive": false,
"mode": "ALL",
"keys": [],
"overwrite": false
},
"rules": {
"list": [],
"timezone": "Asia/Jakarta"
},
"protection": {
"password": false
}
},
"url": "https://hoot.mx/spring-sale"
}
],
"cursor": {
"next": null
}
}Parameter path
idstringIDWajibId link.
Response
200Isi response:
idstringIDId unik link.
workspaceIdstringIDWorkspace pemilik link.
domainIdstringIDDomain tempat link berada.
domainobjectDomain tempat link berada.
hostnamestringHostname, misalnya hoot.mx.
userIdstringIDopsionalPengguna yang membuat link, jika diketahui.
folderIdstringIDopsionalnullableFolder tempat link berada, atau null.
slugstringSlugPath setelah domain.
statusstringLink active akan mengalihkan. Link disabled berhenti mengalihkan tetapi analitiknya tetap ada.
Salah satuactivedisabledcreatedAtstringISO 8601Waktu link dibuat.
modestringTipe redirect. Sama dengan target.type dan tidak bisa diubah.
Salah satuREDIRECTDEVICESMARTSPLITROTATORtargetobjectTujuan link. Berupa objek yang type-nya menentukan properti lainnya.
typestringCara pengunjung diarahkan. Pilih salah satu tipe redirect di bawah.
Salah satuREDIRECTDEVICESMARTSPLIT
Jika type bernilai REDIRECT. Mengarahkan semua pengunjung ke satu URL.
urlstringURLTujuan. URL HTTP atau HTTPS.
statusCodeintegerStatus HTTP untuk redirect.
Salah satu301302307308configurationobjectPengaturan tambahan link. Bisa dibaca di sini; perubahannya dilakukan di dashboard.
forwardingobjectMeneruskan parameter query link pendek ke tujuan.
isActivebooleanApakah penerusan aktif.
modestringALL meneruskan semua parameter. ALLOWLIST hanya meneruskan key di bawah.
Salah satuALLALLOWLISTkeysarray<string>Parameter yang diteruskan pada mode ALLOWLIST.
overwritebooleanApakah parameter yang diteruskan menggantikan parameter yang sudah ada di tujuan.
rulesobjectAturan redirect.
timezonestringlistarray<object>idstringId unik link.
destinationstringURL
protectionobjectPerlindungan akses.
passwordbooleanApakah link meminta password. Password tidak pernah dikembalikan.
cloakingobjectopsionalPengaturan pratinjau link, ada jika dikonfigurasi.
isActivebooleanApakah pratinjau kustom aktif.
urlstringURLLink pendek lengkap, siap dibagikan.
Error
- 401API key hilang, tidak valid, kedaluwarsa, atau dicabut.
- 403API key tidak punya scope yang dibutuhkan endpoint ini.
- 404Link atau folder tidak ditemukan di workspace ini.
- 429Key melewati batas request. Tunggu selama Retry-After detik.
GET /v1/links/{id}curl -X GET "https://www.hootmix.com/api/v1/links/6650f1c2a1b2c3d4e5f60718" \
-H "Authorization: Bearer $HOOTMIX_API_KEY"200 OK
{
"id": "6650f1c2a1b2c3d4e5f60718",
"workspaceId": "6650f0aaa1b2c3d4e5f60001",
"domainId": "6650f0bbb1b2c3d4e5f60002",
"domain": {
"hostname": "hoot.mx"
},
"folderId": "6650f0ccc1b2c3d4e5f60003",
"slug": "spring-sale",
"status": "active",
"createdAt": "2026-10-19T08:30:00.000Z",
"mode": "REDIRECT",
"target": {
"type": "REDIRECT",
"url": "https://example.com/spring-sale"
},
"statusCode": 302,
"configuration": {
"forwarding": {
"isActive": false,
"mode": "ALL",
"keys": [],
"overwrite": false
},
"rules": {
"list": [],
"timezone": "Asia/Jakarta"
},
"protection": {
"password": false
}
},
"url": "https://hoot.mx/spring-sale"
}/v1/links/{id}Ubah link
Mengubah tujuan atau pengaturan link. Kirim hanya yang ingin diubah.
Parameter path
idstringIDWajibId link.
Isi request
targetobjectOpsionalTujuan baru. Tipenya harus sama dengan tipe link saat ini.
typestringWajibCara pengunjung diarahkan. Pilih salah satu tipe redirect di bawah.
Salah satuREDIRECTDEVICESMARTSPLIT
Jika type bernilai REDIRECT. Mengarahkan semua pengunjung ke satu URL.
urlstringURLWajibTujuan. URL HTTP atau HTTPS.
statusCodeintegerOpsionalStatus redirect baru.
Salah satu301302307308statusstringOpsionalPakai disabled agar link berhenti mengalihkan, dan active untuk menyalakannya lagi.
Salah satuactivedisabledfolderIdstringIDOpsionalnullablePindahkan link ke folder ini, atau kirim null untuk mengeluarkannya dari folder. Kirim folderId atau folderName, jangan keduanya.
folderobjectOpsionalnamestringWajibMaks60
Response
200Isi response:
idstringIDId unik link.
workspaceIdstringIDWorkspace pemilik link.
domainIdstringIDDomain tempat link berada.
domainobjectDomain tempat link berada.
hostnamestringHostname, misalnya hoot.mx.
userIdstringIDopsionalPengguna yang membuat link, jika diketahui.
folderIdstringIDopsionalnullableFolder tempat link berada, atau null.
slugstringSlugPath setelah domain.
statusstringLink active akan mengalihkan. Link disabled berhenti mengalihkan tetapi analitiknya tetap ada.
Salah satuactivedisabledcreatedAtstringISO 8601Waktu link dibuat.
modestringTipe redirect. Sama dengan target.type dan tidak bisa diubah.
Salah satuREDIRECTDEVICESMARTSPLITROTATORtargetobjectTujuan link. Berupa objek yang type-nya menentukan properti lainnya.
typestringCara pengunjung diarahkan. Pilih salah satu tipe redirect di bawah.
Salah satuREDIRECTDEVICESMARTSPLIT
Jika type bernilai REDIRECT. Mengarahkan semua pengunjung ke satu URL.
urlstringURLTujuan. URL HTTP atau HTTPS.
statusCodeintegerStatus HTTP untuk redirect.
Salah satu301302307308configurationobjectPengaturan tambahan link. Bisa dibaca di sini; perubahannya dilakukan di dashboard.
forwardingobjectMeneruskan parameter query link pendek ke tujuan.
isActivebooleanApakah penerusan aktif.
modestringALL meneruskan semua parameter. ALLOWLIST hanya meneruskan key di bawah.
Salah satuALLALLOWLISTkeysarray<string>Parameter yang diteruskan pada mode ALLOWLIST.
overwritebooleanApakah parameter yang diteruskan menggantikan parameter yang sudah ada di tujuan.
rulesobjectAturan redirect.
timezonestringlistarray<object>idstringId unik link.
destinationstringURL
protectionobjectPerlindungan akses.
passwordbooleanApakah link meminta password. Password tidak pernah dikembalikan.
cloakingobjectopsionalPengaturan pratinjau link, ada jika dikonfigurasi.
isActivebooleanApakah pratinjau kustom aktif.
urlstringURLLink pendek lengkap, siap dibagikan.
Catatan
- Tipe redirect sebuah link tidak bisa diubah. Buat link baru sebagai gantinya.
- Mengubah tujuan tidak mengubah link pendek atau analitiknya.
Error
- 400Request salah format, atau folderId dan folderName dikirim bersamaan.
- 401API key hilang, tidak valid, kedaluwarsa, atau dicabut.
- 403API key tidak punya scope yang dibutuhkan endpoint ini.
- 404Link atau folder tidak ditemukan di workspace ini.
- 409Slug sudah dipakai, atau nama folder cocok dengan lebih dari satu folder.
- 422Batas paket atau aturan menahan request.
- 429Key melewati batas request. Tunggu selama Retry-After detik.
PATCH /v1/links/{id}curl -X PATCH "https://www.hootmix.com/api/v1/links/6650f1c2a1b2c3d4e5f60718" \
-H "Authorization: Bearer $HOOTMIX_API_KEY" \
-H "Content-Type: application/json" \
-d '{"target":{"type":"REDIRECT","url":"https://example.com/autumn-sale"},"statusCode":301}'200 OK
{
"id": "6650f1c2a1b2c3d4e5f60718",
"workspaceId": "6650f0aaa1b2c3d4e5f60001",
"domainId": "6650f0bbb1b2c3d4e5f60002",
"domain": {
"hostname": "hoot.mx"
},
"folderId": "6650f0ccc1b2c3d4e5f60003",
"slug": "spring-sale",
"status": "active",
"createdAt": "2026-10-19T08:30:00.000Z",
"mode": "REDIRECT",
"target": {
"type": "REDIRECT",
"url": "https://example.com/autumn-sale"
},
"statusCode": 301,
"configuration": {
"forwarding": {
"isActive": false,
"mode": "ALL",
"keys": [],
"overwrite": false
},
"rules": {
"list": [],
"timezone": "Asia/Jakarta"
},
"protection": {
"password": false
}
},
"url": "https://hoot.mx/spring-sale"
}/v1/links/{id}Hapus link
Menonaktifkan link, sehingga berhenti mengalihkan tetapi analitiknya tetap ada. Tambahkan hard=true untuk menghapusnya selamanya.
Parameter path
idstringIDWajibId link.
Parameter query
hardbooleanOpsionalIsi true untuk menghapus link beserta analitiknya. Ini tidak bisa dibatalkan.
Bawaanfalse
Response
204Mengembalikan response kosong.
Catatan
- Kedua bentuk menjawab 204 tanpa isi.
- Link yang dinonaktifkan bisa dinyalakan lagi dengan Ubah link.
Error
- 401API key hilang, tidak valid, kedaluwarsa, atau dicabut.
- 403API key tidak punya scope yang dibutuhkan endpoint ini.
- 404Link atau folder tidak ditemukan di workspace ini.
- 429Key melewati batas request. Tunggu selama Retry-After detik.
DELETE /v1/links/{id}curl -X DELETE "https://www.hootmix.com/api/v1/links/6650f1c2a1b2c3d4e5f60718" \
-H "Authorization: Bearer $HOOTMIX_API_KEY"204 No Content
Tanpa isi response/v1/links/{id}/statsAmbil analitik link
Mengembalikan klik, pengunjung, deret waktu, dan rincian untuk satu link.
Parameter path
idstringIDWajibId link.
Parameter query
daysintegerOpsionalRentang laporan.
Salah satu173090Bawaan7tagstringOpsionalHanya hitung event yang diberi tag ini.
Maks60
Response
200Isi response:
visitsintegerTotal klik dalam periode.
visitorsobjectJumlah pengunjung.
uniqueintegerPengunjung berbeda dalam periode.
tagsarray<object>Klik dikelompokkan menurut tag yang dimilikinya. Klik dengan dua tag dihitung di keduanya.
_idstringNilai yang dihitung, misalnya nama browser.
countintegerJumlah klik.
seriesarray<object>Klik dari waktu ke waktu. Satu titik per jam untuk rentang 1 hari, selain itu satu per hari.
timestringISO 8601Awal periode.
availablebooleanFalse untuk periode sebelum analitik dicatat.
visitsintegerKlik pada periode itu.
breakdownsobjectKlik dikelompokkan menurut dimensi umum. Setiap daftar diurutkan menurut jumlah.
sourcesarray<object>Situs perujuk, atau Direct / unknown.
_idstringNilai yang dihitung, misalnya nama browser.
countintegerJumlah klik.
devicesarray<object>Desktop, Mobile atau Tablet.
_idstringNilai yang dihitung, misalnya nama browser.
countintegerJumlah klik.
browsersarray<object>Nama browser.
_idstringNilai yang dihitung, misalnya nama browser.
countintegerJumlah klik.
outcomesarray<object>Untuk smart link, bagaimana pengunjung diteruskan.
_idstringNilai yang dihitung, misalnya nama browser.
countintegerJumlah klik.
attemptsarray<object>Untuk smart link, tujuan yang dicoba.
_idstringNilai yang dihitung, misalnya nama browser.
countintegerJumlah klik.
openingsarray<object>Untuk smart link, apakah aplikasi tampak terbuka.
_idstringNilai yang dihitung, misalnya nama browser.
countintegerJumlah klik.
detailsobjectDimensi lain, setiap daftar dibatasi 10 teratas.
geoobjectLokasi pengunjung.
countryCodesarray<object>Klik per kode negara.
_idstringNilai yang dihitung, misalnya nama browser.
countintegerJumlah klik.
regionsarray<object>Klik per negara dan wilayah.
_idstringNilai yang dihitung, misalnya nama browser.
countintegerJumlah klik.
citiesarray<object>Klik per negara dan kota.
_idstringNilai yang dihitung, misalnya nama browser.
countintegerJumlah klik.
agentobjectYang dipakai pengunjung.
osarray<object>Nama sistem operasi.
_idstringNilai yang dihitung, misalnya nama browser.
countintegerJumlah klik.
referrerobjectAsal pengunjung.
urlsarray<object>Halaman perujuk tanpa query string.
_idstringNilai yang dihitung, misalnya nama browser.
countintegerJumlah klik.
utmobjectParameter kampanye pada link pendek.
sourcearray<object>Nilai utm_source.
_idstringNilai yang dihitung, misalnya nama browser.
countintegerJumlah klik.
mediumarray<object>Nilai utm_medium.
_idstringNilai yang dihitung, misalnya nama browser.
countintegerJumlah klik.
campaignarray<object>Nilai utm_campaign.
_idstringNilai yang dihitung, misalnya nama browser.
countintegerJumlah klik.
cutoffstringISO 8601Akhir periode, yaitu saat stats dibuat.
historyobjectApakah periode tercatat seluruhnya.
sincestringISO 8601nullableKapan pencatatan analitik dimulai, atau null jika seluruh periode tercakup.
isPartialbooleanTrue jika periode dimulai sebelum analitik dicatat.
Catatan
- Jumlah hari yang bisa diminta bergantung pada paket. Rentang lebih panjang mengembalikan 422.
- Tag dimiliki event klik, jadi memberi tag pada event nanti akan mengubah angka ini.
Error
- 400Request salah format, atau folderId dan folderName dikirim bersamaan.
- 401API key hilang, tidak valid, kedaluwarsa, atau dicabut.
- 403API key tidak punya scope yang dibutuhkan endpoint ini.
- 404Link atau folder tidak ditemukan di workspace ini.
- 422Batas paket atau aturan menahan request.
- 429Key melewati batas request. Tunggu selama Retry-After detik.
GET /v1/links/{id}/statscurl -X GET "https://www.hootmix.com/api/v1/links/6650f1c2a1b2c3d4e5f60718/stats?days=7" \
-H "Authorization: Bearer $HOOTMIX_API_KEY"200 OK
{
"visits": 128,
"visitors": {
"unique": 97
},
"tags": [
{
"_id": "launch",
"count": 128
}
],
"series": [
{
"time": "2026-10-12T08:30:00.000Z",
"available": true,
"visits": 14
},
{
"time": "2026-10-13T08:30:00.000Z",
"available": true,
"visits": 21
}
],
"breakdowns": {
"sources": [
{
"_id": "Direct / unknown",
"count": 80
}
],
"devices": [
{
"_id": "Mobile",
"count": 90
}
],
"browsers": [
{
"_id": "Chrome",
"count": 70
}
],
"outcomes": [],
"attempts": [],
"openings": []
},
"details": {
"geo": {
"countryCodes": [
{
"_id": "ID",
"count": 90
}
],
"regions": [],
"cities": []
},
"agent": {
"os": [
{
"_id": "Android",
"count": 60
}
]
},
"referrer": {
"urls": []
},
"utm": {
"source": [
{
"_id": "newsletter",
"count": 40
}
],
"medium": [],
"campaign": []
}
},
"cutoff": "2026-10-19T08:30:00.000Z",
"history": {
"since": null,
"isPartial": false
}
}/v1/eventsDaftar event
Mengembalikan event klik, terbaru lebih dulu. Bot tidak disertakan.
Parameter query
limitintegerOpsionalJumlah event yang dikembalikan.
Bawaan20Min1Maks100cursorstringOpsionalcursor.next dari halaman sebelumnya.
linkIdstringIDOpsionalHanya event dari link ini.
tagstringOpsionalHanya event dengan tag ini.
Maks60
Response
200Isi response:
dataarray<object>idstringId unik event. Pakai untuk membaca dan memberi tag pada event.
linkIdstringIDLink yang diklik.
createdAtstringISO 8601Waktu klik terjadi.
tagsarray<string>Tag pada event ini. Kosong sampai kamu memberinya tag.
Maks10devicestringnullableDesktop, Mobile atau Tablet.
browserstringnullableNama browser.
osstringnullableNama sistem operasi.
referrerstringURLnullableHalaman asal pengunjung, tanpa query string.
geoobjectLokasi pengunjung.
countryCodestringnullableKode negara ISO 3166-1 alpha-2.
regionstringnullableWilayah.
citystringnullableKota.
visitorobjectPengunjung di balik klik.
idstringnullableId anonim pengunjung, disimpan di cookie first-party.
isUniquebooleannullableTrue saat pengunjung ini pertama kali mengeklik link ini.
utmobjectParameter kampanye pada link pendek.
sourcestringnullableNilai utm_source.
mediumstringnullableNilai utm_medium.
campaignstringnullableNilai utm_campaign.
nextCursorstringnullable
Catatan
- Id setiap event adalah id yang dikirim webhook klik.
- Kirim cursor.next sebagai cursor untuk halaman berikutnya. Nilainya null di halaman terakhir.
Error
- 400Request salah format, atau folderId dan folderName dikirim bersamaan.
- 401API key hilang, tidak valid, kedaluwarsa, atau dicabut.
- 403API key tidak punya scope yang dibutuhkan endpoint ini.
- 429Key melewati batas request. Tunggu selama Retry-After detik.
GET /v1/eventscurl -X GET "https://www.hootmix.com/api/v1/events?limit=20" \
-H "Authorization: Bearer $HOOTMIX_API_KEY"200 OK
{
"data": [
{
"id": "b1f2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"linkId": "6650f1c2a1b2c3d4e5f60718",
"createdAt": "2026-10-19T08:31:12.000Z",
"tags": [
"converted"
],
"device": "Mobile",
"browser": "Chrome",
"os": "Android",
"referrer": "https://newsletter.example.com/issue-42",
"geo": {
"countryCode": "ID",
"region": "JK",
"city": "Jakarta"
},
"visitor": {
"id": "5a0e9d1c-3b7f-4c52-9a1e-2f6d8b4c7e10",
"isUnique": true
},
"utm": {
"source": "newsletter",
"medium": "email",
"campaign": "spring"
}
}
],
"cursor": {
"next": null
}
}/v1/events/{id}Ambil event
Mengembalikan satu event klik berdasarkan id yang dikirim webhook klik.
Parameter path
idstringWajibId event. Ini adalah data.event.id di webhook klik.
Response
200Isi response:
idstringId unik event. Pakai untuk membaca dan memberi tag pada event.
linkIdstringIDLink yang diklik.
createdAtstringISO 8601Waktu klik terjadi.
tagsarray<string>Tag pada event ini. Kosong sampai kamu memberinya tag.
Maks10devicestringnullableDesktop, Mobile atau Tablet.
browserstringnullableNama browser.
osstringnullableNama sistem operasi.
referrerstringURLnullableHalaman asal pengunjung, tanpa query string.
geoobjectLokasi pengunjung.
countryCodestringnullableKode negara ISO 3166-1 alpha-2.
regionstringnullableWilayah.
citystringnullableKota.
visitorobjectPengunjung di balik klik.
idstringnullableId anonim pengunjung, disimpan di cookie first-party.
isUniquebooleannullableTrue saat pengunjung ini pertama kali mengeklik link ini.
utmobjectParameter kampanye pada link pendek.
sourcestringnullableNilai utm_source.
mediumstringnullableNilai utm_medium.
campaignstringnullableNilai utm_campaign.
Error
- 401API key hilang, tidak valid, kedaluwarsa, atau dicabut.
- 403API key tidak punya scope yang dibutuhkan endpoint ini.
- 404Link atau folder tidak ditemukan di workspace ini.
- 429Key melewati batas request. Tunggu selama Retry-After detik.
GET /v1/events/{id}curl -X GET "https://www.hootmix.com/api/v1/events/b1f2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d" \
-H "Authorization: Bearer $HOOTMIX_API_KEY"200 OK
{
"id": "b1f2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"linkId": "6650f1c2a1b2c3d4e5f60718",
"createdAt": "2026-10-19T08:31:12.000Z",
"tags": [
"converted"
],
"device": "Mobile",
"browser": "Chrome",
"os": "Android",
"referrer": "https://newsletter.example.com/issue-42",
"geo": {
"countryCode": "ID",
"region": "JK",
"city": "Jakarta"
},
"visitor": {
"id": "5a0e9d1c-3b7f-4c52-9a1e-2f6d8b4c7e10",
"isUnique": true
},
"utm": {
"source": "newsletter",
"medium": "email",
"campaign": "spring"
}
}/v1/foldersDaftar folder
Mengembalikan semua folder di workspace. Pakai parentId untuk menyusun ulang pohon.
Response
200Isi response:
dataarray<object>idstringIDId unik folder.
parentIdstringIDnullableFolder induk, atau null di tingkat atas.
namestringNama folder.
Error
- 401API key hilang, tidak valid, kedaluwarsa, atau dicabut.
- 403API key tidak punya scope yang dibutuhkan endpoint ini.
- 429Key melewati batas request. Tunggu selama Retry-After detik.
GET /v1/folderscurl -X GET "https://www.hootmix.com/api/v1/folders" \
-H "Authorization: Bearer $HOOTMIX_API_KEY"200 OK
{
"data": [
{
"id": "6650f0ccc1b2c3d4e5f60003",
"parentId": null,
"name": "Campaigns"
},
{
"id": "6650f0ddd1b2c3d4e5f60004",
"parentId": "6650f0ccc1b2c3d4e5f60003",
"name": "Autumn"
}
]
}/v1/domainsDaftar domain
Mengembalikan domain yang bisa dipakai untuk membuat link.
Response
200Isi response:
dataarray<object>idstringIDId unik domain.
hostnamestringHostname.
kindstringDomain GLOBAL dibagikan dan dikelola Hootmix. WORKSPACE disiapkan untuk domain milik workspace.
Salah satuGLOBALWORKSPACE
Catatan
- Untuk saat ini domain dikelola oleh administrator Hootmix. Menambah domain sendiri lewat API sudah direncanakan.
Error
- 401API key hilang, tidak valid, kedaluwarsa, atau dicabut.
- 403API key tidak punya scope yang dibutuhkan endpoint ini.
- 429Key melewati batas request. Tunggu selama Retry-After detik.
GET /v1/domainscurl -X GET "https://www.hootmix.com/api/v1/domains" \
-H "Authorization: Bearer $HOOTMIX_API_KEY"200 OK
{
"data": [
{
"id": "6650f0bbb1b2c3d4e5f60002",
"hostname": "hoot.mx",
"kind": "GLOBAL"
}
]
}Webhook
Webhook mengirim HTTP POST ke server kamu saat sesuatu terjadi di workspace, sehingga kamu tidak perlu polling API. Tambahkan endpoint di menu Webhook pada workspace, pilih event yang diinginkan, dan batasi ke beberapa folder jika perlu. Filter folder juga mencakup subfolder.
Setiap request memiliki body JSON dengan amplop yang sama. Isi data bergantung pada event.
{
"id": "9d2f6c1e-7a4b-4e0d-8f53-2c1b6a9e4d70",
"event": "link.clicked",
"createdAt": "2026-10-19T08:31:12.000Z",
"data": { }
}Setiap request juga membawa header berikut:
- X-Hootmix-Event: nama event.
- X-Hootmix-Delivery: id percobaan pengiriman ini.
- X-Hootmix-Signature: sha256= diikuti HMAC SHA-256 dari body request mentah, dibuat dengan signing secret kamu.
- User-Agent: Hootmix-Webhook/1.0
Periksa tanda tangan sebelum mempercayai request. Signing secret hanya ditampilkan sekali, saat kamu membuat endpoint atau memutar secret-nya. Hitung HMAC dari body mentah, bukan dari JSON yang sudah diurai.
import { createHmac, timingSafeEqual } from "node:crypto";
const verify = (rawBody, header, secret) => {
const expected = "sha256=" + createHmac("sha256", secret).update(rawBody).digest("hex");
return header.length === expected.length && timingSafeEqual(Buffer.from(header), Buffer.from(expected));
};import hashlib
import hmac
def verify(raw_body: bytes, header: str, secret: str) -> bool:
expected = "sha256=" + hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(header, expected)function verify(string $rawBody, string $header, string $secret): bool {
$expected = "sha256=" . hash_hmac("sha256", $rawBody, $secret);
return hash_equals($expected, $header);
}Pengiriman:
- Jawab dengan status 2xx apa pun dalam 5 detik. Status lain, atau tanpa jawaban, dianggap gagal.
- Pengiriman yang gagal dicoba ulang setelah 30 detik, 2 menit, 8 menit, dan 32 menit. Setelah percobaan kelima gagal, statusnya ditandai gagal. Pengiriman terbaru setiap endpoint tercantum di workspace kamu.
- Id di body tetap sama saat dicoba ulang dan di semua endpoint kamu, jadi pakai untuk mengabaikan duplikat.
- Redirect tidak diikuti, dan endpoint harus berupa alamat HTTP atau HTTPS publik.
- Pakai Kirim tes pada endpoint untuk mengirim notifikasi webhook.test.
Payload
idstringId unik notifikasi ini. Tetap sama saat dicoba ulang dan di semua endpoint kamu, jadi pakai untuk mengabaikan duplikat.
eventstringKlik tersebut.
Salah satulink.clickedcreatedAtstringISO 8601Waktu notifikasi dibuat.
dataobjectApa yang terjadi. Propertinya bergantung pada event.
linkobjectLink yang diklik.
idstringIDId link.
urlstringURLLink pendek.
slugstringPath setelah domain.
eventobjectKlik tersebut.
idstringId event klik. Pakai dengan API untuk membaca atau memberi tag pada event.
visitorIdstringId anonim pengunjung, disimpan di cookie first-party.
isUniquebooleanTrue saat pengunjung ini pertama kali mengeklik link ini.
countryCodestringnullableKode negara ISO 3166-1 alpha-2, jika diketahui.
regionstringnullableWilayah, jika diketahui.
citystringnullableKota, jika diketahui.
devicestringnullableDesktop, Mobile atau Tablet.
browserstringnullableNama browser.
osstringnullableNama sistem operasi.
referrerstringURLnullableHalaman asal pengunjung, tanpa query string.
utmobjectParameter kampanye pada link pendek.
sourcestringnullableNilai utm_source.
mediumstringnullableNilai utm_medium.
campaignstringnullableNilai utm_campaign.
Catatan
- data.event.id adalah id event klik. Pakai dengan PUT /v1/events/{id}/tags untuk memberi tag pada klik, atau GET /v1/events/{id} untuk membacanya.
- Buat endpoint dengan filter folder untuk hanya menerima klik dari link di folder tersebut.
POST endpoint kamu{
"id": "9d2f6c1e-7a4b-4e0d-8f53-2c1b6a9e4d70",
"event": "link.clicked",
"createdAt": "2026-10-19T08:31:12.000Z",
"data": {
"link": {
"id": "6650f1c2a1b2c3d4e5f60718",
"url": "https://hoot.mx/spring-sale",
"slug": "spring-sale"
},
"event": {
"id": "b1f2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"visitorId": "5a0e9d1c-3b7f-4c52-9a1e-2f6d8b4c7e10",
"isUnique": true,
"countryCode": "ID",
"region": "JK",
"city": "Jakarta",
"device": "Mobile",
"browser": "Chrome",
"os": "Android",
"referrer": "https://newsletter.example.com/issue-42",
"utm": {
"source": "newsletter",
"medium": "email",
"campaign": "spring"
}
}
}
}Payload
idstringId unik notifikasi ini. Tetap sama saat dicoba ulang dan di semua endpoint kamu, jadi pakai untuk mengabaikan duplikat.
eventstringNama event. Juga ada di header X-Hootmix-Event.
Salah satulink.createdcreatedAtstringISO 8601Waktu notifikasi dibuat.
dataobjectApa yang terjadi. Propertinya bergantung pada event.
linkobjectLink yang dimaksud.
idstringIDId link.
urlstringURLLink pendek.
slugstringPath setelah domain.
modestringTipe redirect.
Salah satuREDIRECTDEVICESMARTSPLITstatusstringactive atau disabled.
Salah satuactivedisabledfolderIdstringIDnullableFolder tempat link berada, atau null.
Catatan
- Mengimpor link mengirim satu notifikasi per link.
POST endpoint kamu{
"id": "9d2f6c1e-7a4b-4e0d-8f53-2c1b6a9e4d70",
"event": "link.created",
"createdAt": "2026-10-19T08:31:12.000Z",
"data": {
"link": {
"id": "6650f1c2a1b2c3d4e5f60718",
"url": "https://hoot.mx/spring-sale",
"slug": "spring-sale",
"mode": "REDIRECT",
"status": "active",
"folderId": "6650f0ccc1b2c3d4e5f60003"
}
}
}Payload
idstringId unik notifikasi ini. Tetap sama saat dicoba ulang dan di semua endpoint kamu, jadi pakai untuk mengabaikan duplikat.
eventstringNama event. Juga ada di header X-Hootmix-Event.
Salah satulink.updatedcreatedAtstringISO 8601Waktu notifikasi dibuat.
dataobjectApa yang terjadi. Propertinya bergantung pada event.
linkobjectLink yang dimaksud.
idstringIDId link.
urlstringURLLink pendek.
slugstringPath setelah domain.
modestringTipe redirect.
Salah satuREDIRECTDEVICESMARTSPLITstatusstringactive atau disabled.
Salah satuactivedisabledfolderIdstringIDnullableFolder tempat link berada, atau null.
POST endpoint kamu{
"id": "9d2f6c1e-7a4b-4e0d-8f53-2c1b6a9e4d70",
"event": "link.updated",
"createdAt": "2026-10-19T08:31:12.000Z",
"data": {
"link": {
"id": "6650f1c2a1b2c3d4e5f60718",
"url": "https://hoot.mx/spring-sale",
"slug": "spring-sale",
"mode": "REDIRECT",
"status": "disabled",
"folderId": "6650f0ccc1b2c3d4e5f60003"
}
}
}Payload
idstringId unik notifikasi ini. Tetap sama saat dicoba ulang dan di semua endpoint kamu, jadi pakai untuk mengabaikan duplikat.
eventstringNama event. Juga ada di header X-Hootmix-Event.
Salah satulink.deletedcreatedAtstringISO 8601Waktu notifikasi dibuat.
dataobjectApa yang terjadi. Propertinya bergantung pada event.
linkobjectLink yang dimaksud.
idstringIDId link.
slugstringPath setelah domain.
POST endpoint kamu{
"id": "9d2f6c1e-7a4b-4e0d-8f53-2c1b6a9e4d70",
"event": "link.deleted",
"createdAt": "2026-10-19T08:31:12.000Z",
"data": {
"link": {
"id": "6650f1c2a1b2c3d4e5f60718",
"slug": "spring-sale"
}
}
}webhook.test
Dikirim saat kamu menekan Kirim tes pada endpoint, untuk memastikan endpoint berfungsi.
Payload
idstringId unik notifikasi ini. Tetap sama saat dicoba ulang dan di semua endpoint kamu, jadi pakai untuk mengabaikan duplikat.
eventstringNama event. Juga ada di header X-Hootmix-Event.
Salah satuwebhook.testcreatedAtstringISO 8601Waktu notifikasi dibuat.
dataobjectKosong untuk notifikasi tes.
POST endpoint kamu{
"id": "9d2f6c1e-7a4b-4e0d-8f53-2c1b6a9e4d70",
"event": "webhook.test",
"createdAt": "2026-10-19T08:31:12.000Z",
"data": {}
}