Addon

Endpoint API Addon — Publik & Header Kustom

Membuat satu endpoint API addon bisa dipanggil tanpa token AlurKerja, dan meneruskan header pemanggil (mis. x-token) ke script/REST addon

Selain actions (dipanggil dari Service Task BPMN — lihat Pembuatan Addon pada AlurKerja), satu addon juga bisa mendeklarasikan blok apis di index.json: endpoint API milik addon itu sendiri, dipanggil langsung oleh pihak eksternal (bukan lewat BPMN). Secara default endpoint ini tetap butuh token AlurKerja seperti endpoint lain — halaman ini soal dua pengecualian opt-in per endpoint:

  • public — satu endpoint apis bisa dipanggil tanpa token AlurKerja sama sekali.
  • allowed-headers — header yang dikirim pemanggil (mis. x-token) diteruskan ke eksekusi addon, supaya addon publik bisa mengamankan dirinya sendiri.

Halaman ini melanjutkan Pembuatan Addon pada AlurKerja: struktur addon dan kontrak run(ctx) di sana tetap berlaku. Kalau addon-nya juga memakai ctx.svc untuk memanggil balik AlurKerja, itu topik terpisah — lihat AlurKerja Python SDK untuk Script Addon; ctx.svc hanya ada di jalur Service Task BPMN, tidak pernah di jalur apis yang dibahas di sini.

1. Cara Kerja

Pemanggil eksternal (tanpa token AlurKerja)
   │        header: x-token: <secret>
   ▼
{ANY} /api/v1/integration/addons/{addon}/{tenant_setting_id}/api/{action}
   │
   ▼
integration-service
   1. Tidak ada Authorization header sama sekali?
      → diteruskan TANPA identitas, HANYA untuk bentuk path ini
   2. Baca baris addon + endpoint `action` dari database
   3. index.json apis.<action>.public == true ?
      YA  → lanjut, tanpa syarat token
      TIDAK → 401 Authorization header required
   4. Salin header yang terdaftar di apis.<action>.allowed-headers
   │
   ▼
python3 scripts/<endpoint>/<endpoint>.py --run <ctx.json>
   ctx["headers"] = { "x-token": "<secret>" }
   │
   ▼
Script memvalidasi x-token sendiri, lalu jalankan logikanya

Hal yang perlu diingat:

  • Per endpoint, bukan per addon. Endpoint lain di addon yang sama yang tidak menuliskan public tetap butuh token seperti biasa — defaultnya public: false kalau key-nya tidak ada di index.json. Menambahkan public di satu endpoint tidak membuka endpoint lain.
  • Pemanggil yang tetap mengirim token AlurKerja tidak dirugikan maupun diistimewakan. Token yang valid tetap divalidasi dan tetap membawa parameters.user_token seperti biasa (lihat Bagian 3); token yang salah tetap ditolak 401 — public: true tidak pernah menurunkan token yang salah jadi permintaan anonim yang diloloskan.
  • Platform tidak lagi memeriksa siapa pemanggilnya untuk endpoint yang public. Kalau addon perlu membatasi siapa yang boleh memanggil, addon sendiri yang mengamankannya — pola yang dipakai adalah shared secret di header kustom (lihat Bagian 2 dan 4).
  • Berlaku hanya untuk endpoint di blok apis, dipanggil lewat .../api/{action}. actions (Service Task BPMN) tidak terpengaruh sama sekali oleh public/allowed-headers.

2. Opt-in di index.json

Tambahkan public dan/atau allowed-headers di definisi satu endpoint, di dalam blok apis:

{
  "apis": {
    "get_record_by_email": {
      "name": "Get Record By Email API",
      "description": "Ambil record berdasarkan email, dipanggil sistem eksternal.",
      "type": "SCRIPT",
      "endpoint": "get_record_by_email",
      "public": true,
      "allowed-headers": ["x-token"]
    }
  }
}
KeyWajib?Arti
publicTidak, default falsetrue = endpoint ini bisa dipanggil tanpa Authorization header sama sekali
allowed-headersTidak, default kosongDaftar nama header yang diteruskan ke eksekusi addon. Cocok tanpa memandang huruf besar/kecil

Mendaftarkan "Authorization" di allowed-headers tidak berefek apa pun — nilai itu tetap hanya lewat parameters.user_token, tidak pernah digandakan ke ctx["headers"]["Authorization"]. Satu token, satu jalur, satu nama.

Nilai public/allowed-headers disimpan saat addon di-install atau di-publish — addon yang sudah terpasang sebelum field ini ditambahkan harus dipublish ulang.

3. Isi ctx yang Diterima Script

{
  "variables": {},
  "parameters": {
    "user_token": ""
  },
  "configuration": {},
  "runkey": "api-exec-1789123456789-get_record_by_email",
  "headers": {
    "x-token": "secret-dari-pemanggil"
  }
}
FieldKeterangan
parameters.user_tokenToken AlurKerja milik pemanggil TANPA prefix Bearer . Kosong ("") kalau pemanggil tidak mengirim Authorization — normal untuk endpoint public.
headersHANYA berisi header yang terdaftar di allowed-headers DAN benar-benar dikirim pemanggil. Header yang tidak terdaftar tidak pernah muncul di sini, dan header yang terdaftar tapi tidak dikirim TIDAK muncul sebagai key kosong — script harus cek keberadaan key-nya, bukan menganggap selalu ada.

headers hanya ada di jalur apis (.../api/{action}). Jalur Service Task BPMN (actions, .../execute/{action}) tidak mengenal allowed-headers — tidak ada request HTTP masuk untuk diambil headernya di jalur itu.

4. Contoh: Endpoint Publik dengan Shared Secret

4.1 Script

def run(ctx):
    headers = ctx.get("headers") or {}
    token = headers.get("x-token", "")

    # Simpan secret ini di config addon (bukan di kode) saat setup, mis. lewat
    # tenant_settings addon. Dibandingkan dengan konstanta waktu-tetap kalau
    # butuh lebih ketat dari perbandingan string biasa.
    expected = (ctx.get("configuration") or {}).get("shared_secret", "")

    if not token or token != expected:
        return {"status": 401, "data": {"message": "Token tidak valid"}}

    email = (ctx.get("parameters") or {}).get("email", "")
    if not email:
        return {
            "status": 400,
            "data": {"message": "Parameter 'email' wajib diisi"},
        }

    # ... ambil record dari master data, dsb.
    record = {"email": email, "status": "found"}

    return {"status": "ok", "data": record}

Field top-level status di sini adalah kanal khusus jalur API — "ok"/integer 100–599 dipetakan langsung jadi HTTP status response. Lihat penjelasan lengkapnya di dokumen backend ADDON_ACTION_EXECUTION_API.md (bagian "API Type Action") kalau perlu detail pemetaannya.

4.2 Panggilan dari Luar

Tanpa token AlurKerja sama sekali — cukup shared secret di header:

curl -X GET \
  "https://<host>/api/v1/integration/addons/telegram-account/42/api/get_record_by_email?email=user@example.com" \
  -H "x-token: secret-dari-pemanggil"

5. Endpoint Tipe REST

Untuk apis.<key>.type bernilai "REST" (bukan "SCRIPT"), allowed-headers diteruskan sebagai header HTTP ke request upstream addon — menimpa nilai statis yang sama dari konfigurasi addon kalau ada, karena allowed-headers mewakili apa yang pemanggil kirim untuk request itu, bukan nilai tetap.

{
  "apis": {
    "hello": {
      "type": "REST",
      "method": "GET",
      "endpoint": "/echo",
      "public": true,
      "allowed-headers": ["x-token"]
    }
  }
}

6. Aturan Keamanan

LakukanHindari
Simpan shared secret di konfigurasi addon (configuration/tenant_settings), bukan hardcode di scriptMembandingkan header ke string yang ditulis langsung di kode sumber
Set public: true cuma di endpoint yang memang perlu dipanggil tanpa token AlurKerjaMengaktifkan public di seluruh apis "supaya gampang"
Validasi headers di awal run(ctx), tolak sebelum baca parameters/configuration lainMempercayai ctx["headers"] tanpa validasi apa pun karena "kan sudah lewat allowed-headers" — allowed-headers cuma mengatur PENERUSAN, bukan VALIDASI
Daftarkan cuma header yang benar-benar dipakai script di allowed-headersMendaftarkan header secara longgar (mis. seluruh header custom) tanpa alasan

7. Troubleshooting

GejalaPenyebabSolusi
Selalu 401 Authorization header required walau sudah set public: trueAddon belum dipublish ulang setelah menambahkan publicPublish ulang addon
ctx["headers"] selalu kosong walau header sudah dikirimNama header tidak terdaftar di allowed-headers, atau salah ejaCocokkan persis nama header yang didaftarkan (tidak case-sensitive, tapi harus sama karakternya)
ctx["headers"]["Authorization"] selalu tidak ada walau Authorization didaftarkan di allowed-headersMemang disengaja — Authorization tidak pernah digandakan ke headersBaca token pemanggil dari parameters.user_token, bukan headers
Endpoint lain di addon yang sama jadi ikut publikTidak mungkin dari fitur ini — public per endpoint. Periksa apakah endpoint lain juga menuliskan public: true sendiriHapus public dari endpoint yang seharusnya tetap butuh token