API Reference
Server tools
Web search, web fetch, dan X search yang dijalankan Ngoding — cara pakai per format, bentuk respons, harga credit, batas, dan kode error.
Server tools
Server tool adalah tool yang dijalankan Ngoding, bukan oleh aplikasimu. Model meminta pencarian atau pengambilan halaman, api kami menjalankannya, lalu hasilnya masuk ke respons dalam bentuk standar format yang kamu panggil. Kamu tidak perlu menulis loop tool sendiri.
Satu tool berlaku untuk semua model yang mendukung tool calling, lintas lab. Contohnya, X search bisa dipakai model Claude.
Status
| Format | Tool | Status |
|---|---|---|
Messages (POST /v1/messages) | web_search, web_fetch, x_search | Tersedia |
Responses (POST /v1/responses) | web_search (termasuk buka halaman), x_search | Tersedia |
Chat Completions (POST /v1/chat/completions) | web_search_options (search dan buka halaman) | Tersedia |
Cara memastikan tool sudah aktif untuk model yang kamu pakai: lihat capabilities.web_search.supported, capabilities.web_fetch.supported, dan capabilities.x_search.supported di GET /v1/models. Nilainya true hanya bila model itu mendukung tool calling, tool tidak sedang dimatikan, dan (untuk pencarian) mesin pencarinya aktif. Selama false, request yang memakai tool itu ditolak 400: unsupported_tool bila tool sedang dimatikan atau mesinnya belum aktif, unsupported_content bila model tidak mendukung tool calling. Di Chat, web_search_options saat server tool dimatikan seluruhnya ditolak 400 unsupported_parameter.
Tool yang tersedia
| Tool | Fungsi | Catatan |
|---|---|---|
web_search | Mencari di web; hasilnya URL, judul, dan cuplikan | Maks 10 hasil per pencarian |
web_fetch | Mengambil isi satu halaman web atau PDF | Hanya URL yang sudah muncul di percakapan |
x_search | Mencari post di X | Ekstensi Ngoding, bukan tool resmi Anthropic |
x_search adalah tambahan kami. Di format Messages ia memakai tipe x_search_20261005, yang tidak ada di dokumentasi Anthropic; di format Responses bentuknya mengikuti tool x_search xAI. Cuplikan hasil X search berupa ringkasan beserta tautan post, bukan kutipan asli post.
Messages (format Anthropic)
Mendeklarasikan tool
Tulis tool di tools persis seperti dokumentasi Anthropic. Versi di luar daftar di bawah ditolak 400 unsupported_tool.
web_search, type salah satu dari web_search_20250305, web_search_20260209, web_search_20260318:
| Parameter | Keterangan |
|---|---|
name | Wajib "web_search" |
max_uses | Batas jumlah pencarian per request. Lewat batas → hasil error max_uses_exceeded, lalu model melanjutkan tanpa tool itu |
allowed_domains atau blocked_domains | Pilih salah satu; keduanya sekaligus → 400. Domain polos dengan path opsional, tanpa skema (contoh.id, contoh.id/blog). * hanya boleh di path |
user_location | type: "approximate" plus city, region, country (kode ISO 2 huruf, mis. ID), timezone (ID IANA, mis. Asia/Jakarta) |
allowed_callers, response_inclusion | Diterima lalu diabaikan |
Ketiga versi berjalan sama: pencarian langsung, tanpa dynamic filtering (penyaringan hasil lewat eksekusi kode).
web_fetch, type salah satu dari web_fetch_20250910, web_fetch_20260209, web_fetch_20260309, web_fetch_20260318:
| Parameter | Keterangan |
|---|---|
name | Wajib "web_fetch" |
max_uses | Sama seperti web_search |
allowed_domains atau blocked_domains | Sama seperti web_search |
citations | {"enabled": true} meminta sitasi ke isi halaman (lihat Sitasi) |
max_content_tokens | Memotong isi halaman, dengan perkiraan 4 karakter per token |
use_cache | Default true (cache 15 menit). false = selalu ambil ulang |
x_search (ekstensi Ngoding), type x_search_20261005:
| Parameter | Keterangan |
|---|---|
name | Wajib "x_search" |
max_uses | Sama seperti web_search |
allowed_x_handles atau excluded_x_handles | Pilih salah satu, masing-masing maks 20 handle |
from_date, to_date | Rentang tanggal YYYY-MM-DD |
Tool klien tidak boleh memakai nama web_search, web_fetch, atau x_search bila server tool bernama sama ikut dikirim → 400.
Contoh
import anthropic
client = anthropic.Anthropic(
base_url="https://api.ngoding.in",
api_key="sk-ngd-GANTI-DENGAN-KUNCIMU",
)
resp = client.messages.create(
model="claude-opus-5-5",
max_tokens=2048,
messages=[{"role": "user", "content": "Apa kabar terbaru soal MRT Jakarta fase 2? Sertakan sumber."}],
tools=[
{
"type": "web_search_20250305",
"name": "web_search",
"max_uses": 3,
"user_location": {"type": "approximate", "country": "ID", "timezone": "Asia/Jakarta"},
},
{"type": "web_fetch_20250910", "name": "web_fetch", "max_uses": 2},
],
)
for block in resp.content:
if block.type == "text":
print(block.text)
print(resp.usage.server_tool_use)Tipe x_search_20261005 belum dikenal SDK resmi. SDK Python menerimanya sebagai dict biasa; di TypeScript perlu cast tipe pada elemen tools. Hasilnya tetap terbaca karena memakai blok web_search_tool_result.
Bentuk respons
{
"id": "msg_01JB5Q8YH0R6",
"type": "message",
"role": "assistant",
"model": "claude-opus-5-5",
"content": [
{ "type": "text", "text": "Saya cari dulu kabar terbarunya." },
{
"type": "server_tool_use",
"id": "srvtoolu_01JB5Q8YH4K2",
"name": "web_search",
"input": { "query": "MRT Jakarta fase 2 terbaru" }
},
{
"type": "web_search_tool_result",
"tool_use_id": "srvtoolu_01JB5Q8YH4K2",
"content": [
{
"type": "web_search_result",
"url": "https://contoh.id/berita/mrt-fase-2",
"title": "Progres MRT fase 2",
"encrypted_content": "ngd1.1.Q2hhbmdlZC1ieS1kb2Nz…",
"page_age": "2026-10-03"
}
]
},
{
"type": "text",
"text": "Pengerjaan fase 2 sudah masuk tahap uji.",
"citations": [
{
"type": "web_search_result_location",
"url": "https://contoh.id/berita/mrt-fase-2",
"title": "Progres MRT fase 2",
"encrypted_index": "ngd1.1.SW5kZXgtYnktZG9jcw…",
"cited_text": "Pengerjaan fase 2 kini masuk tahap uji sistem."
}
]
}
],
"stop_reason": "end_turn",
"usage": {
"input_tokens": 5120,
"output_tokens": 410,
"server_tool_use": { "web_search_requests": 1, "web_fetch_requests": 0 }
}
}server_tool_use: id berawalansrvtoolu_.inputberisiquery(search, X search) atauurl(fetch).web_search_tool_result:contentberupa daftarweb_search_result(url,title,encrypted_content,page_age). Pencarian tanpa hasil = daftar kosong, bukan error. Hasil X search memakai tipe blok yang sama supaya SDK tidak gagal membaca; judulnya berbentuk@handle — awal post.web_fetch_tool_result:contentberupaweb_fetch_resultberisiurl,retrieved_at, dancontentdokumen (source.typetextataubase64,media_type,data,title).- Error:
contentberupa objekweb_search_tool_result_error/web_fetch_tool_result_errordenganerror_code, bukan daftar. Periksa bentuknya sebelum membaca hasil. Daftar kode: Kode error di dalam respons 200. usage.server_tool_use:web_search_requestsdanweb_fetch_requests. X search ikut dihitung diweb_search_requestsdan juga dix_search_requests(ekstensi).
Sitasi
- Bila model mengutip hasil pencarian, blok teks membawa
citationsbertipeweb_search_result_location(url,title,encrypted_index,cited_textmaks 150 karakter). Tidak semua model mengeluarkan sitasi; tanpa itu teks tampil apa adanya. - Sitasi isi halaman (
char_location) hanya muncul bilacitations.enableddi toolweb_fetchdan model mendukungnya.
Melanjutkan percakapan
Kirim balik semua blok assistant apa adanya, termasuk server_tool_use, blok hasil, encrypted_content, dan encrypted_index. Dari blok itulah api memulihkan hasil tool untuk model. Blok yang diubah, rusak, atau berasal dari akun lain → 400 invalid_request_error ("encrypted_content tidak valid").
pause_turn
Satu request menjalankan paling banyak 8 iterasi (model memanggil tool, api menjalankannya, model melanjutkan). Bila batas itu tercapai, credit tidak cukup untuk iterasi berikutnya, atau (tanpa stream) upstream gagal setelah iterasi pertama, respons berhenti dengan stop_reason: "pause_turn". Lanjutkan dengan mengirim ulang konten assistant apa adanya, tanpa pesan user tambahan:
messages = [{"role": "user", "content": "Rangkum perkembangan terbaru regulasi AI di Indonesia, dengan sumber."}]
tools = [{"type": "web_search_20250305", "name": "web_search"}]
resp = client.messages.create(model="claude-opus-5-5", max_tokens=4096, tools=tools, messages=messages)
continuations = 0
while resp.stop_reason == "pause_turn" and continuations < 5:
# Kirim balik giliran yang terjeda apa adanya; api melanjutkan dari situ.
messages.append({"role": "assistant", "content": resp.content})
resp = client.messages.create(model="claude-opus-5-5", max_tokens=4096, tools=tools, messages=messages)
continuations += 1- Tool runner di SDK Anthropic tidak melanjutkan
pause_turnotomatis; tangani sendiri seperti di atas. - Bila jeda terjadi karena credit habis, isi saldo dulu. Request lanjutan saat saldo habis ditolak
402.
Tool klien dan server tool dalam satu giliran
Bila model memanggil server tool dan tool milikmu sekaligus, api menjalankan server tool lebih dulu dan mengirim hasilnya, lalu respons berhenti dengan stop_reason: "tool_use" untuk tool milikmu. Di request berikutnya kirim riwayat lengkap seperti biasa ditambah tool_result milikmu; hasil server tool diambil api dari blok di riwayat.
Streaming
- Satu
message_startper request; indeks blok berlanjut lintas iterasi. server_tool_usedatang sebagaicontent_block_start, satuinput_json_deltaberisi JSON utuh, lalucontent_block_stop.- Blok hasil datang utuh di
content_block_start(tanpa delta), lalucontent_block_stop. - Event
pingdikirim tiap 10 detik selama tool berjalan. message_deltadi akhir membawausagekumulatif semua iterasi.- Error setelah byte pertama terkirim datang sebagai
event: errordi dalam stream.
Responses (format OpenAI)
Tool dan parameter
web_search, type salah satu dari web_search, web_search_preview, web_search_2025_08_26. Versi lain (mis. web_search_preview_2025_03_11) ditolak 400 unsupported_tool.
| Parameter | Keterangan |
|---|---|
search_context_size | low / medium / high → 5 / 8 / 10 hasil per pencarian. Default medium |
filters.allowed_domains | Maks 100 domain. Domain polos dengan path opsional, tanpa skema. Berlaku juga untuk halaman yang dibuka |
user_location | type: "approximate" plus city, region, country (ISO 2 huruf), timezone (ID IANA) |
web_searchsekaligus mengizinkan model membuka halaman (aksiopen_page, setaraweb_fetch), seperti perilaku OpenAI, bilacapabilities.web_fetch.supportedmodel itutrue. Isi teks halaman yang dibuka dengan cara ini dibatasi 25.000 token per halaman (sekitar 100.000 karakter), karena tiap halaman ikut terkirim lagi di setiap iterasi berikutnya dan ditagih sebagai token input. PDF hanya dibuka di model yang mendukung input PDF, dan dikirim utuh (maks 10 MB) tanpa batas token itu.- Tool klien yang boleh ikut di request yang sama hanya
function(lihat jalur terjemah). Bila kamu punya tool fungsi bernamaweb_fetch, buka halaman otomatis tidak diaktifkan dan tool fungsimu tetap milikmu. Tool fungsi yang namanya sama dengan server tool yang kamu aktifkan (web_search,x_search) →400.
x_search (ekstensi Ngoding, bentuk xAI): {"type": "x_search", "allowed_x_handles": […], "excluded_x_handles": […], "from_date": "YYYY-MM-DD", "to_date": "YYYY-MM-DD"}. Pilih salah satu daftar handle, masing-masing maks 20; @ di depan handle boleh. X search tidak membuka halaman.
max_tool_calls (bilangan bulat ≥ 1): batas jumlah panggilan server tool per request, dihitung lintas semua tool. Panggilan yang melewati batas tidak dijalankan dan tidak ditagih; item-nya berstatus failed dan model menerima teks error.
tool_choice berbentuk tool hosted ({"type": "web_search"}, {"type": "x_search"}, …) memaksa tool itu di iterasi pertama saja; iterasi berikutnya auto. Tool yang sama wajib ada di tools, selain itu 400.
from openai import OpenAI
client = OpenAI(base_url="https://api.ngoding.in/v1", api_key="sk-ngd-GANTI-DENGAN-KUNCIMU")
resp = client.responses.create(
model="gpt-6-luna",
input="Apa kabar terbaru soal tarif KRL Jabodetabek? Sertakan sumber.",
tools=[{"type": "web_search", "search_context_size": "low"}],
max_tool_calls=4,
)
print(resp.output_text)Bentuk keluaran
{
"id": "resp_01JB5Q8YH0R6",
"object": "response",
"status": "completed",
"incomplete_details": null,
"model": "gpt-6-luna",
"output": [
{
"id": "msg_01JB5Q8YH1A1",
"type": "message",
"status": "completed",
"role": "assistant",
"content": [{ "type": "output_text", "text": "Saya cari dulu.", "annotations": [] }]
},
{
"id": "ws_01JB5Q8YH4K2",
"type": "web_search_call",
"status": "completed",
"action": {
"type": "search",
"query": "tarif KRL Jabodetabek terbaru",
"sources": [{ "type": "url", "url": "https://contoh.id/berita/tarif-krl" }]
}
},
{
"id": "msg_01JB5Q8YH7M3",
"type": "message",
"status": "completed",
"role": "assistant",
"content": [
{
"type": "output_text",
"text": "Menurut [Tarif KRL 2026](https://contoh.id/berita/tarif-krl), tarif dasar belum berubah.",
"annotations": [
{
"type": "url_citation",
"start_index": 8,
"end_index": 60,
"url": "https://contoh.id/berita/tarif-krl",
"title": "Tarif KRL 2026"
}
]
}
]
}
],
"usage": {
"input_tokens": 4210,
"input_tokens_details": { "cached_tokens": 0 },
"output_tokens": 180,
"output_tokens_details": { "reasoning_tokens": 0 },
"total_tokens": 4390
}
}- Teks tiap iterasi menjadi item
messagesendiri, dengan item tool di antaranya sesuai urutan kejadian.output_textdi SDK menggabungkan semua teks. web_search_call:idberawalanws_,statuscompletedataufailed(in_progresshanya muncul di stream), danactionsalah satu dari:{"type": "search", "query": …, "sources": [{"type": "url", "url": …}]}.sourcesselalu disertakan, tanpa perluinclude.{"type": "open_page", "url": …}untuk halaman yang dibuka model.
x_search_call:idberawalanxs_,actionberbentuk sama dengansearch(query, dansourcesberisi URL post).- Tool gagal (kode error apa pun, termasuk lewat
max_tool_calls) →status: "failed". Kodenya tidak ditampilkan di item; model menerima teks error lalu melanjutkan.
Sitasi (url_citation)
- Anotasi
url_citationada diannotationsmilikoutput_text, berbentuk datar:{"type": "url_citation", "start_index", "end_index", "url", "title"}. - Anotasi diturunkan dari tautan markdown
[judul](url)di jawaban yang URL-nya ada di hasil tool (pencarian, X search, atau halaman yang dibuka). Untuk itu api menambahkan instruksi sistem singkat bertanda[ngoding:servertools]yang meminta model mengutip dengan format tersebut. Model yang tidak menulis tautan seperti itu tidak menghasilkan anotasi. start_indexdanend_indexmenunjuk seluruh tautan[judul](url), dihitung per karakter Unicode (code point),end_indexeksklusif. Di JavaScript, ambil rentangnya dengan[...text].slice(start_index, end_index).join(""), bukantext.slice.urldiambil dari hasil tool, jadi fragmen#…yang ditulis model tidak ikut.titlejuga dari hasil tool; bila hasil tanpa judul, teks tautannya yang dipakai.
Stream
- Satu
response.createddanresponse.in_progressper request, walau ada beberapa iterasi. - Per panggilan tool:
response.output_item.added(itemweb_search_call,status: "in_progress",actionbelum berisisources), laluresponse.web_search_call.in_progressdanresponse.web_search_call.searching. Setelah hasil tiba:response.web_search_call.completed, laluresponse.output_item.donedengan item lengkap. Tool gagal:response.output_item.donedenganstatus: "failed", tanpa.completed. open_pagememakai event yang sama karena itemnya jugaweb_search_call.x_search_callhanya mengirimresponse.output_item.addeddanresponse.output_item.done, karena xAI tidak mendokumentasikan sub-event untuk X search.- Anotasi dikirim lewat
response.output_text.annotation.added(satu event per anotasi) saat item message ditutup: setelah semuaresponse.output_text.deltadan sebelumresponse.output_text.done. - Penutup:
response.completed, atauresponse.incompletebila statusincomplete. - Selama tool berjalan, api mengirim komentar SSE
: pingtiap 10 detik. Komentar ini bukan event dan diabaikan parser SSE di SDK.
Batas dan akhir respons
- Batas 8 iterasi tercapai → satu panggilan akhir dengan
tool_choice: "none"supaya model tetap menjawab. Panggilan tool di jawaban akhir itu dibuang, dan status tetapcompleted. max_tool_callshabis dan request tidak punya tool fungsi milikmu → iterasi berikutnya langsung panggilan akhir dengantool_choice: "none". Bila ada tool fungsi milikmu, loop berlanjut (tool fungsimu tetap bisa dipanggil) dan panggilan server tool berikutnyafailed.- Credit tidak cukup untuk iterasi berikutnya →
status: "incomplete",incomplete_details.reason: "max_tool_calls". Teks dan item yang sudah jadi tetap dikirim. Nilaimax_tool_callsini tidak ada di enum tipe SDK OpenAI, jadi baca sebagai string. Isi saldo lalu kirim ulang. max_output_tokensberlaku untuk total output semua iterasi. Habis →status: "incomplete",incomplete_details.reason: "max_output_tokens".
Melanjutkan percakapan
- Kirim balik item output apa adanya di
input. Itemweb_search_calldanx_search_calllama tidak dikirim ulang ke model; teks dan anotasinya tetap dipakai. - URL di anotasi
url_citationsebelumnya boleh dibuka (open_page) di request baru. inputberisi itemweb_search_call/x_search_calltetapitoolstidak memuat tool yang sama →400invalid_request_error.- Model memanggil server tool dan tool fungsi milikmu sekaligus: server tool dijalankan dulu, lalu respons berakhir dengan item
function_callmilikmu. Kirimfunction_call_outputdi request berikutnya seperti biasa.
Chat Completions (format OpenAI)
Parameter
web_search_options mengaktifkan web_search dan buka halaman (web_fetch) sekaligus.
| Parameter | Keterangan |
|---|---|
search_context_size | low / medium / high → 5 / 8 / 10 hasil per pencarian. Default medium |
user_location | Bentuk bersarang resmi OpenAI: {"type": "approximate", "approximate": {"city", "region", "country", "timezone"}} |
- Isi teks halaman yang dibuka dibatasi 25.000 token per halaman, sama seperti di Responses (PDF dikirim utuh di model yang mendukung input PDF). Chat tidak punya
max_tool_callsatau filter domain; batas biaya per request datang dari batas iterasi dan batas isi halaman ini. x_searchtidak tersedia di Chat. Pakai Responses atau Messages.- Tool fungsi milikmu boleh ikut di
tools, kecuali bernamaweb_search(→400). Toolcustomditolak400unsupported_toolbila adaweb_search_options. Bila ada tool fungsi bernamaweb_fetch, buka halaman otomatis tidak diaktifkan. tool_choice: "required"memaksa tool di iterasi pertama saja; iterasi berikutnyaauto.
from openai import OpenAI
client = OpenAI(base_url="https://api.ngoding.in/v1", api_key="sk-ngd-GANTI-DENGAN-KUNCIMU")
resp = client.chat.completions.create(
model="claude-opus-5-5",
messages=[{"role": "user", "content": "Kapan saja libur nasional Desember 2026? Sertakan sumber."}],
web_search_options={
"search_context_size": "low",
"user_location": {"type": "approximate", "approximate": {"country": "ID", "timezone": "Asia/Jakarta"}},
},
)
print(resp.choices[0].message.content)
for a in resp.choices[0].message.annotations or []:
print(a.url_citation.title, a.url_citation.url)Bentuk keluaran
{
"id": "chatcmpl-01JB5Q8YH0R6",
"object": "chat.completion",
"model": "claude-opus-5-5",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "Saya cari dulu.\n\nMenurut [Libur nasional 2026](https://contoh.id/libur-2026), ada dua hari libur di Desember.",
"annotations": [
{
"type": "url_citation",
"url_citation": {
"start_index": 25,
"end_index": 76,
"url": "https://contoh.id/libur-2026",
"title": "Libur nasional 2026"
}
}
]
},
"finish_reason": "stop"
}
],
"usage": { "prompt_tokens": 4210, "completion_tokens": 180, "total_tokens": 4390 }
}- Chat tidak punya item tool: pencarian dan halaman yang dibuka tidak terlihat di respons, hanya teks dan anotasinya.
- Teks dari beberapa iterasi digabung dalam satu
message.content, dipisah tepat satu baris kosong. Indeks anotasi dihitung pada teks gabungan itu. message.annotationsberisi{"type": "url_citation", "url_citation": {"start_index", "end_index", "url", "title"}}(bentuk bersarang resmi OpenAI), diturunkan dengan aturan yang sama seperti di Responses.annotationsselalu berupa array, boleh kosong.- Stream: tanpa event tool. Delta teks berjalan terus; bila ada anotasi,
delta.annotations(semua anotasi sekaligus) dikirim di satu chunk sebelum chunkfinish_reason. Sesudahnya chunk usage (bilastream_options.include_usage), lalu[DONE]. Selama tool berjalan, api mengirim komentar SSE: pingtiap 10 detik. - URL di
annotationspesan assistant sebelumnya boleh dibuka di request baru.
Batas dan akhir respons
- Batas 8 iterasi tercapai → satu panggilan akhir dengan
tool_choice: "none";finish_reasontetapstop. - Credit tidak cukup untuk iterasi berikutnya →
finish_reason: "length", dengan teks yang sudah jadi. Isi saldo lalu kirim ulang. max_tokens/max_completion_tokensberlaku untuk total output semua iterasi. Habis →finish_reason: "length".- Model memanggil tool fungsi milikmu → server tool dijalankan dulu, lalu
finish_reason: "tool_calls".
Responses dan Chat: jalur terjemah
Request Responses atau Chat yang memakai server tool selalu diproses dalam bentuk Messages, jadi selalu lewat jalur terjemah, juga bila upstream model itu berformat sama dengan request-mu.
- Isi selain teks dan gambar, misalnya
input_filedi Responses ataufiledaninput_audiodi Chat, ditolak400unsupported_content. - Tool klien hanya
function. Di Responses,custom,local_shell,apply_patch, danshellditolak400unsupported_toolbila request memuat server tool, dan item riwayatnya (mis.custom_tool_call,local_shell_call) ditolak400unsupported_content. Di Chat, toolcustomjuga ditolakunsupported_tool. - Parameter yang tidak punya padanan dibuang tanpa error:
seed,frequency_penalty,presence_penalty,logprobs,prompt_cache_key. nlebih dari 1 (Chat) →400unsupported_parameter.
Upstream gagal di tengah loop
Satu request bisa memanggil model beberapa iterasi. Bila model menolak dengan error di iterasi pertama, request gagal seperti biasa dan tidak ditagih. Bila model gagal setelah iterasi pertama:
- Responses dan Chat: kamu menerima error, bukan jawaban
incompleteataulength(mis.502upstream_error; daftar kode di Error). Di stream, teks yang sudah terkirim tetap ada, lalu error datang sebagaievent: error(Responses) atau chunk{"error": {…}}tanpa[DONE](Chat). - Messages: tanpa stream, respons berhenti dengan
stop_reason: "pause_turn"berisi konten yang sudah jadi, dan kamu bisa melanjutkan seperti biasa. Dengan stream, error datang sebagaievent: error. - Tagihan: token dan tool dari iterasi yang sudah selesai tetap ditagih, walaupun kamu menerima error. Token itu sudah kami bayar ke penyedia model. Iterasi yang ditolak upstream dengan error tidak ditagih; iterasi yang sempat mengalir lalu terputus, atau jawaban upstream yang rusak, ditagih dari pemakaian yang terlihat atau estimasi, sama seperti stream biasa. Semuanya tercatat sebagai satu baris di riwayat pemakaian, dengan status error.
Harga
Satu request ditagih sekali: credit token ditambah credit tool.
- Token. Usage semua iterasi dijumlahkan lalu ditagih dengan harga model seperti biasa. Hasil tool yang masuk konteks dihitung sebagai token input.
- Tool. Biaya per unit, di atas token:
| Unit | Harga resmi acuan | Default |
|---|---|---|
| Web search, per pencarian | US$10 per 1.000 pencarian | 0,32 credit |
| Web fetch, per pengambilan | Tanpa biaya (token saja) | 0 credit |
| X search, per post yang diambil | US$5 per 1.000 post | 0,16 credit |
| X search, per profil yang diambil | US$10 per 1.000 profil | 0,32 credit |
Default dihitung dengan rumus yang sama dengan tarif model: harga resmi USD × 32 credit (1 credit = Rp100). Harga tool bisa berubah; dasar hitung dan aturan penagihan credit ada di Credit & harga.
- Tool yang error atau dibatalkan tidak ditagih.
- Token model yang dipakai mesin pencari kami di belakang layar tidak ditagihkan kepadamu.
- Credit ditahan per iterasi. Bila saldo tidak cukup untuk iterasi berikutnya, loop berhenti:
pause_turndi Messages,status: "incomplete"di Responses,finish_reason: "length"di Chat. - Upstream gagal setelah iterasi pertama: iterasi yang sudah selesai tetap ditagih (lihat Upstream gagal di tengah loop).
- Di Batches, server tool memakai loop dan harga yang sama: satu baris tagihan per request, tanpa diskon batch.
Batas
| Batas | Nilai |
|---|---|
| Iterasi per request | 8; di Responses dan Chat ditambah satu panggilan akhir tanpa tool |
| Panggilan server tool per request (Responses) | max_tool_calls, bila diisi |
| Panggilan tool paralel per iterasi | 4 |
| Panggilan tool per akun | 60 per menit → too_many_requests |
| Panjang query pencarian | 400 karakter → query_too_long |
| Hasil per pencarian | 10, cuplikan maks 1.000 karakter |
Panjang URL web_fetch | 250 karakter → url_too_long |
Ukuran halaman web_fetch | 10 MB sebelum diproses |
Isi teks halaman yang dibuka lewat web_search (Responses, Chat) | 25.000 token per halaman; PDF utuh, maks 10 MB |
Redirect web_fetch | 5 |
| Timeout | search 15 detik, fetch 20 detik, X search 30 detik → unavailable |
Kode error di dalam respons 200
Error tool tidak menggagalkan request: respons tetap HTTP 200, error ada di blok hasil, dan model melanjutkan jawabannya.
{
"type": "web_search_tool_result",
"tool_use_id": "srvtoolu_01JB5Q8YH4K2",
"content": { "type": "web_search_tool_result_error", "error_code": "max_uses_exceeded" }
}web_search dan x_search:
| Kode | Arti |
|---|---|
too_many_requests | Batas 60 panggilan tool per menit terlewati |
invalid_tool_input | Input tool dari model tidak valid |
max_uses_exceeded | max_uses tercapai |
query_too_long | Query lebih dari 400 karakter |
unavailable | Mesin tool gagal atau melewati timeout |
web_fetch memakai semua kode di atas, ditambah:
| Kode | Arti |
|---|---|
url_too_long | URL lebih dari 250 karakter |
url_not_allowed | Domain di luar allowed_domains / termasuk blocked_domains |
url_not_in_prior_context | URL belum pernah muncul di percakapan (lihat web_fetch) |
url_not_accessible | Halaman gagal diambil, atau ditolak robots.txt |
unsupported_content_type | Jenis isi tidak didukung |
Di Responses, tool yang gagal muncul sebagai item web_search_call atau x_search_call dengan status: "failed", tanpa kode error; model menerima teks error. Di Chat, error tool hanya terlihat oleh model.
Ditolak 400
unsupported_tool:- Tool sedang dimatikan atau belum punya mesin aktif. Pesannya menyebut tool yang ditolak.
- Versi tool di luar daftar di atas.
- Tool server lain:
code_execution*(menunggu sandbox milik kami),file_search,image_generation, computer use versi hosted,mcp*. Parametermcp_servers→unsupported_parameter.
invalid_request_error:allowed_domainsdanblocked_domainsdikirim bersamaan, nama tool klien bentrok dengan server tool, atauencrypted_contenttidak valid. Khusus Responses dan Chat:search_context_sizeselainlow,medium,high.filters.allowed_domainslebih dari 100 domain atau memakai skema (https://…).user_locationbukanapproximate, kosong,countrybukan kode 2 huruf, atautimezonebukan ID IANA; di Chat juga tanpa objekapproximate.- Tool yang sama didefinisikan dua kali, atau
max_tool_callsbukan bilangan bulat ≥ 1. tool_choicehosted, atau itemweb_search_call/x_search_calldiinput, tanpa tool yang sama ditools. Bilatoolstidak memuat server tool sama sekali,tool_choicehosted ditolakunsupported_tool.
unsupported_content: model tidak mendukung tool calling (Model … tidak mendukung isi request ini.), di semua format.unsupported_contentdanunsupported_parameterdi Responses dan Chat: lihat jalur terjemah.
web_fetch: keamanan dan cara kerja
- Hanya
httpdanhttpsdi port 80/443. Alamat loopback, jaringan privat, link-local, dan alamat metadata cloud ditolak, juga setelah redirect. - URL harus sudah muncul di percakapan: di teks user, di hasil search atau fetch sebelumnya, atau di anotasi sebelumnya. URL yang hanya ada di jawaban model atau di system prompt ditolak
url_not_in_prior_context. Aturan ini mencegah prompt injection mengirim datamu ke URL luar. - Halaman diambil dengan
User-Agent: NgodingFetch/1.0 (+https://ngoding.in/bot), tanpa cookie, dan menghormatirobots.txt. - HTML diubah menjadi teks terbaca (markdown);
text/*dan JSON dikirim apa adanya. PDF dikirim sebagai dokumen bila model mendukung input PDF; selain ituunsupported_content_type. - Isi halaman di-cache 15 menit per URL.
use_cache: falsemelewati cache.
Privasi
encrypted_contentdanencrypted_indexdisegel untuk akunmu. Blob itu hanya bisa dibuka lagi lewat request dari akun yang sama (kunci API mana pun di akun itu). Dari akun lain →400.- Hasil pencarian tidak disimpan di server kami; isinya ikut di dalam blob tersegel yang kamu simpan dan kirim balik.
- Cache
web_fetchmenyimpan isi halaman publik per URL selama 15 menit, bukan isi percakapanmu.