Quick Start
Tambahkan satu baris script tag ke halaman HTML Anda. Widget akan otomatis muncul sebagai floating button di kanan bawah halaman.
<script
src="https://cdn.ztakonai.com"
data-widget-id="wgt_abc123"
data-api-key="tk_live_xxxx">
</script>htmlScript Tag Attributes
| Attribute | Required | Description |
|---|---|---|
data-widget-id* | string | Widget ID dari TakonAI dashboard (format: wgt_...) |
data-api-key* | string | Public API key dari TakonAI dashboard (format: tk_live_...) |
data-base-url | string | Override URL widget — hanya untuk development/staging. Default: https://cdn.ztakonai.com |
Embed Guide
Widget bekerja dengan menginjeksi sebuah <iframe> ke halaman Anda. Komunikasi antara halaman host dan widget dilakukan via postMessage.
Cara Kerja
- Script tag loader dieksekusi saat halaman load.
- Loader membuat floating bubble button (fixed, bottom-right, z-index 9990).
- Saat user klik bubble, iframe
/embeddiinjeksi dan chat panel dibuka. - Iframe berkomunikasi dengan halaman host via
postMessage. window.Takonaitersedia untuk kontrol programmatic setelah script dimuat.
Inisialisasi dengan User Context
Panggil window.Takonai.init() setelah halaman selesai dimuat untuk menghubungkan widget dengan sesi user Anda.
window.Takonai.onReady = () => {
window.Takonai.init({
externalId: 'user_123', // ID unik user dari sistem Anda
currentStep: 1, // Step aktif saat ini (opsional)
context: { // Data konteks tambahan (opsional)
planType: 'pro',
cartTotal: 150000,
},
});
};jsMengelola Banyak Step (Multi-Step)
Untuk halaman yang memiliki urutan step — seperti form checkout atau pendaftaran wizard — Anda dapat memisahkan konfigurasi form menjadi beberapa step di dashboard TakonAI.
Di sisi frontend, Anda perlu memberitahu widget setiap kali user berpindah step menggunakan setStep(). Dengan cara ini, AI hanya memproses Tool/Form Filling yang sesuai dengan form di step yang sedang aktif.
Cara kerja multi-step
- Buat konfigurasi widget di dashboard dengan beberapa step, masing-masing memiliki form yang berbeda.
- Saat halaman pertama dimuat, panggil
init({ currentStep: 1 }). - Setiap kali user pindah ke step berikutnya, panggil
setStep(n)agar AI tahu step mana yang aktif. - AI hanya akan mengisi form di step yang sedang aktif — tidak ada kebocoran data antar step.
// Step 1 — saat widget siap
window.Takonai.onReady = () => {
window.Takonai.init({
externalId: 'usr_123',
currentStep: 1,
});
};
// Step 2 — saat user klik tombol "Lanjut"
function goToStep2() {
showStep(2); // tampilkan form step 2 di halaman Anda
window.Takonai.setStep(2, {
// opsional: kirim data dari step sebelumnya sebagai konteks
buyerName: document.querySelector('[name="full_name"]').value,
});
}
// Step 3 — opsional, lanjut ke step berikutnya
function goToStep3() {
showStep(3);
window.Takonai.setStep(3);
}jsGunakan callback onFill untuk mengisi form yang tepat berdasarkan step yang dikirim AI:
window.Takonai.onFill = ({ step, formName, data }) => {
// Pilih form yang sesuai dengan step aktif
const formMap = {
1: document.getElementById('form-buyer'),
2: document.getElementById('form-shipping'),
3: document.getElementById('form-payment'),
};
const formEl = formMap[step];
if (!formEl) return;
Object.entries(data).forEach(([field, value]) => {
const el = formEl.querySelector('[name="' + field + '"]');
if (el) el.value = value;
});
};jswindow.Takonai
Global object yang di-expose oleh widget loader script. Tersedia setelah script tag dimuat.
init(opts)
MethodInisialisasi widget dengan konteks user. Harus dipanggil di dalam callback onReady agar iframe siap menerima pesan. Widget akan mengirim TAKONAI_INIT ke iframe dan menerima konfirmasi TAKONAI_INIT_ACK.
window.Takonai.init(opts: TakonaiInitOptions): void
interface TakonaiInitOptions {
externalId: string; // Required — ID user dari sistem Anda
currentStep?: number; // Optional — step aktif (default: 1)
context?: Record<string, unknown>; // Optional — data konteks dinamis
welcomeMessage?: string; // Optional — override pesan sapaan dari dashboard
}tsParameters
| Name | Type | Description |
|---|---|---|
externalId* | string | ID unik user dari sistem Anda. Digunakan untuk identifikasi sesi. |
currentStep | number | Step aktif saat init. Default: 1. |
context | object | Data konteks bebas yang diteruskan ke AI (kategori produk, nilai form, dll). |
welcomeMessage | string | Override pesan sapaan yang dikonfigurasi di dashboard. Berguna untuk personalisasi per-user atau per-halaman. |
Example
window.Takonai.onReady = () => {
window.Takonai.init({
externalId: 'usr_4891',
currentStep: 2,
context: {
category: 'electronics',
priceRange: '500k-1jt',
},
welcomeMessage: 'Halo, Budi! Ada yang bisa kami bantu hari ini?',
});
};jssetStep(step, context?)
MethodUpdate step aktif widget, misalnya saat user berpindah halaman atau mengisi form multi-step. Mengirim pesan TAKONAI_STEP_CHANGED ke iframe.
window.Takonai.setStep(step: number, context?: Record<string, unknown>): voidtsParameters
| Name | Type | Description |
|---|---|---|
step* | number | Nomor step baru (1-indexed, sesuai konfigurasi widget di dashboard). |
context | object | Konteks baru yang akan menggantikan konteks sebelumnya. |
// User pindah ke step checkout pengiriman
window.Takonai.setStep(2, {
selectedItems: ['item_001', 'item_002'],
total: 320000,
});jssetContext(context)
MethodUpdate konteks tanpa mengubah step aktif. Berguna saat data halaman berubah tapi posisi step tidak berubah. Mengirim TAKONAI_CONTEXT_UPDATE.
window.Takonai.setContext(context: Record<string, unknown>): voidts// User memilih produk lain tanpa pindah step
window.Takonai.setContext({
selectedProduct: 'SKU-9921',
color: 'black',
size: 'XL',
});jsContoh: Validasi Data Form
Gunakan setContext untuk mengirim data yang sudah diisi user ke widget. AI akan mengetahui isi form saat ini, sehingga bisa menjawab pertanyaan seperti "apakah data saya sudah benar?" tanpa user perlu mengetik ulang.
// Kirim data form setiap kali ada perubahan (gunakan 'change' bukan 'input'
// agar tidak terlalu sering mengirim pesan ke widget)
document.getElementById('checkout-form').addEventListener('change', () => {
window.Takonai.setContext({
form_full_name: document.querySelector('[name="full_name"]').value,
form_email: document.querySelector('[name="email"]').value,
form_phone: document.querySelector('[name="phone"]').value,
form_address: document.querySelector('[name="address"]').value,
});
});
// User bisa bertanya:
// "apakah email saya sudah benar?" → AI tahu nilainya dari context
// "cek nomor HP saya" → AI baca form_phone dari contextjsTips
- Gunakan event
changeataublur(bukaninput) agar tidak mengirim terlalu banyak update ke widget. - Prefix key dengan
form_untuk memudahkan AI membedakan data form dari konteks lain. - Jangan kirim data sensitif seperti password atau nomor kartu kredit.
open() / close()
MethodBuka atau tutup chat panel secara programmatic, tanpa user harus klik bubble button.
window.Takonai.open(): void
window.Takonai.close(): voidts// Buka widget otomatis setelah 5 detik
setTimeout(() => {
window.Takonai.open();
}, 5000);
// Tutup widget setelah form selesai diisi
window.Takonai.onFill = (payload) => {
fillMyForm(payload.data);
window.Takonai.close();
};jsonFill(payload)
CallbackDipanggil ketika AI berhasil menjalankan sebuah tool (tool use selesai). formName adalah nama tool yang dipanggil, dan data adalah JSON payload sesuai schema yang Anda definisikan di dashboard. Anda bebas menggunakan payload ini untuk apapun — mengisi form HTML, memperbarui state aplikasi, memanggil API backend, atau memicu aksi UI lainnya.
window.Takonai.onFill = (payload: TakonaiFillPayload) => void
interface TakonaiFillPayload {
step: number; // Step yang aktif saat tool dipanggil
formName: string; // Nama tool (dari konfigurasi widget)
data: Record<string, unknown>; // JSON payload hasil tool call AI
}tsParameters
| Field | Type | Description |
|---|---|---|
step | number | Nomor step yang baru saja di-fill oleh AI. |
formName | string | Nama form sesuai konfigurasi widget di dashboard. |
data | object | Key-value hasil isian AI. Key sesuai field name di konfigurasi form. |
Example
window.Takonai.onFill = ({ step, formName, data }) => {
// Contoh 1: isi form HTML seperti biasa
if (formName === 'form_checkout') {
Object.entries(data).forEach(([field, value]) => {
const el = document.querySelector(`[name="${field}"]`);
if (el) el.value = value;
});
}
// Contoh 2: langsung panggil API backend
if (formName === 'create_booking') {
fetch('/api/booking', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
});
}
// Contoh 3: update state aplikasi (React, Vue, dsb)
if (formName === 'add_to_cart') {
store.dispatch('cart/add', { sku: data.sku, qty: data.qty });
}
// Contoh 4: navigasi
if (formName === 'navigate') {
router.push(data.path);
}
};jsonReady()
CallbackDipanggil ketika widget iframe telah selesai dimuat dan siap menerima komunikasi. Anda wajib memanggil init() di dalam callback ini.
window.Takonai.onReady = () => voidtsExample
window.Takonai.onReady = () => {
console.log('Widget siap digunakan!');
window.Takonai.init({ externalId: 'usr_123' });
};jsonError(payload)
CallbackDipanggil ketika terjadi error di dalam widget (streaming gagal, config tidak ditemukan, dll).
window.Takonai.onError = (payload: TakonaiErrorPayload) => void
interface TakonaiErrorPayload {
code: string; // Error code, contoh: 'STREAM_ERROR', 'CONFIG_NOT_FOUND'
message: string; // Pesan error human-readable
}tswindow.Takonai.onError = ({ code, message }) => {
console.error('[TakonAI]', code, message);
// Log ke Sentry, tampilkan fallback UI, dll
};jssendImage(url)
MethodLampirkan gambar dari URL publik ke composer chat widget secara programatik. Gambar belum dikirim sampai user mengetik pesan dan menekan tombol Send — sehingga Anda bisa pra-lampirkan gambar produk sebelum user mulai chat.
URL harus menggunakan skema https:// dan dapat diakses publik, karena Anthropic akan men-fetch URL tersebut langsung saat memproses pesan.
window.Takonai.sendImage(url: string): voidtsParameters
| Name | Type | Description |
|---|---|---|
url* | string | URL gambar publik (https:// wajib). Tidak mendukung base64 atau URL yang memerlukan autentikasi. |
Example
// Pra-lampirkan foto produk saat user membuka detail produk
window.Takonai.sendImage('https://cdn.toko.com/products/kaos-putih.jpg');
// User bisa langsung tanya "berapa harga ini?" dan AI sudah bisa melihat gambarnyajsCatatan
- Maksimal 3 gambar per pesan. Memanggil
sendImagesaat sudah mencapai batas akan diabaikan. - Gambar yang sudah dilampirkan via
sendImageakan dibersihkan otomatis setelah pesan terkirim. - Callback
onImageUploadakan dipanggil setiap kali gambar berhasil dilampirkan, termasuk darisendImage.
onImageUpload(payload)
CallbackDipanggil setiap kali gambar berhasil dilampirkan ke composer chat — baik via tombol paperclip di widget, paste dari clipboard, drag-and-drop, maupun panggilan sendImage().
window.Takonai.onImageUpload = (payload: TakonaiImagePayload) => void
interface TakonaiImagePayload {
url: string; // URL publik gambar di Supabase Storage (atau URL asli untuk sendImage)
mimeType: string; // MIME type gambar, contoh: "image/jpeg"
sizeBytes: number; // Ukuran file dalam bytes (0 untuk sendImage)
fileName: string; // Nama file asli
}tsParameters
| Field | Type | Description |
|---|---|---|
url | string | URL gambar yang siap diakses. Untuk upload file, ini adalah URL Supabase Storage. Untuk sendImage, ini adalah URL yang dipass. |
mimeType | string | MIME type gambar (image/jpeg, image/png, image/webp, image/gif). |
sizeBytes | number | Ukuran file dalam bytes. Bernilai 0 untuk gambar yang dilampirkan via sendImage(url). |
fileName | string | Nama file asli dari upload, atau bagian akhir URL untuk sendImage. |
Example
// Analytics: lacak setiap gambar yang diupload user
window.Takonai.onImageUpload = ({ url, mimeType, sizeBytes, fileName }) => {
console.log('Image attached:', fileName, '(' + Math.round(sizeBytes / 1024) + 'KB)');
// Contoh: tampilkan preview di sidebar halaman host
document.getElementById('image-preview').src = url;
};jspostMessage Events
Widget berkomunikasi dengan halaman host via window.postMessage. Anda dapat meng-intercept event ini langsung jika perlu kontrol lebih dalam.
Host → Widget
Pesan yang dikirim dari halaman host ke iframe widget.
| Type | Payload | Dikirim oleh |
|---|---|---|
TAKONAI_INIT | TakonaiInitOptions | window.Takonai.init() |
TAKONAI_STEP_CHANGED | { currentStep, context? } | window.Takonai.setStep() |
TAKONAI_CONTEXT_UPDATE | { context } | window.Takonai.setContext() |
TAKONAI_SEND_IMAGE | { url: string } | window.Takonai.sendImage() |
Widget → Host
Pesan yang dikirim dari iframe widget ke halaman host.
| Type | Payload | Kapan dikirim |
|---|---|---|
TAKONAI_READY | {} | Widget iframe selesai dimuat dan config berhasil di-fetch. |
TAKONAI_CONFIG_READY | { primaryColor, fabPosition, fabOffsetX, fabOffsetY, fabImageUrl } | Config widget berhasil di-fetch. Berisi data branding dan FAB customization. |
TAKONAI_CONFIG_ERROR | {} | Config gagal di-fetch (widget ID / API key tidak valid, whitelist error). Bubble FAB disembunyikan. |
TAKONAI_INIT_ACK | { widgetName, steps } | Setelah host memanggil init() dan widget memproses request. |
TAKONAI_FILL | TakonaiFillPayload | AI berhasil menggunakan tool untuk mengisi form. |
TAKONAI_IMAGE_UPLOADED | TakonaiImagePayload | Gambar berhasil dilampirkan (dari upload file atau sendImage). |
TAKONAI_ERROR | TakonaiErrorPayload | Terjadi error di dalam widget. |
Intercept Manual
// Intercept langsung jika perlu (biasanya tidak diperlukan)
window.addEventListener('message', (event) => {
if (event.data?.type === 'TAKONAI_FILL') {
console.log('Fill event:', event.data.payload);
}
});jsType Reference
// Opsi untuk window.Takonai.init()
interface TakonaiInitOptions {
externalId: string;
currentStep?: number;
context?: Record<string, unknown>;
}
// Payload dari callback onFill
interface TakonaiFillPayload {
step: number;
formName: string;
data: Record<string, unknown>;
}
// Payload dari callback onError
interface TakonaiErrorPayload {
code: string;
message: string;
}
// Payload dari callback onImageUpload
interface TakonaiImagePayload {
url: string;
mimeType: string;
sizeBytes: number;
fileName: string;
}
// Global window.Takonai object
interface TakonaiWidget {
init(opts: TakonaiInitOptions): void;
setStep(step: number, context?: Record<string, unknown>): void;
setContext(context: Record<string, unknown>): void;
open(): void;
close(): void;
sendImage(url: string): void;
onReady: ((payload?: Record<string, unknown>) => void) | null;
onOpen: (() => void) | null;
onClose: (() => void) | null;
onMessage: ((payload: any) => void) | null;
onFill: ((payload: TakonaiFillPayload) => void) | null;
onError: ((payload: TakonaiErrorPayload) => void) | null;
onImageUpload: ((payload: TakonaiImagePayload) => void) | null;
}
declare global {
interface Window {
Takonai: TakonaiWidget;
}
}tsWidget Configuration
Konfigurasi widget dilakukan di dashboard TakonAI. Berikut field-field yang tersedia saat membuat atau mengedit widget.
Provider & Model
| Field | Keterangan | |
|---|---|---|
provider | string | Provider AI. Default: anthropic. Pilih openai_compatible untuk BYOK. |
provider_base_url | string | Base URL API untuk openai_compatible (misal: https://api.openai.com/v1). |
provider_api_key | string | API key untuk openai_compatible. Disimpan terenkripsi. |
provider_model | string | Model yang digunakan (misal: gpt-4o, claude-sonnet-4-20250514). |
BYOK (openai_compatible)
Gunakan provider ini jika ingin menggunakan API key sendiri dari OpenAI, Groq, Together, atau provider lain yang kompatibel dengan format OpenAI Chat Completions API. Fitur Custom Skills hanya tersedia di provider ini.
Fitur AI
| Field | Default | Keterangan |
|---|---|---|
thinking_enabled | false | Aktifkan extended thinking / chain-of-thought (label: 'Berpikir...'). |
thinking_budget_tokens | — | Batas token untuk proses thinking. Hanya berlaku jika thinking_enabled = true. |
web_search_enabled | false | Izinkan AI melakukan pencarian web (label: 'Mencari di web...'). |
web_fetch_enabled | false | Izinkan AI mengambil konten dari URL (label: 'Mengambil halaman...'). |
search_provider | — | Provider pencarian web (misal: tavily). Wajib jika web_search_enabled = true. |
search_api_key | — | API key untuk search provider. |
Branding & Tampilan
| Field | Default | Keterangan |
|---|---|---|
primary_color | #32CDCD | Warna aksen utama widget (hex). Digunakan untuk bubble, header, tombol send, dan bubble pesan user. |
avatar_url | /logo.webp | URL logo/avatar yang ditampilkan di header widget dan watermark background. |
welcome_message | string | Pesan sambutan saat widget pertama kali dibuka. Bisa di-override via init({ welcomeMessage }). |
hide_watermark | false | Sembunyikan watermark logo di background chat. Tersedia untuk plan Growth ke atas. |
FAB Customization
Floating Action Button (FAB) bisa dikustomisasi posisi, offset, dan gambarnya melalui dashboard.
| Field | Default | Keterangan |
|---|---|---|
fab_position | bottom-right | Posisi FAB: bottom-right, bottom-left, top-right, atau top-left. |
fab_offset_x | 0 | Offset horizontal dalam pixel dari posisi default. |
fab_offset_y | 0 | Offset vertikal dalam pixel dari posisi default. |
fab_image_url | — | URL gambar custom untuk FAB. Wajib format .webp, maksimal 256KB. Jika tidak diisi, FAB menggunakan ikon default dengan primary_color. |
Data FAB dikirim ke halaman host via event TAKONAI_CONFIG_READY sehingga widget.js bisa menerapkan posisi dan gambar yang sesuai. Jika config gagal di-fetch, event TAKONAI_CONFIG_ERROR dikirim dan bubble FAB disembunyikan.
Rate Limiting & Keamanan
| Field | Keterangan | |
|---|---|---|
external_id_daily_limit | number | Batas maksimal pesan per externalId per hari. Jika tercapai, widget menampilkan error DAILY_LIMIT_REACHED. |
allowed_origins | string[] | Daftar domain yang diizinkan (whitelist). Format: https://example.com (tanpa trailing slash). Kosongkan untuk mengizinkan semua domain. |
Image Upload
Widget mendukung upload gambar via tombol paperclip, paste dari clipboard (Ctrl+V / Cmd+V), drag-and-drop, atau programmatic via sendImage(url).
| Batasan | Nilai | |
|---|---|---|
Format | — | image/png, image/jpeg, image/webp, image/gif |
Ukuran maks per file | — | 5 MB |
Maks gambar per pesan | — | 3 |
Form Configuration
Sebelum widget bisa mengisi form, Anda perlu mengkonfigurasi Form di TakonAI dashboard. Form mendefinisikan tool yang digunakan AI untuk mengekstrak data dari percakapan dan mengirimkannya ke halaman Anda.
Konsep: Form sebagai AI Tool
Setiap form di TakonAI adalah sebuah AI tool. Saat AI memutuskan intent user sudah cukup jelas, ia memanggil tool tersebut dan menghasilkan JSON sesuai skema yang Anda definisikan. JSON ini dikirim ke halaman Anda via callback onFill — Anda bebas menggunakannya untuk apapun: mengisi HTML form, memanggil API, memperbarui state, atau memicu aksi UI. Nama "form" hanyalah konvensi; secara teknis ini adalah structured output dari AI dengan schema yang sepenuhnya Anda kontrol.
Struktur Payload Kompleks (Nested JSON)
Anthropic Tool Schema sepenuhnya mendukung stuktur nested seperti objects dan arrays. Ini sangat bermanfaat ketika Anda ingin output payload dari onFill siap pakai untuk request ke backend API Anda (seperti format produk dengan berbagai atribut dan varian).
Berikut adalah contoh konversi payload untuk produk (Tiket Wisata) yang kompleks:
{
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "Nama produk tiket"
},
"sku": {
"type": "string",
"description": "Kode SKU tiket"
},
"description": {
"type": "string",
"description": "Deskripsi lengkap terkait produk wisata"
},
"category_id": {
"type": "integer",
"description": "ID kategori produk (misal: 3 untuk tiket wisata)"
},
"price": {
"type": "number",
"description": "Harga jual"
},
"publish_rate": {
"type": "number",
"description": "Harga coret / harga publish"
},
"product_advantages_item": {
"type": "array",
"description": "Keunggulan produk",
"items": {
"type": "object",
"properties": {
"name": { "type": "string" }
}
}
},
"attributes": {
"type": "array",
"description": "Atribut varian (contoh: paket, waktu)",
"items": {
"type": "object",
"properties": {
"name": { "type": "string" },
"items": {
"type": "array",
"items": { "type": "string" }
},
"priority": { "type": "integer" }
}
}
},
"varian_items": {
"type": "array",
"description": "Kombinasi hasil varian beserta spesifikasinya",
"items": {
"type": "object",
"properties": {
"name": { "type": "string" },
"sku": { "type": "string" },
"price": { "type": "number" },
"stok": { "type": "integer" }
}
}
},
"tracking_adds": {
"type": "object",
"description": "Pengaturan tracking pixel",
"properties": {
"all_event": { "type": "boolean" },
"facebook_pixel": {
"type": "object",
"properties": {
"pixel_id": { "type": "array", "items": { "type": "string"} },
"event": { "type": "array", "items": { "type": "string"} }
}
}
}
}
},
"required": ["name", "sku", "description", "price", "attributes", "varian_items"]
}jsonTips Penting: Untuk skema yang sangat kompleks seperti pembuatan varian produk, disarankan menggunakan system prompt tambahan di dashboard agar AI tahu bagaimana cara mengisi field tertentu (misal: "Pastikan sku formatnya kebab-case"). Anda juga bisa langsung mem-pass sebagian struktur default (seperti properti tracking_adds) tersebut pada halaman host Anda setelah menerima callback onFill, alih-alih memaksa AI membuat keseluruhan payload statis.
Custom Skills
Custom Skills memungkinkan widget memanggil API eksternal secara server-side saat percakapan berlangsung. Skill dieksekusi oleh backend TakonAI — bukan di browser user — sehingga API key dan endpoint Anda tetap aman.
Catatan
Custom Skills hanya tersedia untuk widget dengan provider openai_compatible (BYOK).
Cara Kerja
- AI memutuskan perlu memanggil skill berdasarkan
description. - Backend mengirim SSE
processevent ke frontend (label: "Menjalankan [Nama Skill]..."). - Backend melakukan HTTP request ke
api_urlyang dikonfigurasi. - Response API dikembalikan sebagai konteks ke AI.
- AI melanjutkan percakapan dengan informasi dari API.
User chat → AI → Skill Call → Backend HTTP Request → API Response → AI lanjut jawabtextField Skill
| Field | Wajib | Keterangan |
|---|---|---|
name* | string | Nama skill (snake_case). Contoh: cek_ongkir |
description* | string | Deskripsi kapan AI harus memanggil skill ini. Semakin spesifik, semakin akurat. |
api_url* | string | URL endpoint API yang akan dipanggil (harus https://). |
method* | string | HTTP method: GET atau POST. |
parameters* | JSON | JSON Schema yang mendefinisikan parameter yang dikirim AI ke API. |
headers | JSON | Header tambahan (misal: Authorization, Content-Type). |
enabled | boolean | Aktifkan/nonaktifkan skill. Default: true. |
Contoh: Cek Ongkir
{
"name": "cek_ongkir",
"description": "Panggil skill ini saat user ingin mengetahui biaya pengiriman. Butuh kota asal, kota tujuan, dan berat dalam gram.",
"api_url": "https://api.rajaongkir.com/starter/cost",
"method": "POST",
"headers": {
"key": "your_api_key_here",
"Content-Type": "application/json"
},
"parameters": {
"type": "object",
"required": ["origin", "destination", "weight"],
"properties": {
"origin": {
"type": "string",
"description": "ID kota asal pengiriman"
},
"destination": {
"type": "string",
"description": "ID kota tujuan pengiriman"
},
"weight": {
"type": "integer",
"description": "Berat paket dalam gram"
}
}
}
}jsonSkill vs Form
| Form | Skill | |
|---|---|---|
| Eksekusi | Frontend (via onFill) | Backend (server-side HTTP) |
| Tujuan | Mengisi form di halaman host | Mengambil data dari API eksternal |
| Output | Data dikirim ke halaman host | Response masuk ke konteks AI |
| Provider | Semua provider | Hanya openai_compatible |
| Konfigurasi | Menu Forms → attach ke Widget Step | Tab Skills di halaman Widget Detail |
Error Codes
Daftar error code yang mungkin dikirim via callback onError atau event TAKONAI_ERROR:
| Code | Pesan Default | Keterangan |
|---|---|---|
DAILY_LIMIT_REACHED | Batas percakapan hari ini tercapai | externalId sudah melebihi external_id_daily_limit. |
INSUFFICIENT_BALANCE | Layanan tidak tersedia | Saldo/kredit habis (provider default). |
BILLING_ERROR | Layanan tidak tersedia | Masalah billing. |
RATE_LIMIT | Terlalu banyak permintaan | Rate limit dari provider AI. |
STREAM_ERROR | Terjadi kesalahan | Error saat streaming response dari AI. |
CONFIG_NOT_FOUND | — | Widget ID atau API key tidak valid. |
INVALID_IMAGE_URL | — | URL gambar tidak valid (harus https://). |
Full Example
Contoh integrasi lengkap untuk form checkout multi-step. Widget di-init saat user login, step di-update saat user berpindah halaman, dan form diisi otomatis saat AI selesai.
<!DOCTYPE html>
<html>
<head>
<title>Checkout</title>
</head>
<body>
<!-- Step 1: Data Pembeli -->
<form id="form-buyer">
<input name="full_name" placeholder="Nama Lengkap" />
<input name="email" placeholder="Email" />
<input name="phone" placeholder="No. HP" />
<button type="button" onclick="goToStep2()">Lanjut</button>
</form>
<!-- Step 2: Alamat Pengiriman -->
<form id="form-shipping" style="display:none">
<input name="address" placeholder="Alamat" />
<input name="city" placeholder="Kota" />
<input name="postal_code" placeholder="Kode Pos" />
<button type="submit">Bayar</button>
</form>
<!-- 1. Embed widget -->
<script
src="https://cdn.ztakonai.com"
data-widget-id="wgt_abc123"
data-api-key="tk_live_xxxx">
</script>
<script>
// 2. Init saat widget siap (iframe dimuat)
window.Takonai.onReady = () => {
window.Takonai.init({
externalId: 'usr_123', // Ganti dengan ID unik user Anda
currentStep: 1,
context: {
cartItems: 3,
totalAmount: 450000,
},
});
};
// 3. Isi form otomatis saat AI selesai
window.Takonai.onFill = ({ step, formName, data }) => {
const formEl = step === 1
? document.getElementById('form-buyer')
: document.getElementById('form-shipping');
Object.entries(data).forEach(([field, value]) => {
const el = formEl.querySelector('[name="' + field + '"]');
if (el) el.value = value;
});
};
// 4. Handle error
window.Takonai.onError = ({ code, message }) => {
console.error('[TakonAI Error]', code, message);
};
// 5. Update step saat user pindah halaman
function goToStep2() {
document.getElementById('form-buyer').style.display = 'none';
document.getElementById('form-shipping').style.display = 'block';
window.Takonai.setStep(2, {
buyerName: document.querySelector('[name="full_name"]').value,
});
}
</script>
</body>
</html>html