{"serverId":"mcp-registry/com.temsor/api","tools":[{"name":"iban_validate","fixed":{"name":"iban_validate","description":"Validates an IBAN from any of 70+ countries: checksum, country length and in-country account structure, and resolves the bank and branch codes.\n\nMost free libraries stop at the mod-97 checksum. That only says the digits are self-consistent — not that the number could exist in that country. This checks the country's BBAN structure too, so a wrong-length or wrong-shaped account is rejected before your payment file reaches the bank. When only the two check digits are wrong, the correct ones are com","inputSchema":{"type":"object","$schema":"https://json-schema.org/draft/2020-12/schema","required":["iban"],"properties":{"iban":{"type":"string","maxLength":42,"minLength":5,"description":"IBAN, with or without spaces."},"expectCountry":{"type":"string","maxLength":2,"minLength":2,"description":"Expected country code (ISO 3166-1 alpha-2)."}}},"annotations":{"readOnlyHint":true},"title":"IBAN Validation"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: true (inferred from the name).","verify":true}],"tokensBefore":247,"tokensAfter":247},{"name":"pbx_calls_get","fixed":{"name":"pbx_calls_get","description":"Get one call by id with transfer graph — customer detail drawer.\n\nGET /v1/pbx/calls/get?call_id=…. Scoped by x-temsor-pbx-key. found=false if missing. Idle $0.","inputSchema":{"type":"object","$schema":"https://json-schema.org/draft/2020-12/schema","required":["call_id"],"properties":{"call_id":{"type":"string","maxLength":80,"minLength":1,"description":"Call id (e.g. call_msp_002)."}}},"annotations":{"readOnlyHint":true},"title":"PBX Get Call"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: true (inferred from the name).","verify":true}],"tokensBefore":120,"tokensAfter":120},{"name":"pbx_dictionary_add","fixed":{"name":"pbx_dictionary_add","description":"Add a synonym/alias (tenant-scoped or global demo) — E4 compounding thickens search boost + Fact extract. ≤60/hour/key → 429. Idle $0. No invented premiums.\n\nPOST /v1/pbx/dictionary/add {term, alias, domain:hotel|pbx_provider|insurance|finance|energy|automotive, scope?:pbx|global}. Managed SaaS compounding (E4): tenant-scoped aliases thicken search + fact extract. No invented premiums/prices. Idle $0, no LLM. Legacy keys (otel, santral_firmasi, msp…) still accepted.","inputSchema":{"type":"object","$schema":"https://json-schema.org/draft/2020-12/schema","required":["term","alias"],"properties":{"kind":{"enum":["imei","tarife","oda","oda_tipi","klima","check_out","iade","sku","police","hasar","yenileme","abone","kesinti","fatura","kart","iban","sube","other"],"type":"string","description":"Fact kind; inferred from seed term when omitted."},"term":{"type":"string","maxLength":64,"minLength":2,"description":"Canonical term (e.g. AC, tariff). Plain Turkish preferred."},"alias":{"type":"string","maxLength":64,"minLength":2,"description":"Synonym / alias to add (e.g. cooling, line package)."},"boost":{"type":"number","maximum":5,"minimum":1,"description":"Search boost weight (default 2)."},"scope":{"enum":["pbx","global"],"type":"string","description":"pbx = scoped to x-temsor-pbx-key; global = demo-wide. Default: pbx if registered key, else global."},"domain":{"enum":["hotel","pbx_provider","insurance","finance","energy","automotive","otel","santral_firmasi","sigorta","finans","enerji","otomotiv","msp"],"type":"string","default":"hotel","description":"Domain: hotel | pbx_provider | insurance | finance | energy | automotive (legacy keys + msp accepted)."},"hint_en":{"type":"string","maxLength":160},"hint_tr":{"type":"string","maxLength":160}}},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false},"title":"PBX Dictionary Add Alias"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: false, destructiveHint: false, idempotentHint: false (inferred from the name).","verify":true}],"tokensBefore":504,"tokensAfter":504},{"name":"pbx_facts","fixed":{"name":"pbx_facts","description":"List extracted facts (IMEI, room, tariff…) from the durable index — filter by call_id, kind, domain, q.\n\nGET /v1/pbx/facts?call_id=&kind=&domain=hotel|pbx_provider|insurance|finance|energy|automotive|all&q=&limit=50. Facts come from transcript extract + domain dictionary; persist in pbx-index. Scoped by x-temsor-pbx-key. Idle $0. No DID sales. Right-to-erasure ready. Advanced: own PBX/Asterisk stays on customer.","inputSchema":{"type":"object","$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"q":{"type":"string","maxLength":200,"description":"Free-text filter over kind + value + call_id."},"kind":{"type":"string","maxLength":32,"description":"Fact kind key (imei, oda, tarife, ...) or all."},"limit":{"type":"integer","default":50,"maximum":200,"minimum":1,"description":"Max facts to return (1–200)."},"domain":{"enum":["hotel","pbx_provider","insurance","finance","energy","automotive","otel","santral_firmasi","sigorta","finans","enerji","otomotiv","msp","all"],"type":"string","description":"Domain slice: hotel | pbx_provider | insurance | finance | energy | automotive | all (legacy keys + msp accepted)."},"call_id":{"type":"string","maxLength":80,"description":"Filter by call id (e.g. call_msp_001)."}}},"annotations":{"readOnlyHint":true},"title":"PBX Facts List"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: true (inferred from the name).","verify":true}],"tokensBefore":356,"tokensAfter":356},{"name":"pbx_facts_get","fixed":{"name":"pbx_facts_get","description":"Get one extracted fact by id — detail drawer for site + customer.\n\nGET /v1/pbx/facts/get?id=…. Scoped by x-temsor-pbx-key. found=false if missing. Idle $0. No DID sales.","inputSchema":{"type":"object","$schema":"https://json-schema.org/draft/2020-12/schema","required":["id"],"properties":{"id":{"type":"string","maxLength":80,"minLength":1,"description":"Fact id (e.g. fact_001)."}}},"annotations":{"readOnlyHint":true},"title":"PBX Get Fact"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: true (inferred from the name).","verify":true}],"tokensBefore":119,"tokensAfter":119},{"name":"pbx_index_partial","fixed":{"name":"pbx_index_partial","description":"Upsert mid-call partial index (utterances → fact/promise hints). Path to ≤400ms whisper; ≤600/hour/key → 429; idle $0.\n\nPOST /v1/pbx/index/partial {call_id, text?, speaker?, t_ms?, is_final?, live?, end_call?, promote?}. Streams partial STT queue into accumulating Fact/Promise hints while the call is live. No Temsor STT/LLM — customer posts text. Managed SaaS in-call index; no DID sales. Own PBX optional footnote. Idle $0.","inputSchema":{"type":"object","$schema":"https://json-schema.org/draft/2020-12/schema","required":["call_id"],"properties":{"live":{"type":"boolean","description":"Default true while call is live."},"t_ms":{"anyOf":[{"type":"integer","maximum":86400000,"minimum":0},{"type":"null"}]},"text":{"type":"string","maxLength":2000,"description":"Partial utterance / snippet (customer STT or demo). Empty = metadata-only."},"pbx_id":{"type":"string","maxLength":64},"call_id":{"type":"string","maxLength":80,"minLength":1,"description":"Live call id to upsert partial index for."},"promote":{"type":"boolean","description":"Promote heuristic hints into durable Promise/Fact docs."},"speaker":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}]},"end_call":{"type":"boolean","description":"Mark live=false; idle $0 for this call."},"is_final":{"type":"boolean","description":"Finalized utterance span (vs interim)."}}},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":true},"title":"PBX In-Call Partial Index Upsert"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: false, destructiveHint: false, idempotentHint: true (inferred from the name).","verify":true}],"tokensBefore":387,"tokensAfter":387},{"name":"pbx_index_partial_get","fixed":{"name":"pbx_index_partial_get","description":"GET mid-call partial index — accumulating facts/promises/snippets while live.\n\nGET /v1/pbx/index/partial/get?call_id=…. Returns live partial state for whisper ≤400ms path. Idle $0 when no live call. Managed SaaS in-call index; no DID sales. Own PBX optional footnote.","inputSchema":{"type":"object","$schema":"https://json-schema.org/draft/2020-12/schema","required":["call_id"],"properties":{"call_id":{"type":"string","maxLength":80,"minLength":1,"description":"Call id whose live partial index to read."}}},"annotations":{"readOnlyHint":true},"title":"PBX In-Call Partial Index Read"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: true (inferred from the name).","verify":true}],"tokensBefore":156,"tokensAfter":156},{"name":"pbx_persons","fixed":{"name":"pbx_persons","description":"Light CRM from call graph / facts — caller phones+names and extension identities seen on transfers.\n\nGET /v1/pbx/persons?call_id=&kind=caller|extension|all&q=&limit=50. Durable Person rows from pbx-index plus derived extension identities (ext_NNN) from Transfer edges / promise.ext. Scoped by x-temsor-pbx-key. Idle $0. No DID sales. Right-to-erasure ready. Advanced: own PBX/Asterisk stays on customer.","inputSchema":{"type":"object","$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"q":{"type":"string","maxLength":200,"description":"Free-text over names, phones, org, extensions, facts."},"kind":{"enum":["caller","extension","all"],"type":"string","description":"caller = durable Person; extension = derived from call-graph hops; all = both."},"limit":{"type":"integer","default":50,"maximum":200,"minimum":1,"description":"Max persons to return (1–200)."},"call_id":{"type":"string","maxLength":80,"description":"Filter persons seen on this call id."},"include_extensions":{"type":"boolean","description":"Include derived extension identities (default true)."}}},"annotations":{"readOnlyHint":true},"title":"PBX Persons List"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: true (inferred from the name).","verify":true}],"tokensBefore":314,"tokensAfter":314},{"name":"pbx_persons_get","fixed":{"name":"pbx_persons_get","description":"Get one light-CRM identity by id — caller Person or derived extension.\n\nGET /v1/pbx/persons/get?id=per_001|ext_101. Scoped by x-temsor-pbx-key. found=false if missing. Idle $0. No DID sales.","inputSchema":{"type":"object","$schema":"https://json-schema.org/draft/2020-12/schema","required":["id"],"properties":{"id":{"type":"string","maxLength":80,"minLength":1,"description":"Person id (e.g. per_001) or extension id (e.g. ext_101)."}}},"annotations":{"readOnlyHint":true},"title":"PBX Get Person"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: true (inferred from the name).","verify":true}],"tokensBefore":134,"tokensAfter":134},{"name":"pbx_promises_act","fixed":{"name":"pbx_promises_act","description":"E1 moat: who→whom→promise → orchestra handoff intent (whisper/transfer/hold). Idle $0. No live PSTN. Own PBX = advanced footnote.\n\nPOST /v1/pbx/promises/act {promise_id, action?}. Loads the promise + call graph, suggests whisper/transfer/hold, records orchestra intent with source_type=promise for agent handoff. Managed SaaS runtime. ≤120/hour/key (shares orchestra bucket). Idle $0. carrier/pstn always false. No cross-tenant graph merge. Advanced: not Asterisk-first glue; own PBX optional footnot","inputSchema":{"type":"object","$schema":"https://json-schema.org/draft/2020-12/schema","required":["promise_id"],"properties":{"action":{"enum":["whisper","hold","transfer","pci_stop","snoop"],"type":"string","description":"Default whisper. transfer uses graph stuck_at / promise.ext."},"pbx_id":{"type":"string","maxLength":64},"agent_ext":{"type":"string","maxLength":64},"promise_id":{"type":"string","maxLength":64,"minLength":2,"description":"Open (or any) promise id — closed loop reads call graph then records orchestra intent."},"skip_forward":{"type":"boolean","description":"Default true — record intent only."},"stasis_webhook_url":{"type":"string","maxLength":500}}},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":true},"title":"Promise → Orchestra Closed Loop"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: false, destructiveHint: true, idempotentHint: true (inferred from the name).","verify":true}],"tokensBefore":341,"tokensAfter":341},{"name":"pbx_promises_close","fixed":{"name":"pbx_promises_close","description":"Mark an open promise kept or broken with an optional privacy-safe note — makes the sales demo writable, not read-only. ≤60/hour/key → 429.\n\nPOST /v1/pbx/promises/close {promise_id, status:kept|broken, note?}. Phones/emails in note are scrubbed. Scoped by x-temsor-pbx-key when set. Idle $0 — no LLM/PSTN.","inputSchema":{"type":"object","$schema":"https://json-schema.org/draft/2020-12/schema","required":["promise_id","status"],"properties":{"note":{"type":"string","maxLength":200,"description":"Optional short operator note. Phones/emails stripped (privacy-safe)."},"status":{"enum":["kept","broken"],"type":"string","description":"Close outcome: kept (honoured) or broken (not kept)."},"promise_id":{"type":"string","maxLength":64,"minLength":2,"description":"Promise id (prm_*). Sales demo marks open promises kept|broken."}}},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":true},"title":"PBX Close Promise"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: false, destructiveHint: true, idempotentHint: true (inferred from the name).","verify":true}],"tokensBefore":244,"tokensAfter":244},{"name":"pbx_promises_export","fixed":{"name":"pbx_promises_export","description":"Export open/broken promises as CSV or JSON — hotel / PBX-provider unclosed-promise sales list.\n\nGET /v1/pbx/promises/export?status=open|closed&format=csv|json. CSV/JSON include closed_at, close_note, path crumbs. Scoped by x-temsor-pbx-key when set. Idle $0.","inputSchema":{"type":"object","$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"format":{"enum":["csv","json"],"type":"string","default":"csv","description":"Export format."},"status":{"enum":["open","kept","broken","unknown","all","closed"],"type":"string","default":"open","description":"Promise status filter; closed = kept|broken. Sales demo uses open."}}},"annotations":{"readOnlyHint":true},"title":"PBX Promises Export"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: true (inferred from the name).","verify":true}],"tokensBefore":192,"tokensAfter":192},{"name":"pbx_search","fixed":{"name":"pbx_search","description":"Agent archive search over call promises and facts — voice-Google for call-ops, not a receptionist bot. Idle $0.\n\nDemo index + domain dictionary v0. Filters: status, date, ext, competitor, stuck_after (transfer/handoff hop). Returns call-graph path + transfer edges for orchestration. Idle $0. No live PSTN.","inputSchema":{"type":"object","$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"q":{"type":"string","default":"","maxLength":200,"description":"Full-text query over promises, facts, and call summaries."},"ext":{"type":"string","maxLength":16},"status":{"enum":["open","kept","broken","unknown"],"type":"string"},"date_to":{"type":"string","maxLength":40,"description":"ISO date/time upper bound."},"date_from":{"type":"string","maxLength":40,"description":"ISO date/time lower bound (promise.when_iso / call.started_at)."},"competitor":{"type":"string","maxLength":64},"stuck_after":{"type":"string","maxLength":16,"description":"Filter: promise stuck after transfer to this extension (to_ext hop)."}}},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":true},"title":"Voice Archive Search"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: false, destructiveHint: true, idempotentHint: true (inferred from the name).","verify":true}],"tokensBefore":298,"tokensAfter":298},{"name":"pbx_status","fixed":{"name":"pbx_status","description":"Control-plane status — promise/orchestra/search counts + idle $0. No DID sales.\n\nGET /v1/pbx/status. Scoped by x-temsor-pbx-key when set. Derived index on Temsor for agent search/orchestration. Idle $0. Advanced: own PBX/Asterisk stays on customer.","inputSchema":{"type":"object","$schema":"https://json-schema.org/draft/2020-12/schema","properties":{},"description":"No input — scoped by x-temsor-pbx-key when set."},"annotations":{"readOnlyHint":true},"title":"PBX Status"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: true (inferred from the name).","verify":true}],"tokensBefore":127,"tokensAfter":127},{"name":"pbx_whisper_status","fixed":{"name":"pbx_whisper_status","description":"Capability: mode=stub|ready from TEMSOR_RTP_*. No live RTP on forge; idle $0.\n\nGET /v1/pbx/whisper/status. Reports MediaBridge config presence (TEMSOR_RTP_PATH). mode=ready means path env set — not that Asterisk RTP is flowing. live_rtp/listening always false on forge (R2–R3 IVR sidecar; R4 lab E2E harness). No ≤400ms production claim. TEMSOR_RTP_LAB=1 → optional lab_latency_ms on suggest. No DID sales.","inputSchema":{"type":"object","$schema":"https://json-schema.org/draft/2020-12/schema","properties":{},"description":"No input — TEMSOR_RTP_* from process env."},"annotations":{"readOnlyHint":true},"title":"PBX Whisper RTP Status"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: true (inferred from the name).","verify":true}],"tokensBefore":172,"tokensAfter":172},{"name":"phone_validate","fixed":{"name":"phone_validate","description":"Validates and normalises any phone number to E.164, with structural checks for every country calling code.\n\nFor signup and checkout flows that need to store one canonical form and reject typos early. Any common input (spaces, dashes, brackets, 00 or + prefix, a stray national trunk zero) comes back as E.164 plus national notation, with the country resolved from the calling code. Numbers without an international prefix use `defaultCountry` (US when omitted), so (415) 555-0134 and +1 415 555 0134 ","inputSchema":{"type":"object","$schema":"https://json-schema.org/draft/2020-12/schema","required":["phone"],"properties":{"phone":{"type":"string","maxLength":30,"minLength":4,"description":"Phone number in any common format."},"defaultCountry":{"type":"string","maxLength":2,"minLength":2,"description":"ISO 3166-1 alpha-2 country to assume when the number has no international prefix. Defaults to US."}}},"annotations":{"readOnlyHint":true},"title":"Phone Number Validation"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: true (inferred from the name).","verify":true}],"tokensBefore":265,"tokensAfter":265},{"name":"tr_address_parse","fixed":{"name":"tr_address_parse","description":"Splits a free-form Turkish address into neighbourhood, street, building, floor, flat, district, province and postcode.\n\nHandles the abbreviation chaos (Mah./Mh., Cd./Cad., Sk./Sok., No:12/5, K:3 D:7), cross-checks the province against the postcode, repairs misspelled district names against a dictionary, and returns a confidence score. Anything it could not place is listed in `unparsed` — nothing is dropped silently. Built for shipping, checkout and CRM systems that receive Turkish addresses type","inputSchema":{"type":"object","$schema":"https://json-schema.org/draft/2020-12/schema","required":["address"],"properties":{"address":{"type":"string","maxLength":500,"minLength":3,"description":"Free-text address."},"defaultProvince":{"type":"string","description":"Province to assume when the address has none."}}},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false},"title":"Turkish Address Parser"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: false, destructiveHint: false, idempotentHint: false (inferred from the name).","verify":true}],"tokensBefore":240,"tokensAfter":240},{"name":"tr_posta_kodu","fixed":{"name":"tr_posta_kodu","description":"Validates a 5-digit Turkish postal code and resolves the province from the first two digits (plate map).\n\nPTT postal codes are five digits; the leading pair matches the province plate code for the 81 provinces. This endpoint checks the shape, maps 01–81 to the province name, and returns null with confidence none when the prefix is outside that range — it does not invent a district. District-level resolution needs the full PTT directory and is out of scope here.","inputSchema":{"type":"object","$schema":"https://json-schema.org/draft/2020-12/schema","required":["postalCode"],"properties":{"postalCode":{"type":"string","maxLength":10,"minLength":3,"description":"Turkish 5-digit postal code, with or without spaces."}}},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false},"title":"Turkish Postal Code"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: false, destructiveHint: false, idempotentHint: false (inferred from the name).","verify":true}],"tokensBefore":214,"tokensAfter":214},{"name":"tr_qr_odeme","fixed":{"name":"tr_qr_odeme","description":"Builds a person-to-person TR Karekod (FAST) payment payload from IBAN, name and optional TRY amount. Text only — no PNG.\n\nTurkish instant payments (FAST) can start from a TR Karekod that encodes the payee IBAN and name in EMV-style TLV. This builds the person-to-person organisation (payload format indicator 750210): application template with IBAN, payee name, optional 12-digit kuruş amount, optional free-text explanation, and a CRC-16/CCITT-FALSE trailer. The Turkish IBAN is normalised and check","inputSchema":{"type":"object","$schema":"https://json-schema.org/draft/2020-12/schema","required":["iban","name"],"properties":{"iban":{"type":"string","description":"Beneficiary Turkish IBAN (with or without spaces)."},"name":{"type":"string","description":"Payee name shown to the payer (2–26 chars after trim)."},"amount":{"type":"number","description":"TRY amount; omitted → static QR (payer enters amount)."},"currency":{"type":"string","description":"Must be TRY if provided."},"explanation":{"type":"string","description":"Optional remittance note (application free field 10)."},"generatorCode":{"type":"string","description":"QR generator / EFT code (4 digits). Defaults to last 4 of the IBAN bank code."}}},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false},"title":"Turkish FAST / TR Karekod Payload"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: false, destructiveHint: false, idempotentHint: false (inferred from the name).","verify":true}],"tokensBefore":350,"tokensAfter":350},{"name":"tr_validate","fixed":{"name":"tr_validate","description":"Validates Turkish national ID, tax number, IBAN, licence plate, IMEI, barcodes, KEP, MERSİS, postal code and ISBN from one endpoint, with type auto-detection.\n\nGoes past a yes/no: resolves the bank behind an IBAN, the province behind a licence plate and the GS1 country prefix behind a barcode. Pure local computation — no upstream service is called, so latency is microseconds and the answer never changes for the same input.","inputSchema":{"type":"object","$schema":"https://json-schema.org/draft/2020-12/schema","required":["value"],"properties":{"type":{"enum":["auto","tckn","vkn","iban","plate","imei","gtin","kep","mersis","postal","isbn"],"type":"string","default":"auto","description":"Omitted → inferred from the format."},"value":{"type":"string","maxLength":64,"minLength":1,"description":"Value to validate."}}},"annotations":{"readOnlyHint":true},"title":"Turkish ID & Number Validation"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: true (inferred from the name).","verify":true}],"tokensBefore":241,"tokensAfter":241}],"toolsChanged":20,"tokensSaved":0,"todo":[{"tool":"email_verify","params":["rejectRoleAccounts","rejectFreeProviders"]},{"tool":"pbx_audio_chunk","params":["t_ms","pbx_id","call_id"]},{"tool":"pbx_dictionary_add","params":["hint_en","hint_tr"]},{"tool":"pbx_index_partial","params":["t_ms","pbx_id","speaker"]},{"tool":"pbx_ingest_transcript","params":["ext","who","pbx_id","call_id"]},{"tool":"pbx_promises_act","params":["pbx_id","agent_ext","stasis_webhook_url"]},{"tool":"pbx_search","params":["ext","status","competitor"]},{"tool":"tr_invoice_build","params":["lines","notes","customer","supplier","issueDate","issueTime","invoiceTypeCode","orderReferenceId"]},{"tool":"tr_money_to_words","params":["currency","wrapHash"]}],"note":"Deterministic fixes. Changes marked verify need a human look before shipping (renames, inferred annotations, inferred types, removed text). Parameter descriptions in `todo` need to be written by someone who knows the API."}