• Hootmix
Panduan
  • Pengantar
  • Mulai cepat
  • Autentikasi
  • Memberi tag pada event
  • Batas request
  • Error
  • Paginasi
Link
  • Buat linkPOST
  • Daftar linkGET
  • Ambil linkGET
  • Ubah linkPATCH
  • Hapus linkDELETE
  • Ambil analitik linkGET
Event
  • Daftar eventGET
  • Ambil eventGET
  • Beri tag pada eventPUT
Folder
  • Daftar folderGET
Tag
  • Daftar tagGET
Domain
  • Daftar domainGET
Webhook
  • Webhook
  • link.clicked
  • link.created
  • link.updated
  • link.deleted
  • webhook.test
Dokumentasi API
Masuk

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/v1

Versi 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.

MasukMasuk untuk memilih workspace dan mengelola API key-nya.

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" }
}
POST/v1/links

Buat link

Membuat link pendek. Kosongkan domain untuk memakai domain aktif pertama dan slug untuk mendapat slug acak.

Scope yang dibutuhkanlinks.write

Isi request

  • targetobjectWajib

    Tujuan link. Wajib. Pilih tipe dan isi propertinya.

    • typestringWajib

      Cara pengunjung diarahkan. Pilih salah satu tipe redirect di bawah.

      Salah satuREDIRECTDEVICESMARTSPLIT

    Jika type bernilai REDIRECT. Mengarahkan semua pengunjung ke satu URL.

    • urlstringURLWajib

      Tujuan. URL HTTP atau HTTPS.

  • statusCodeintegerOpsional

    Status HTTP untuk redirect. 301 dan 308 permanen, 302 dan 307 sementara.

    Salah satu301302307308Bawaan 302
  • domainIdstringIDOpsional

    Domain untuk membuat link. Lihat Daftar domain. Bawaannya domain aktif pertama.

  • slugstringSlugOpsional

    Path link pendek. Huruf kecil, angka, dan tanda hubung. Dibuat acak jika tidak diisi.

    Maks 64
  • folderIdstringIDOpsional

    Id folder. Kirim folderId atau folderName, jangan keduanya.

  • folderobjectOpsional
    • namestringWajib
      Maks 60

Response

201Isi response:

  • idstringID

    Id unik link.

  • workspaceIdstringID

    Workspace pemilik link.

  • domainIdstringID

    Domain tempat link berada.

  • domainobject

    Domain tempat link berada.

    • hostnamestring

      Hostname, misalnya hoot.mx.

  • userIdstringIDopsional

    Pengguna yang membuat link, jika diketahui.

  • folderIdstringIDopsionalnullable

    Folder tempat link berada, atau null.

  • slugstringSlug

    Path setelah domain.

  • statusstring

    Link active akan mengalihkan. Link disabled berhenti mengalihkan tetapi analitiknya tetap ada.

    Salah satuactivedisabled
  • createdAtstringISO 8601

    Waktu link dibuat.

  • modestring

    Tipe redirect. Sama dengan target.type dan tidak bisa diubah.

    Salah satuREDIRECTDEVICESMARTSPLITROTATOR
  • targetobject

    Tujuan link. Berupa objek yang type-nya menentukan properti lainnya.

    • typestring

      Cara pengunjung diarahkan. Pilih salah satu tipe redirect di bawah.

      Salah satuREDIRECTDEVICESMARTSPLIT

    Jika type bernilai REDIRECT. Mengarahkan semua pengunjung ke satu URL.

    • urlstringURL

      Tujuan. URL HTTP atau HTTPS.

  • statusCodeinteger

    Status HTTP untuk redirect.

    Salah satu301302307308
  • configurationobject

    Pengaturan tambahan link. Bisa dibaca di sini; perubahannya dilakukan di dashboard.

    • forwardingobject

      Meneruskan parameter query link pendek ke tujuan.

      • isActiveboolean

        Apakah penerusan aktif.

      • modestring

        ALL meneruskan semua parameter. ALLOWLIST hanya meneruskan key di bawah.

        Salah satuALLALLOWLIST
      • keysarray<string>

        Parameter yang diteruskan pada mode ALLOWLIST.

      • overwriteboolean

        Apakah parameter yang diteruskan menggantikan parameter yang sudah ada di tujuan.

    • rulesobject

      Aturan redirect.

      • timezonestring
      • listarray<object>
        • idstring

          Id unik link.

        • destinationstringURL
    • protectionobject

      Perlindungan akses.

      • passwordboolean

        Apakah link meminta password. Password tidak pernah dikembalikan.

    • cloakingobjectopsional

      Pengaturan pratinjau link, ada jika dikonfigurasi.

      • isActiveboolean

        Apakah pratinjau kustom aktif.

  • urlstringURL

    Link 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/links
Contoh
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/spring-sale"},"slug":"spring-sale","folder":{"name":"Campaigns"}}'
Response

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"
}
GET/v1/links

Daftar link

Mengembalikan link kamu, terbaru lebih dulu, satu halaman sekali.

Scope yang dibutuhkanlinks.read

Parameter query

  • limitintegerOpsional

    Jumlah link yang dikembalikan.

    Bawaan 20Min 1Maks 100
  • cursorstringIDOpsional

    cursor.next dari halaman sebelumnya.

  • folderIdstringIDOpsional

    Hanya link di folder ini. Kirim folderId atau folderName, jangan keduanya.

  • folderNamestringOpsional

    Hanya link di folder dengan nama ini. Kirim folderId atau folderName, jangan keduanya.

    Maks 60

Response

200Isi response:

  • dataarray<object>
    • idstringID

      Id unik link.

    • workspaceIdstringID

      Workspace pemilik link.

    • domainIdstringID

      Domain tempat link berada.

    • domainobject

      Domain tempat link berada.

      • hostnamestring

        Hostname, misalnya hoot.mx.

    • userIdstringIDopsional

      Pengguna yang membuat link, jika diketahui.

    • folderIdstringIDopsionalnullable

      Folder tempat link berada, atau null.

    • slugstringSlug

      Path setelah domain.

    • statusstring

      Link active akan mengalihkan. Link disabled berhenti mengalihkan tetapi analitiknya tetap ada.

      Salah satuactivedisabled
    • createdAtstringISO 8601

      Waktu link dibuat.

    • modestring

      Tipe redirect. Sama dengan target.type dan tidak bisa diubah.

      Salah satuREDIRECTDEVICESMARTSPLITROTATOR
    • targetobject

      Tujuan link. Berupa objek yang type-nya menentukan properti lainnya.

      • typestring

        Cara pengunjung diarahkan. Pilih salah satu tipe redirect di bawah.

        Salah satuREDIRECTDEVICESMARTSPLIT

      Jika type bernilai REDIRECT. Mengarahkan semua pengunjung ke satu URL.

      • urlstringURL

        Tujuan. URL HTTP atau HTTPS.

    • statusCodeinteger

      Status HTTP untuk redirect.

      Salah satu301302307308
    • configurationobject

      Pengaturan tambahan link. Bisa dibaca di sini; perubahannya dilakukan di dashboard.

      • forwardingobject

        Meneruskan parameter query link pendek ke tujuan.

        • isActiveboolean

          Apakah penerusan aktif.

        • modestring

          ALL meneruskan semua parameter. ALLOWLIST hanya meneruskan key di bawah.

          Salah satuALLALLOWLIST
        • keysarray<string>

          Parameter yang diteruskan pada mode ALLOWLIST.

        • overwriteboolean

          Apakah parameter yang diteruskan menggantikan parameter yang sudah ada di tujuan.

      • rulesobject

        Aturan redirect.

        • timezonestring
        • listarray<object>
          • idstring

            Id unik link.

          • destinationstringURL
      • protectionobject

        Perlindungan akses.

        • passwordboolean

          Apakah link meminta password. Password tidak pernah dikembalikan.

      • cloakingobjectopsional

        Pengaturan pratinjau link, ada jika dikonfigurasi.

        • isActiveboolean

          Apakah pratinjau kustom aktif.

    • urlstringURL

      Link 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/links
Contoh
curl -X GET "https://www.hootmix.com/api/v1/links?limit=20" \
  -H "Authorization: Bearer $HOOTMIX_API_KEY"
Response

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
  }
}
GET/v1/links/{id}

Ambil link

Mengembalikan satu link.

Scope yang dibutuhkanlinks.read

Parameter path

  • idstringIDWajib

    Id link.

Response

200Isi response:

  • idstringID

    Id unik link.

  • workspaceIdstringID

    Workspace pemilik link.

  • domainIdstringID

    Domain tempat link berada.

  • domainobject

    Domain tempat link berada.

    • hostnamestring

      Hostname, misalnya hoot.mx.

  • userIdstringIDopsional

    Pengguna yang membuat link, jika diketahui.

  • folderIdstringIDopsionalnullable

    Folder tempat link berada, atau null.

  • slugstringSlug

    Path setelah domain.

  • statusstring

    Link active akan mengalihkan. Link disabled berhenti mengalihkan tetapi analitiknya tetap ada.

    Salah satuactivedisabled
  • createdAtstringISO 8601

    Waktu link dibuat.

  • modestring

    Tipe redirect. Sama dengan target.type dan tidak bisa diubah.

    Salah satuREDIRECTDEVICESMARTSPLITROTATOR
  • targetobject

    Tujuan link. Berupa objek yang type-nya menentukan properti lainnya.

    • typestring

      Cara pengunjung diarahkan. Pilih salah satu tipe redirect di bawah.

      Salah satuREDIRECTDEVICESMARTSPLIT

    Jika type bernilai REDIRECT. Mengarahkan semua pengunjung ke satu URL.

    • urlstringURL

      Tujuan. URL HTTP atau HTTPS.

  • statusCodeinteger

    Status HTTP untuk redirect.

    Salah satu301302307308
  • configurationobject

    Pengaturan tambahan link. Bisa dibaca di sini; perubahannya dilakukan di dashboard.

    • forwardingobject

      Meneruskan parameter query link pendek ke tujuan.

      • isActiveboolean

        Apakah penerusan aktif.

      • modestring

        ALL meneruskan semua parameter. ALLOWLIST hanya meneruskan key di bawah.

        Salah satuALLALLOWLIST
      • keysarray<string>

        Parameter yang diteruskan pada mode ALLOWLIST.

      • overwriteboolean

        Apakah parameter yang diteruskan menggantikan parameter yang sudah ada di tujuan.

    • rulesobject

      Aturan redirect.

      • timezonestring
      • listarray<object>
        • idstring

          Id unik link.

        • destinationstringURL
    • protectionobject

      Perlindungan akses.

      • passwordboolean

        Apakah link meminta password. Password tidak pernah dikembalikan.

    • cloakingobjectopsional

      Pengaturan pratinjau link, ada jika dikonfigurasi.

      • isActiveboolean

        Apakah pratinjau kustom aktif.

  • urlstringURL

    Link 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"
Response

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"
}
PATCH/v1/links/{id}

Ubah link

Mengubah tujuan atau pengaturan link. Kirim hanya yang ingin diubah.

Scope yang dibutuhkanlinks.write

Parameter path

  • idstringIDWajib

    Id link.

Isi request

  • targetobjectOpsional

    Tujuan baru. Tipenya harus sama dengan tipe link saat ini.

    • typestringWajib

      Cara pengunjung diarahkan. Pilih salah satu tipe redirect di bawah.

      Salah satuREDIRECTDEVICESMARTSPLIT

    Jika type bernilai REDIRECT. Mengarahkan semua pengunjung ke satu URL.

    • urlstringURLWajib

      Tujuan. URL HTTP atau HTTPS.

  • statusCodeintegerOpsional

    Status redirect baru.

    Salah satu301302307308
  • statusstringOpsional

    Pakai disabled agar link berhenti mengalihkan, dan active untuk menyalakannya lagi.

    Salah satuactivedisabled
  • folderIdstringIDOpsionalnullable

    Pindahkan link ke folder ini, atau kirim null untuk mengeluarkannya dari folder. Kirim folderId atau folderName, jangan keduanya.

  • folderobjectOpsional
    • namestringWajib
      Maks 60

Response

200Isi response:

  • idstringID

    Id unik link.

  • workspaceIdstringID

    Workspace pemilik link.

  • domainIdstringID

    Domain tempat link berada.

  • domainobject

    Domain tempat link berada.

    • hostnamestring

      Hostname, misalnya hoot.mx.

  • userIdstringIDopsional

    Pengguna yang membuat link, jika diketahui.

  • folderIdstringIDopsionalnullable

    Folder tempat link berada, atau null.

  • slugstringSlug

    Path setelah domain.

  • statusstring

    Link active akan mengalihkan. Link disabled berhenti mengalihkan tetapi analitiknya tetap ada.

    Salah satuactivedisabled
  • createdAtstringISO 8601

    Waktu link dibuat.

  • modestring

    Tipe redirect. Sama dengan target.type dan tidak bisa diubah.

    Salah satuREDIRECTDEVICESMARTSPLITROTATOR
  • targetobject

    Tujuan link. Berupa objek yang type-nya menentukan properti lainnya.

    • typestring

      Cara pengunjung diarahkan. Pilih salah satu tipe redirect di bawah.

      Salah satuREDIRECTDEVICESMARTSPLIT

    Jika type bernilai REDIRECT. Mengarahkan semua pengunjung ke satu URL.

    • urlstringURL

      Tujuan. URL HTTP atau HTTPS.

  • statusCodeinteger

    Status HTTP untuk redirect.

    Salah satu301302307308
  • configurationobject

    Pengaturan tambahan link. Bisa dibaca di sini; perubahannya dilakukan di dashboard.

    • forwardingobject

      Meneruskan parameter query link pendek ke tujuan.

      • isActiveboolean

        Apakah penerusan aktif.

      • modestring

        ALL meneruskan semua parameter. ALLOWLIST hanya meneruskan key di bawah.

        Salah satuALLALLOWLIST
      • keysarray<string>

        Parameter yang diteruskan pada mode ALLOWLIST.

      • overwriteboolean

        Apakah parameter yang diteruskan menggantikan parameter yang sudah ada di tujuan.

    • rulesobject

      Aturan redirect.

      • timezonestring
      • listarray<object>
        • idstring

          Id unik link.

        • destinationstringURL
    • protectionobject

      Perlindungan akses.

      • passwordboolean

        Apakah link meminta password. Password tidak pernah dikembalikan.

    • cloakingobjectopsional

      Pengaturan pratinjau link, ada jika dikonfigurasi.

      • isActiveboolean

        Apakah pratinjau kustom aktif.

  • urlstringURL

    Link 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}
Contoh
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}'
Response

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"
}
DELETE/v1/links/{id}

Hapus link

Menonaktifkan link, sehingga berhenti mengalihkan tetapi analitiknya tetap ada. Tambahkan hard=true untuk menghapusnya selamanya.

Scope yang dibutuhkanlinks.delete

Parameter path

  • idstringIDWajib

    Id link.

Parameter query

  • hardbooleanOpsional

    Isi true untuk menghapus link beserta analitiknya. Ini tidak bisa dibatalkan.

    Bawaan false

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}
Contoh
curl -X DELETE "https://www.hootmix.com/api/v1/links/6650f1c2a1b2c3d4e5f60718" \
  -H "Authorization: Bearer $HOOTMIX_API_KEY"
Response

204 No Content

Tanpa isi response
GET/v1/links/{id}/stats

Ambil analitik link

Mengembalikan klik, pengunjung, deret waktu, dan rincian untuk satu link.

Scope yang dibutuhkananalytics.read

Parameter path

  • idstringIDWajib

    Id link.

Parameter query

  • daysintegerOpsional

    Rentang laporan.

    Salah satu173090Bawaan 7
  • tagstringOpsional

    Hanya hitung event yang diberi tag ini.

    Maks 60

Response

200Isi response:

  • visitsinteger

    Total klik dalam periode.

  • visitorsobject

    Jumlah pengunjung.

    • uniqueinteger

      Pengunjung berbeda dalam periode.

  • tagsarray<object>

    Klik dikelompokkan menurut tag yang dimilikinya. Klik dengan dua tag dihitung di keduanya.

    • _idstring

      Nilai yang dihitung, misalnya nama browser.

    • countinteger

      Jumlah klik.

  • seriesarray<object>

    Klik dari waktu ke waktu. Satu titik per jam untuk rentang 1 hari, selain itu satu per hari.

    • timestringISO 8601

      Awal periode.

    • availableboolean

      False untuk periode sebelum analitik dicatat.

    • visitsinteger

      Klik pada periode itu.

  • breakdownsobject

    Klik dikelompokkan menurut dimensi umum. Setiap daftar diurutkan menurut jumlah.

    • sourcesarray<object>

      Situs perujuk, atau Direct / unknown.

      • _idstring

        Nilai yang dihitung, misalnya nama browser.

      • countinteger

        Jumlah klik.

    • devicesarray<object>

      Desktop, Mobile atau Tablet.

      • _idstring

        Nilai yang dihitung, misalnya nama browser.

      • countinteger

        Jumlah klik.

    • browsersarray<object>

      Nama browser.

      • _idstring

        Nilai yang dihitung, misalnya nama browser.

      • countinteger

        Jumlah klik.

    • outcomesarray<object>

      Untuk smart link, bagaimana pengunjung diteruskan.

      • _idstring

        Nilai yang dihitung, misalnya nama browser.

      • countinteger

        Jumlah klik.

    • attemptsarray<object>

      Untuk smart link, tujuan yang dicoba.

      • _idstring

        Nilai yang dihitung, misalnya nama browser.

      • countinteger

        Jumlah klik.

    • openingsarray<object>

      Untuk smart link, apakah aplikasi tampak terbuka.

      • _idstring

        Nilai yang dihitung, misalnya nama browser.

      • countinteger

        Jumlah klik.

  • detailsobject

    Dimensi lain, setiap daftar dibatasi 10 teratas.

    • geoobject

      Lokasi pengunjung.

      • countryCodesarray<object>

        Klik per kode negara.

        • _idstring

          Nilai yang dihitung, misalnya nama browser.

        • countinteger

          Jumlah klik.

      • regionsarray<object>

        Klik per negara dan wilayah.

        • _idstring

          Nilai yang dihitung, misalnya nama browser.

        • countinteger

          Jumlah klik.

      • citiesarray<object>

        Klik per negara dan kota.

        • _idstring

          Nilai yang dihitung, misalnya nama browser.

        • countinteger

          Jumlah klik.

    • agentobject

      Yang dipakai pengunjung.

      • osarray<object>

        Nama sistem operasi.

        • _idstring

          Nilai yang dihitung, misalnya nama browser.

        • countinteger

          Jumlah klik.

    • referrerobject

      Asal pengunjung.

      • urlsarray<object>

        Halaman perujuk tanpa query string.

        • _idstring

          Nilai yang dihitung, misalnya nama browser.

        • countinteger

          Jumlah klik.

    • utmobject

      Parameter kampanye pada link pendek.

      • sourcearray<object>

        Nilai utm_source.

        • _idstring

          Nilai yang dihitung, misalnya nama browser.

        • countinteger

          Jumlah klik.

      • mediumarray<object>

        Nilai utm_medium.

        • _idstring

          Nilai yang dihitung, misalnya nama browser.

        • countinteger

          Jumlah klik.

      • campaignarray<object>

        Nilai utm_campaign.

        • _idstring

          Nilai yang dihitung, misalnya nama browser.

        • countinteger

          Jumlah klik.

  • cutoffstringISO 8601

    Akhir periode, yaitu saat stats dibuat.

  • historyobject

    Apakah periode tercatat seluruhnya.

    • sincestringISO 8601nullable

      Kapan pencatatan analitik dimulai, atau null jika seluruh periode tercakup.

    • isPartialboolean

      True 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}/stats
Contoh
curl -X GET "https://www.hootmix.com/api/v1/links/6650f1c2a1b2c3d4e5f60718/stats?days=7" \
  -H "Authorization: Bearer $HOOTMIX_API_KEY"
Response

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
  }
}
GET/v1/events

Daftar event

Mengembalikan event klik, terbaru lebih dulu. Bot tidak disertakan.

Scope yang dibutuhkanevents.read

Parameter query

  • limitintegerOpsional

    Jumlah event yang dikembalikan.

    Bawaan 20Min 1Maks 100
  • cursorstringOpsional

    cursor.next dari halaman sebelumnya.

  • linkIdstringIDOpsional

    Hanya event dari link ini.

  • tagstringOpsional

    Hanya event dengan tag ini.

    Maks 60

Response

200Isi response:

  • dataarray<object>
    • idstring

      Id unik event. Pakai untuk membaca dan memberi tag pada event.

    • linkIdstringID

      Link yang diklik.

    • createdAtstringISO 8601

      Waktu klik terjadi.

    • tagsarray<string>

      Tag pada event ini. Kosong sampai kamu memberinya tag.

      Maks 10
    • devicestringnullable

      Desktop, Mobile atau Tablet.

    • browserstringnullable

      Nama browser.

    • osstringnullable

      Nama sistem operasi.

    • referrerstringURLnullable

      Halaman asal pengunjung, tanpa query string.

    • geoobject

      Lokasi pengunjung.

      • countryCodestringnullable

        Kode negara ISO 3166-1 alpha-2.

      • regionstringnullable

        Wilayah.

      • citystringnullable

        Kota.

    • visitorobject

      Pengunjung di balik klik.

      • idstringnullable

        Id anonim pengunjung, disimpan di cookie first-party.

      • isUniquebooleannullable

        True saat pengunjung ini pertama kali mengeklik link ini.

    • utmobject

      Parameter kampanye pada link pendek.

      • sourcestringnullable

        Nilai utm_source.

      • mediumstringnullable

        Nilai utm_medium.

      • campaignstringnullable

        Nilai 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/events
Contoh
curl -X GET "https://www.hootmix.com/api/v1/events?limit=20" \
  -H "Authorization: Bearer $HOOTMIX_API_KEY"
Response

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
  }
}
GET/v1/events/{id}

Ambil event

Mengembalikan satu event klik berdasarkan id yang dikirim webhook klik.

Scope yang dibutuhkanevents.read

Parameter path

  • idstringWajib

    Id event. Ini adalah data.event.id di webhook klik.

Response

200Isi response:

  • idstring

    Id unik event. Pakai untuk membaca dan memberi tag pada event.

  • linkIdstringID

    Link yang diklik.

  • createdAtstringISO 8601

    Waktu klik terjadi.

  • tagsarray<string>

    Tag pada event ini. Kosong sampai kamu memberinya tag.

    Maks 10
  • devicestringnullable

    Desktop, Mobile atau Tablet.

  • browserstringnullable

    Nama browser.

  • osstringnullable

    Nama sistem operasi.

  • referrerstringURLnullable

    Halaman asal pengunjung, tanpa query string.

  • geoobject

    Lokasi pengunjung.

    • countryCodestringnullable

      Kode negara ISO 3166-1 alpha-2.

    • regionstringnullable

      Wilayah.

    • citystringnullable

      Kota.

  • visitorobject

    Pengunjung di balik klik.

    • idstringnullable

      Id anonim pengunjung, disimpan di cookie first-party.

    • isUniquebooleannullable

      True saat pengunjung ini pertama kali mengeklik link ini.

  • utmobject

    Parameter kampanye pada link pendek.

    • sourcestringnullable

      Nilai utm_source.

    • mediumstringnullable

      Nilai utm_medium.

    • campaignstringnullable

      Nilai 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"
Response

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"
  }
}
PUT/v1/events/{id}/tags

Beri tag pada event

Menetapkan tag satu event klik. Ini menggantikan tag yang ada sekarang.

Scope yang dibutuhkanevents.write

Parameter path

  • idstringWajib

    Id event. Ini adalah data.event.id di webhook klik.

Isi request

  • tagsarray<string>Wajib

    Tag untuk event ini. Kirim daftar kosong untuk menghapus semuanya. Tag baru dibuatkan otomatis.

    Maks 10

Response

200Isi response:

  • idstring

    Id unik event. Pakai untuk membaca dan memberi tag pada event.

  • linkIdstringID

    Link yang diklik.

  • createdAtstringISO 8601

    Waktu klik terjadi.

  • tagsarray<string>

    Tag pada event ini. Kosong sampai kamu memberinya tag.

    Maks 10
  • devicestringnullable

    Desktop, Mobile atau Tablet.

  • browserstringnullable

    Nama browser.

  • osstringnullable

    Nama sistem operasi.

  • referrerstringURLnullable

    Halaman asal pengunjung, tanpa query string.

  • geoobject

    Lokasi pengunjung.

    • countryCodestringnullable

      Kode negara ISO 3166-1 alpha-2.

    • regionstringnullable

      Wilayah.

    • citystringnullable

      Kota.

  • visitorobject

    Pengunjung di balik klik.

    • idstringnullable

      Id anonim pengunjung, disimpan di cookie first-party.

    • isUniquebooleannullable

      True saat pengunjung ini pertama kali mengeklik link ini.

  • utmobject

    Parameter kampanye pada link pendek.

    • sourcestringnullable

      Nilai utm_source.

    • mediumstringnullable

      Nilai utm_medium.

    • campaignstringnullable

      Nilai utm_campaign.

Catatan

  • Panggil ini dari server yang menerima webhook klik, dengan data.event.id sebagai id.
  • Tag berupa huruf kecil dan tidak boleh mengandung koma. Satu event bisa punya maksimal 10 tag, dan satu workspace maksimal 50 tag berbeda.
  • Event yang diberi tag muncul di analitik. Pakai parameter tag pada Ambil analitik link atau Daftar event untuk memfilter.

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.
PUT /v1/events/{id}/tags
Contoh
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"]}'
Response

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"
  }
}
GET/v1/folders

Daftar folder

Mengembalikan semua folder di workspace. Pakai parentId untuk menyusun ulang pohon.

Scope yang dibutuhkanfolders.read

Response

200Isi response:

  • dataarray<object>
    • idstringID

      Id unik folder.

    • parentIdstringIDnullable

      Folder induk, atau null di tingkat atas.

    • namestring

      Nama 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/folders
curl -X GET "https://www.hootmix.com/api/v1/folders" \
  -H "Authorization: Bearer $HOOTMIX_API_KEY"
Response

200 OK

{
  "data": [
    {
      "id": "6650f0ccc1b2c3d4e5f60003",
      "parentId": null,
      "name": "Campaigns"
    },
    {
      "id": "6650f0ddd1b2c3d4e5f60004",
      "parentId": "6650f0ccc1b2c3d4e5f60003",
      "name": "Autumn"
    }
  ]
}
GET/v1/tags

Daftar tag

Mengembalikan tag di workspace. Tag ada setelah kamu memberi tag pada event, atau membuatnya di halaman Tag.

Scope yang dibutuhkanlinks.read

Response

200Isi response:

  • dataarray<object>
    • namestring

      Nama tag. Huruf kecil.

    • createdAtstringISO 8601

      Waktu tag dibuat.

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/tags
curl -X GET "https://www.hootmix.com/api/v1/tags" \
  -H "Authorization: Bearer $HOOTMIX_API_KEY"
Response

200 OK

{
  "data": [
    {
      "name": "launch",
      "createdAt": "2026-10-01T10:00:00.000Z"
    },
    {
      "name": "newsletter",
      "createdAt": "2026-10-02T09:15:00.000Z"
    }
  ]
}
GET/v1/domains

Daftar domain

Mengembalikan domain yang bisa dipakai untuk membuat link.

Scope yang dibutuhkandomains.read

Response

200Isi response:

  • dataarray<object>
    • idstringID

      Id unik domain.

    • hostnamestring

      Hostname.

    • kindstring

      Domain 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/domains
curl -X GET "https://www.hootmix.com/api/v1/domains" \
  -H "Authorization: Bearer $HOOTMIX_API_KEY"
Response

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.

Node.js
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));
};
Python
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)
PHP
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.
Webhook

link.clicked

Pengunjung mengeklik link pendek. Klik dari bot tidak dikirim.

Payload

  • idstring

    Id unik notifikasi ini. Tetap sama saat dicoba ulang dan di semua endpoint kamu, jadi pakai untuk mengabaikan duplikat.

  • eventstring

    Klik tersebut.

    Salah satulink.clicked
  • createdAtstringISO 8601

    Waktu notifikasi dibuat.

  • dataobject

    Apa yang terjadi. Propertinya bergantung pada event.

    • linkobject

      Link yang diklik.

      • idstringID

        Id link.

      • urlstringURL

        Link pendek.

      • slugstring

        Path setelah domain.

    • eventobject

      Klik tersebut.

      • idstring

        Id event klik. Pakai dengan API untuk membaca atau memberi tag pada event.

      • visitorIdstring

        Id anonim pengunjung, disimpan di cookie first-party.

      • isUniqueboolean

        True saat pengunjung ini pertama kali mengeklik link ini.

      • countryCodestringnullable

        Kode negara ISO 3166-1 alpha-2, jika diketahui.

      • regionstringnullable

        Wilayah, jika diketahui.

      • citystringnullable

        Kota, jika diketahui.

      • devicestringnullable

        Desktop, Mobile atau Tablet.

      • browserstringnullable

        Nama browser.

      • osstringnullable

        Nama sistem operasi.

      • referrerstringURLnullable

        Halaman asal pengunjung, tanpa query string.

      • utmobject

        Parameter kampanye pada link pendek.

        • sourcestringnullable

          Nilai utm_source.

        • mediumstringnullable

          Nilai utm_medium.

        • campaignstringnullable

          Nilai 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"
      }
    }
  }
}
Webhook

link.created

Link dibuat, dari dashboard, impor, atau API.

Payload

  • idstring

    Id unik notifikasi ini. Tetap sama saat dicoba ulang dan di semua endpoint kamu, jadi pakai untuk mengabaikan duplikat.

  • eventstring

    Nama event. Juga ada di header X-Hootmix-Event.

    Salah satulink.created
  • createdAtstringISO 8601

    Waktu notifikasi dibuat.

  • dataobject

    Apa yang terjadi. Propertinya bergantung pada event.

    • linkobject

      Link yang dimaksud.

      • idstringID

        Id link.

      • urlstringURL

        Link pendek.

      • slugstring

        Path setelah domain.

      • modestring

        Tipe redirect.

        Salah satuREDIRECTDEVICESMARTSPLIT
      • statusstring

        active atau disabled.

        Salah satuactivedisabled
      • folderIdstringIDnullable

        Folder 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"
    }
  }
}
Webhook

link.updated

Link berubah: tujuan, slug, status, atau foldernya.

Payload

  • idstring

    Id unik notifikasi ini. Tetap sama saat dicoba ulang dan di semua endpoint kamu, jadi pakai untuk mengabaikan duplikat.

  • eventstring

    Nama event. Juga ada di header X-Hootmix-Event.

    Salah satulink.updated
  • createdAtstringISO 8601

    Waktu notifikasi dibuat.

  • dataobject

    Apa yang terjadi. Propertinya bergantung pada event.

    • linkobject

      Link yang dimaksud.

      • idstringID

        Id link.

      • urlstringURL

        Link pendek.

      • slugstring

        Path setelah domain.

      • modestring

        Tipe redirect.

        Salah satuREDIRECTDEVICESMARTSPLIT
      • statusstring

        active atau disabled.

        Salah satuactivedisabled
      • folderIdstringIDnullable

        Folder 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"
    }
  }
}
Webhook

link.deleted

Link dihapus. Hanya id dan slug yang dikirim, karena link sudah tidak ada.

Payload

  • idstring

    Id unik notifikasi ini. Tetap sama saat dicoba ulang dan di semua endpoint kamu, jadi pakai untuk mengabaikan duplikat.

  • eventstring

    Nama event. Juga ada di header X-Hootmix-Event.

    Salah satulink.deleted
  • createdAtstringISO 8601

    Waktu notifikasi dibuat.

  • dataobject

    Apa yang terjadi. Propertinya bergantung pada event.

    • linkobject

      Link yang dimaksud.

      • idstringID

        Id link.

      • slugstring

        Path 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

webhook.test

Dikirim saat kamu menekan Kirim tes pada endpoint, untuk memastikan endpoint berfungsi.

Payload

  • idstring

    Id unik notifikasi ini. Tetap sama saat dicoba ulang dan di semua endpoint kamu, jadi pakai untuk mengabaikan duplikat.

  • eventstring

    Nama event. Juga ada di header X-Hootmix-Event.

    Salah satuwebhook.test
  • createdAtstringISO 8601

    Waktu notifikasi dibuat.

  • dataobject

    Kosong untuk notifikasi tes.

    POST endpoint kamu
    {
      "id": "9d2f6c1e-7a4b-4e0d-8f53-2c1b6a9e4d70",
      "event": "webhook.test",
      "createdAt": "2026-10-19T08:31:12.000Z",
      "data": {}
    }