ngodingdocs

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

FormatToolStatus
Messages (POST /v1/messages)web_search, web_fetch, x_searchTersedia
Responses (POST /v1/responses)web_search (termasuk buka halaman), x_searchTersedia
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

ToolFungsiCatatan
web_searchMencari di web; hasilnya URL, judul, dan cuplikanMaks 10 hasil per pencarian
web_fetchMengambil isi satu halaman web atau PDFHanya URL yang sudah muncul di percakapan
x_searchMencari post di XEkstensi 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:

ParameterKeterangan
nameWajib "web_search"
max_usesBatas jumlah pencarian per request. Lewat batas → hasil error max_uses_exceeded, lalu model melanjutkan tanpa tool itu
allowed_domains atau blocked_domainsPilih salah satu; keduanya sekaligus → 400. Domain polos dengan path opsional, tanpa skema (contoh.id, contoh.id/blog). * hanya boleh di path
user_locationtype: "approximate" plus city, region, country (kode ISO 2 huruf, mis. ID), timezone (ID IANA, mis. Asia/Jakarta)
allowed_callers, response_inclusionDiterima 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:

ParameterKeterangan
nameWajib "web_fetch"
max_usesSama seperti web_search
allowed_domains atau blocked_domainsSama seperti web_search
citations{"enabled": true} meminta sitasi ke isi halaman (lihat Sitasi)
max_content_tokensMemotong isi halaman, dengan perkiraan 4 karakter per token
use_cacheDefault true (cache 15 menit). false = selalu ambil ulang

x_search (ekstensi Ngoding), type x_search_20261005:

ParameterKeterangan
nameWajib "x_search"
max_usesSama seperti web_search
allowed_x_handles atau excluded_x_handlesPilih salah satu, masing-masing maks 20 handle
from_date, to_dateRentang 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 berawalan srvtoolu_. input berisi query (search, X search) atau url (fetch).
  • web_search_tool_result: content berupa daftar web_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: content berupa web_fetch_result berisi url, retrieved_at, dan content dokumen (source.type text atau base64, media_type, data, title).
  • Error: content berupa objek web_search_tool_result_error / web_fetch_tool_result_error dengan error_code, bukan daftar. Periksa bentuknya sebelum membaca hasil. Daftar kode: Kode error di dalam respons 200.
  • usage.server_tool_use: web_search_requests dan web_fetch_requests. X search ikut dihitung di web_search_requests dan juga di x_search_requests (ekstensi).

Sitasi

  • Bila model mengutip hasil pencarian, blok teks membawa citations bertipe web_search_result_location (url, title, encrypted_index, cited_text maks 150 karakter). Tidak semua model mengeluarkan sitasi; tanpa itu teks tampil apa adanya.
  • Sitasi isi halaman (char_location) hanya muncul bila citations.enabled di tool web_fetch dan 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_turn otomatis; 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_start per request; indeks blok berlanjut lintas iterasi.
  • server_tool_use datang sebagai content_block_start, satu input_json_delta berisi JSON utuh, lalu content_block_stop.
  • Blok hasil datang utuh di content_block_start (tanpa delta), lalu content_block_stop.
  • Event ping dikirim tiap 10 detik selama tool berjalan.
  • message_delta di akhir membawa usage kumulatif semua iterasi.
  • Error setelah byte pertama terkirim datang sebagai event: error di 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.

ParameterKeterangan
search_context_sizelow / medium / high → 5 / 8 / 10 hasil per pencarian. Default medium
filters.allowed_domainsMaks 100 domain. Domain polos dengan path opsional, tanpa skema. Berlaku juga untuk halaman yang dibuka
user_locationtype: "approximate" plus city, region, country (ISO 2 huruf), timezone (ID IANA)
  • web_search sekaligus mengizinkan model membuka halaman (aksi open_page, setara web_fetch), seperti perilaku OpenAI, bila capabilities.web_fetch.supported model itu true. 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 bernama web_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 message sendiri, dengan item tool di antaranya sesuai urutan kejadian. output_text di SDK menggabungkan semua teks.
  • web_search_call: id berawalan ws_, status completed atau failed (in_progress hanya muncul di stream), dan action salah satu dari:
    • {"type": "search", "query": …, "sources": [{"type": "url", "url": …}]}. sources selalu disertakan, tanpa perlu include.
    • {"type": "open_page", "url": …} untuk halaman yang dibuka model.
  • x_search_call: id berawalan xs_, action berbentuk sama dengan search (query, dan sources berisi 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_citation ada di annotations milik output_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_index dan end_index menunjuk seluruh tautan [judul](url), dihitung per karakter Unicode (code point), end_index eksklusif. Di JavaScript, ambil rentangnya dengan [...text].slice(start_index, end_index).join(""), bukan text.slice.
  • url diambil dari hasil tool, jadi fragmen #… yang ditulis model tidak ikut. title juga dari hasil tool; bila hasil tanpa judul, teks tautannya yang dipakai.

Stream

  • Satu response.created dan response.in_progress per request, walau ada beberapa iterasi.
  • Per panggilan tool: response.output_item.added (item web_search_call, status: "in_progress", action belum berisi sources), lalu response.web_search_call.in_progress dan response.web_search_call.searching. Setelah hasil tiba: response.web_search_call.completed, lalu response.output_item.done dengan item lengkap. Tool gagal: response.output_item.done dengan status: "failed", tanpa .completed.
  • open_page memakai event yang sama karena itemnya juga web_search_call.
  • x_search_call hanya mengirim response.output_item.added dan response.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 semua response.output_text.delta dan sebelum response.output_text.done.
  • Penutup: response.completed, atau response.incomplete bila status incomplete.
  • Selama tool berjalan, api mengirim komentar SSE : ping tiap 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 tetap completed.
  • max_tool_calls habis dan request tidak punya tool fungsi milikmu → iterasi berikutnya langsung panggilan akhir dengan tool_choice: "none". Bila ada tool fungsi milikmu, loop berlanjut (tool fungsimu tetap bisa dipanggil) dan panggilan server tool berikutnya failed.
  • Credit tidak cukup untuk iterasi berikutnya → status: "incomplete", incomplete_details.reason: "max_tool_calls". Teks dan item yang sudah jadi tetap dikirim. Nilai max_tool_calls ini tidak ada di enum tipe SDK OpenAI, jadi baca sebagai string. Isi saldo lalu kirim ulang.
  • max_output_tokens berlaku untuk total output semua iterasi. Habis → status: "incomplete", incomplete_details.reason: "max_output_tokens".

Melanjutkan percakapan

  • Kirim balik item output apa adanya di input. Item web_search_call dan x_search_call lama tidak dikirim ulang ke model; teks dan anotasinya tetap dipakai.
  • URL di anotasi url_citation sebelumnya boleh dibuka (open_page) di request baru.
  • input berisi item web_search_call/x_search_call tetapi tools tidak memuat tool yang sama → 400 invalid_request_error.
  • Model memanggil server tool dan tool fungsi milikmu sekaligus: server tool dijalankan dulu, lalu respons berakhir dengan item function_call milikmu. Kirim function_call_output di request berikutnya seperti biasa.

Chat Completions (format OpenAI)

Parameter

web_search_options mengaktifkan web_search dan buka halaman (web_fetch) sekaligus.

ParameterKeterangan
search_context_sizelow / medium / high → 5 / 8 / 10 hasil per pencarian. Default medium
user_locationBentuk 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_calls atau filter domain; batas biaya per request datang dari batas iterasi dan batas isi halaman ini.
  • x_search tidak tersedia di Chat. Pakai Responses atau Messages.
  • Tool fungsi milikmu boleh ikut di tools, kecuali bernama web_search (→ 400). Tool custom ditolak 400 unsupported_tool bila ada web_search_options. Bila ada tool fungsi bernama web_fetch, buka halaman otomatis tidak diaktifkan.
  • tool_choice: "required" memaksa tool di iterasi pertama saja; iterasi berikutnya auto.
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.annotations berisi {"type": "url_citation", "url_citation": {"start_index", "end_index", "url", "title"}} (bentuk bersarang resmi OpenAI), diturunkan dengan aturan yang sama seperti di Responses. annotations selalu 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 chunk finish_reason. Sesudahnya chunk usage (bila stream_options.include_usage), lalu [DONE]. Selama tool berjalan, api mengirim komentar SSE : ping tiap 10 detik.
  • URL di annotations pesan assistant sebelumnya boleh dibuka di request baru.

Batas dan akhir respons

  • Batas 8 iterasi tercapai → satu panggilan akhir dengan tool_choice: "none"; finish_reason tetap stop.
  • Credit tidak cukup untuk iterasi berikutnya → finish_reason: "length", dengan teks yang sudah jadi. Isi saldo lalu kirim ulang.
  • max_tokens / max_completion_tokens berlaku 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_file di Responses atau file dan input_audio di Chat, ditolak 400 unsupported_content.
  • Tool klien hanya function. Di Responses, custom, local_shell, apply_patch, dan shell ditolak 400 unsupported_tool bila request memuat server tool, dan item riwayatnya (mis. custom_tool_call, local_shell_call) ditolak 400 unsupported_content. Di Chat, tool custom juga ditolak unsupported_tool.
  • Parameter yang tidak punya padanan dibuang tanpa error: seed, frequency_penalty, presence_penalty, logprobs, prompt_cache_key.
  • n lebih dari 1 (Chat) → 400 unsupported_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 incomplete atau length (mis. 502 upstream_error; daftar kode di Error). Di stream, teks yang sudah terkirim tetap ada, lalu error datang sebagai event: 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 sebagai event: 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:
UnitHarga resmi acuanDefault
Web search, per pencarianUS$10 per 1.000 pencarian0,32 credit
Web fetch, per pengambilanTanpa biaya (token saja)0 credit
X search, per post yang diambilUS$5 per 1.000 post0,16 credit
X search, per profil yang diambilUS$10 per 1.000 profil0,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_turn di 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

BatasNilai
Iterasi per request8; 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 iterasi4
Panggilan tool per akun60 per menit → too_many_requests
Panjang query pencarian400 karakter → query_too_long
Hasil per pencarian10, cuplikan maks 1.000 karakter
Panjang URL web_fetch250 karakter → url_too_long
Ukuran halaman web_fetch10 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_fetch5
Timeoutsearch 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:

KodeArti
too_many_requestsBatas 60 panggilan tool per menit terlewati
invalid_tool_inputInput tool dari model tidak valid
max_uses_exceededmax_uses tercapai
query_too_longQuery lebih dari 400 karakter
unavailableMesin tool gagal atau melewati timeout

web_fetch memakai semua kode di atas, ditambah:

KodeArti
url_too_longURL lebih dari 250 karakter
url_not_allowedDomain di luar allowed_domains / termasuk blocked_domains
url_not_in_prior_contextURL belum pernah muncul di percakapan (lihat web_fetch)
url_not_accessibleHalaman gagal diambil, atau ditolak robots.txt
unsupported_content_typeJenis 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*. Parameter mcp_servers → unsupported_parameter.
  • invalid_request_error: allowed_domains dan blocked_domains dikirim bersamaan, nama tool klien bentrok dengan server tool, atau encrypted_content tidak valid. Khusus Responses dan Chat:
    • search_context_size selain low, medium, high.
    • filters.allowed_domains lebih dari 100 domain atau memakai skema (https://…).
    • user_location bukan approximate, kosong, country bukan kode 2 huruf, atau timezone bukan ID IANA; di Chat juga tanpa objek approximate.
    • Tool yang sama didefinisikan dua kali, atau max_tool_calls bukan bilangan bulat ≥ 1.
    • tool_choice hosted, atau item web_search_call/x_search_call di input, tanpa tool yang sama di tools. Bila tools tidak memuat server tool sama sekali, tool_choice hosted ditolak unsupported_tool.
  • unsupported_content: model tidak mendukung tool calling (Model … tidak mendukung isi request ini.), di semua format.
  • unsupported_content dan unsupported_parameter di Responses dan Chat: lihat jalur terjemah.

web_fetch: keamanan dan cara kerja

  • Hanya http dan https di 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 menghormati robots.txt.
  • HTML diubah menjadi teks terbaca (markdown); text/* dan JSON dikirim apa adanya. PDF dikirim sebagai dokumen bila model mendukung input PDF; selain itu unsupported_content_type.
  • Isi halaman di-cache 15 menit per URL. use_cache: false melewati cache.

Privasi

  • encrypted_content dan encrypted_index disegel 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_fetch menyimpan isi halaman publik per URL selama 15 menit, bukan isi percakapanmu.