Alpaca Trading API integration for Model Context Protocol (MCP)
Simpler.Asia is installed from its publisher's own source and answers where it runs, so this marketplace is not in the path of a single call. There is no address here to send one to, and a panel that pretended otherwise would be showing you an answer we made up. Install it and call it from your own client — the Installation tab has the entry for each one.
What it does
Free back office for small businesses in Singapore and Southeast Asia: invoices, expenses, stock.
Quickstart
# 1 — add it to Claude Code
claude mcp add --scope user --transport http simpler-asia-mcp https://simpler.asia/mcp
# 2 — ask your agent for something these tools do
# simpler.directory, simpler.describe_service, simpler.invoke and 315 more
Simpler.Asia costs nothing on mcprush: there is no plan to choose here, no cap to set and nothing mcprush can bill you for.
Collected from a public index. Nobody has claimed this account, so nothing here was written by its author — claim it if it is yours.
Where are you running it?
Every route below installs the same thing and ends at the same approval screen. Nothing here runs on your machine and nothing runs on ours: this server answers at its publisher’s own address, and what you install is the connection straight to it.
This is a public server: it answers at its publisher’s own address and this marketplace is not in the path. Claude Code registers it in one command; --scope user makes it available in every project. The transport below is http, as the publisher's own manifest declares it.
claude mcp add --scope user --transport http simpler-asia-mcp https://simpler.asia/mcpReconnect, or start a new session, and the tools appear in the model’s tool list.
One config entry pointing straight at the publisher’s own address — this marketplace is not in the path, and nothing from this listing executes on your machine.
318 tools, with what each one reads, writes and reaches shown before you agree — the same list on every route above. Read the tool surface.
Tool surface
What the model actually sees. Descriptions are diffed on every release — see version history.
DISCOVERY TIER 1 of 3 — the service directory: one token-dense line per service (s:name st:status cost:class ops:N — purpose). START HERE instead of reading every tool. No auth required. NEXT: simpler.describe_service with a service name from the listing.
No parameter schema on file.
DISCOVERY TIER 2 of 3 — one service's operations and entity shapes from the live catalog, token-dense (op lines name the underlying tool). No auth required. NEXT: simpler.invoke {service, operation, args} — or call the named tool directly.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| service | string | yes | A service name from simpler.directory. |
DISCOVERY TIER 3 of 3 — execute one operation: dispatches to the underlying generated tool (same gates, same envelope, same idempotency as calling it directly). Requires auth. args = the underlying tool's arguments object.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| service | string | yes | A service name from simpler.directory. |
| operation | string | yes | An op name from simpler.describe_service (e.g. 'create'), or the full tool name (e.g. 'sticky_note_create'). |
| args | object | no | Arguments for the resolved tool. |
DISCOVERY TIER 0 — the OUTCOME MENU: one line per common business outcome, each mapped to ONE tool with one-call notes (composites: ONE call creates the whole document). START HERE for a business task. No auth required. NEXT: call the named tool directly, or simpler.directory for the full catalog.
No parameter schema on file.
Check a parked approval by approval_id (returned in an APPROVAL_REQUIRED refusal). States: pending (the account owner has not decided — tell the user, do NOT retry the original call), executed (done — the result rides this response; never re-run the call; an approved invoice_share or quote_share keeps no link or document here, so read the current link with that tool and action 'get' as result.link
| Parameter | Type | Required | Notes |
|---|---|---|---|
| approval_id | string | yes | The approval id from the APPROVAL_REQUIRED refusal envelope. |
Send a cross-tenant AI-to-AI message into another tenant's agent_note inbox — the door that turns a cross_tenant_comm consent grant into an actual reach. Both tenants must be KYB-approved and the recipient must hold an active grant (claims can narrow it further); every recipient-side failure refuses identically so the network can't be probed for who exists — only your OWN unapproved KYB answers di
| Parameter | Type | Required | Notes |
|---|---|---|---|
| from_tenant_id | string | no | — |
| consent_grant_id | string | no | — |
| subject | string | no | — |
| body | string | no | — |
| related_entity_type | string | no | — |
| related_entity_id | string | no | — |
| status | string | no | — |
| to_tenant_id | string | yes | The recipient tenant id — must be another tenant, never your own. The recipient must hold an active cross_tenant_comm consent grant and both tenants must be KYB-approved, or the door refuses uniformly |
Create-or-merge a contact keyed on email-then-phone identity — the sync door the future desktop harness and ingest lanes write through. Matching probes email first, then phone; a hit MERGES only the fields you send (omitted fields keep their stored values, so a partial sync payload can never wipe a curated field), a miss creates. Status moves still obey the transition machine — an upsert cannot ju
| Parameter | Type | Required | Notes |
|---|---|---|---|
| name | string | no | — |
| company | string | no | — |
| string | no | — | |
| phone | string | no | — |
| address | string | no | — |
| status | string | no | — |
| source | string | no | — |
| tags | string | no | — |
| last_contact_at | integer | no | — |
| note | string | no | Log a first note in the SAME call — ONE call makes both. |
| notes | string | no | Alias of note. |
| interaction | object | no | Log the first interaction in the same call: {type, summary, occurred_at?} — occurred_at takes "YYYY-MM-DD". |
| first_interaction | object | no | Alias of interaction. |
Logs a new expense — amount_cents must be integer CENTS (a decimal string via amount also works, and category resolves to a category_id by name). A same-amount, same-UTC-day duplicate for the same user is refused as CONFLICT unless you resend identically with force: true. Status is honor-or-refuse: admin/owner creators land 'approved' by default (or may request it explicitly), everyone else al
| Parameter | Type | Required | Notes |
|---|---|---|---|
| vendor | string | no | — |
| amount_cents | integer | no | — |
| currency | string | no | — |
| category_id | string | no | — |
| expense_date | integer | no | — |
| receipt_key | string | no | — |
| ocr_json | string | no | — |
| notes | string | no | — |
| tags_json | string | no | — |
| subtotal_cents | integer | no | — |
| tax_amount_cents | integer | no | — |
| tax_rate_bps | integer | no | — |
| tax_type | string | no | — |
| status | string | no | — |
| submitted_at | integer | no | — |
| approved_by | string | no | — |
| approved_at | integer | no | — |
| rejection_reason | string | no | — |
| rejected_at | integer | no | — |
| reimbursed_at | integer | no | — |
Sends your own draft expense into the approval queue — draft only; an already-submitted or resolved expense refuses CONFLICT, and only the expense's own creator may submit it. Nobody is notified automatically — approvers see it appear in the Team Claims view. NEXT: expense_approve or expense_reject (admin/owner).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| vendor | string | no | — |
| amount_cents | integer | no | — |
| currency | string | no | — |
| category_id | string | no | — |
| expense_date | integer | no | — |
| receipt_key | string | no | — |
| ocr_json | string | no | — |
| notes | string | no | — |
| tags_json | string | no | — |
| subtotal_cents | integer | no | — |
| tax_amount_cents | integer | no | — |
| tax_rate_bps | integer | no | — |
| tax_type | string | no | — |
| status | string | no | — |
| submitted_at | integer | no | — |
| approved_by | string | no | — |
| approved_at | integer | no | — |
| rejection_reason | string | no | — |
| rejected_at | integer | no | — |
| reimbursed_at | integer | no | — |
Approves a submitted expense claim — requires the admin or owner role, and only a 'pending' expense qualifies (CONFLICT otherwise). Stamps approved_by and approved_at with the caller and the current time; once approved, the row's content freezes for everyone except the approver themselves. NEXT: expense_reimburse (owner only) to pay it out.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| vendor | string | no | — |
| amount_cents | integer | no | — |
| currency | string | no | — |
| category_id | string | no | — |
| expense_date | integer | no | — |
| receipt_key | string | no | — |
| ocr_json | string | no | — |
| notes | string | no | — |
| tags_json | string | no | — |
| subtotal_cents | integer | no | — |
| tax_amount_cents | integer | no | — |
| tax_rate_bps | integer | no | — |
| tax_type | string | no | — |
| status | string | no | — |
| submitted_at | integer | no | — |
| approved_by | string | no | — |
| approved_at | integer | no | — |
| rejection_reason | string | no | — |
| rejected_at | integer | no | — |
| reimbursed_at | integer | no | — |
Log an interaction — call, meeting, email, message, visit, payment, or other — against a contact. The ONE activity-logging door every lane funnels through, so the contact's last_contact_at freshness bumps no matter which surface logged the touch; the bump never moves backward, so importing older history can never regress a fresher touch. Accepts contact_name, contact_email or contact_phone in plac
| Parameter | Type | Required | Notes |
|---|---|---|---|
| contact_id | string | no | — |
| interaction_type | string | no | — |
| summary | string | no | — |
| occurred_at | integer | no | — |
| source_ref | string | no | — |
| contact_name | string | no | No contact_id handy? Resolves the contact by exact name — a unique match wins; ambiguity refuses with the candidate ids. |
| contact_email | string | no | Resolves the contact by exact email when contact_id is absent. |
| contact_phone | string | no | Resolves the contact by exact phone when contact_id is absent. |
ONE call creates the whole document: claims the next invoice number, then writes the header plus every line in items ([{description, quantity, unit_price_cents}], integer CENTS). client_name finds a client by name or creates one. Birth status 'paid' needs items in the same call. tax_scheme sg_gst or my_sst taxes each line by its tax_code (refusals: see tax_scheme). When present, the second conte
| Parameter | Type | Required | Notes |
|---|---|---|---|
| client_id | string | no | — |
| invoice_number | string | no | — |
| status | string | no | — |
| issue_date | integer | no | — |
| due_date | integer | no | — |
| currency | string | no | — |
| tax_rate_bps | integer | no | — |
| notes | string | no | — |
| payment_terms | string | no | — |
| source_type | string | no | — |
| source_id | string | no | — |
| cash_sale | integer | no | — |
| payment_method | string | no | — |
| sent_at | integer | no | — |
| paid_at | integer | no | — |
| tax_scheme | string | no | sg_gst (Singapore GST) or my_sst (Malaysia SST): each line is taxed by its tax_code at the rate in force on the issue date. Under a scheme, a tax_rate_bps other than that rate, an unknown tax_code and |
| prices_include_tax | boolean | no | true = unit prices already include the tax (the tax is worked back out of each line). Default false. Needs a tax_scheme, except on a cash sale (cash_sale 1): its total is then the amount taken, with t |
| fx_rate_to_sgd_ppm | integer | no | — |
| fx_rate_date | string | no | The date the fx rate is for, YYYY-MM-DD. Send with fx_rate_to_sgd. |
| items | array | no | ONE call creates the whole document — line items in integer CENTS ($15.00 → 1500), or unit_price as a decimal string. quantity takes up to 3 decimals (1.5 hours → 1.5); unit is an optional label (hr, |
[REQUIRES APPROVAL] Records a credit note, write-off or post-issue discount on an issued invoice. A credit_note is numbered from the credit note series, holds its tax at the invoice's rate and takes reason_code and credit_outcome: reduce_balance (default) lowers what is owed; refunded_outside records a refund the business made outside Simpler, moves no money and is how a 'paid' invoice gets one. w
| Parameter | Type | Required | Notes |
|---|---|---|---|
| invoice_id | string | no | — |
| adjustment_type | string | no | — |
| amount_cents | integer | no | — |
| currency | string | no | — |
| reason | string | no | — |
| occurred_at | integer | no | — |
| reason_code | string | no | — |
| credit_outcome | string | no | — |
| invoice_number | string | no | Alias of invoice_id — the invoice's own number (tenant-unique), resolved server-side. |
| amount | string | no | Money as a decimal STRING ("1500.00" = $1,500.00), parsed server-side. Use amount_cents for integer CENTS instead — never convert units yourself. |
| partial | boolean | no | Confirms a deliberate PARTIAL write_off below the invoice's full remaining balance (checked only when adjustment_type is write_off) — resend the SAME call with partial:true; without it a below-remaind |
Records a money-in fact row against an invoice (by invoice_id or its invoice_number) in ONE call: money is integer CENTS via amount_cents, or a decimal STRING via amount — never multiply or divide yourself. A draft invoice auto-advances to 'sent'; a cancelled invoice refuses; an amount above the remaining balance refuses unless allow_overpayment is true. status 'paid' derives from the ledger this
| Parameter | Type | Required | Notes |
|---|---|---|---|
| invoice_id | string | no | — |
| amount_cents | integer | no | — |
| currency | string | no | — |
| occurred_at | integer | no | — |
| method | string | no | — |
| note | string | no | — |
| invoice_number | string | no | Alias of invoice_id — the invoice's own number (tenant-unique), resolved server-side. |
| amount | string | no | Money as a decimal STRING ("1500.00" = $1,500.00), parsed server-side. Use amount_cents for integer CENTS instead — never convert units yourself. |
| allow_overpayment | boolean | no | Explicit override (default false): record more than the remaining balance / pay an already-settled invoice. |
| force | boolean | no | Confirms a genuine second payment when the same invoice/amount/day already has one recorded (default false refuses it as a likely duplicate) — resend the SAME call with force:true. |
Mint a sealed LHDN e-invoice in ONE call: invoice_type, line_items (unit_price_cents in integer CENTS, tax_rate_bps in basis points), and a buyer as customer_id or an inline buyer object. Refuses until myinvois_settings_save is done; invoice_type 02/03/04 also needs original_invoice_id naming a type-01 invoice with a recorded LHDN UUID, checked BEFORE the number is claimed, so a rejected note neve
| Parameter | Type | Required | Notes |
|---|---|---|---|
| customer_id | string | no | — |
| invoice_number | string | no | — |
| invoice_type | string | no | — |
| status | string | no | — |
| issue_date | string | no | — |
| currency | string | no | — |
| subtotal_cents | integer | no | — |
| tax_cents | integer | no | — |
| total_cents | integer | no | — |
| buyer_name | string | no | — |
| buyer_tin | string | no | — |
| invoice_data | string | no | — |
| reference_invoice_id | string | no | — |
| lhdn_uuid | string | no | — |
| lhdn_long_id | string | no | — |
| lhdn_submitted_at | integer | no | — |
| line_items | array | yes | Line items: [{description, quantity, unit_price_cents, tax_rate_bps?, tax_type?, classification_code?, unit_code?}]. Money is integer CENTS, tax_rate_bps is basis points (600 = 6%); tax_type/classific |
| buyer | object | no | Inline one-off buyer party — {name, tin, brn?, address?, city?, state_code?, postal_code?, country_code?, email?, contact_number?}. Required when customer_id is not given; ignored when it is. |
| original_invoice_id | string | no | The type-01 original this note references — required for invoice_type 02, 03 or 04, refused for 01. Must already carry an LHDN UUID (myinvois_invoice_record_submission). |
| payment_terms | string | no | Payment terms text for this document; defaults to the supplier profile's default_payment_terms when omitted. |
Record the UUID the LHDN MyInvois portal assigned after the owner keyed this e-invoice into the portal (its form or LHDN's Excel batch template). Simpler never submits to LHDN and never calls the MyInvois API; this only stores the UUID the owner copies back. Only a type-01 original accepts a UUID: credit, debit and refund notes are refused (they link through BillingReference), so record the UUID o
| Parameter | Type | Required | Notes |
|---|---|---|---|
| customer_id | string | no | — |
| invoice_number | string | no | — |
| invoice_type | string | no | — |
| status | string | no | — |
| issue_date | string | no | — |
| currency | string | no | — |
| subtotal_cents | integer | no | — |
| tax_cents | integer | no | — |
| total_cents | integer | no | — |
| buyer_name | string | no | — |
| buyer_tin | string | no | — |
| invoice_data | string | no | — |
| reference_invoice_id | string | no | — |
| lhdn_uuid | string | no | — |
| lhdn_long_id | string | no | — |
| lhdn_submitted_at | integer | no | — |
| id | string | yes | The myinvois_invoice id to record the LHDN UUID against (myinvois_invoice_list shows them). |
Read one sealed e-invoice by id, with its portal_field_sheet: the document's values laid out to key into the LHDN MyInvois portal form (e-invoice details, supplier, buyer, each line, totals), coded values with their meaning. Simpler never submits to LHDN; portal_field_sheet.portal_routes names the two portal routes (the online form and LHDN's Excel batch template). Refuses an id outside your tenan
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The myinvois_invoice id. |
ONE call creates the whole document: claims the next atomic quote number, then writes the header plus every line in items ([{description, quantity, unit_price_cents}], integer CENTS) together. client_name resolves an existing client by name or creates one. tax_scheme sg_gst or my_sst taxes each line by its tax_code (refusals: see tax_scheme). When present, the second content block is the quote a
| Parameter | Type | Required | Notes |
|---|---|---|---|
| client_id | string | no | — |
| quote_number | string | no | — |
| status | string | no | — |
| issue_date | integer | no | — |
| valid_until | integer | no | — |
| currency | string | no | — |
| tax_rate_bps | integer | no | — |
| notes | string | no | — |
| converted_invoice_id | string | no | — |
| tax_scheme | string | no | sg_gst (Singapore GST) or my_sst (Malaysia SST): each line is taxed by its tax_code at the rate in force on the issue date. Under a scheme, a tax_rate_bps other than that rate, an unknown tax_code and |
| prices_include_tax | boolean | no | true = unit prices already include the tax (the tax is worked back out of each line). Default false. Needs a tax_scheme. |
| items | array | no | ONE call creates the whole document — line items in integer CENTS ($15.00 → 1500), or unit_price as a decimal string. quantity takes up to 3 decimals (1.5 hours → 1.5); unit is an optional label (hr, |
| line_items | array | no | Alias of items. |
| client_name | string | no | Client by NAME — resolves to an existing client or creates one (no client_id lookup needed). |
| force | boolean | no | Confirms a create whose notes or single line item read like a payment RECEIVED or a write-off rather than a new bill — resend the SAME call with force:true to create it anyway. No effect on quote_crea |
Converts a quote into its invoice in ONE call: claims the quote's 'converted' status first (so a lost race never creates an orphan invoice), copies every live line item across, and records converted_invoice_id — nothing else to do afterward. Refuses if the quote is already converted (the error carries converted_invoice_id) or declined (revive it with quote_update first), and refuses with nothing c
| Parameter | Type | Required | Notes |
|---|---|---|---|
| client_id | string | no | — |
| quote_number | string | no | — |
| status | string | no | — |
| issue_date | integer | no | — |
| valid_until | integer | no | — |
| currency | string | no | — |
| tax_rate_bps | integer | no | — |
| notes | string | no | — |
| converted_invoice_id | string | no | — |
| tax_scheme | string | no | — |
| prices_include_tax | integer | no | — |
| id | string | yes | The quote id (quote_list shows them). |
| quote_id | string | no | Alias of id. |
Record a payment obligation against a KYB-verified partner tenant's settlement_proposals — the record-don't-move on-ramp: this writes the row only, no money moves until a later settlement-rails door executes it. amount_cents is a nonzero integer CENTS (positive = you owe them, negative = a refund/reversal record) and currency must be a 3-letter code. Requires the payee's cross_tenant_settlement co
| Parameter | Type | Required | Notes |
|---|---|---|---|
| payer_tenant_id | string | no | — |
| consent_grant_id | string | no | — |
| amount_cents | integer | no | — |
| currency | string | no | — |
| description | string | no | — |
| related_entity_type | string | no | — |
| related_entity_id | string | no | — |
| status | string | no | — |
| accepted_at | integer | no | — |
| to_tenant_id | string | yes | The payee tenant id — must be another tenant, never your own. The payee must hold an active cross_tenant_settlement consent grant and both tenants must be KYB-approved, or the door refuses uniformly w |
Create a sticky_note.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| content | string | yes | — |
| color | string | no | — |
| position_x | integer | no | — |
| position_y | integer | no | — |
| triggers_at | integer | no | — |
| z_index | integer | no | — |
| width | integer | no | — |
| height | integer | no | — |
Move stock in or out by id or item name, in one atomic write with its movements-ledger row: stock-out clamps at zero (never negative) and applied_quantity reports what actually moved. An unmatched name CREATES the item at quantity 0 first so the delivery still lands as an audited ledger row; a name matching multiple active items refuses with the candidate ids. Concurrent adjusts on the same item r
| Parameter | Type | Required | Notes |
|---|---|---|---|
| name | string | no | No id? Resolve-or-create by item name: a unique active match resolves; an unknown name CREATES the item at quantity 0 and the adjustment lands as its first ledger row. |
| quantity | integer | yes | Whole units — count whole units: 24 bags → 24 (the digit string "24" also works). |
| unit | string | no | — |
| low_stock_threshold | integer | no | — |
| cost_per_unit_cents | integer | no | — |
| sell_price_cents | integer | no | — |
| category | string | no | — |
| expiry_date | string | no | — |
| notes | string | no | Free-form note recorded on the movements-ledger row. |
| is_active | integer | no | — |
| id | string | no | The stock item id. |
| item_name | string | no | Alias of name. |
| type | string | yes | "in" | "out" — also accepts received/delivery/restock (→ in) and sold/used (→ out). |
| reason | string | no | Why the stock moved — recorded on the movements-ledger row. |
| occurred_at | string | no | When the stock ACTUALLY moved (business time): "YYYY-MM-DD" or epoch milliseconds. Omitted = now. Backdated deliveries stay distinguishable from entry time. |
[REQUIRES APPROVAL] Delegates a task to a teammate (or yourself) as a new team_assignment; status is workflow-owned and always starts 'pending' — passing status yourself fails validation instead of being silently overridden. Accepts natural language for the common fields: task_name/task for title, due_date/due for due_at ('YYYY-MM-DD', epoch millis, 'today', 'tomorrow', or 'next <weekday>'), and '
| Parameter | Type | Required | Notes |
|---|---|---|---|
| assigned_to | string | no | — |
| title | string | no | — |
| description | string | no | — |
| priority | string | no | — |
| status | string | no | — |
| due_at | integer | no | — |
| accepted_at | integer | no | — |
| started_at | integer | no | — |
| completed_at | integer | no | — |
| declined_at | integer | no | — |
| decline_reason | string | no | — |
| completion_notes | string | no | — |
| attachment_key | string | no | — |
| attachment_name | string | no | — |
| attachment_type | string | no | — |
| photos_json | string | no | — |
| artifact_id | string | no | — |
| previous_assignee | string | no | — |
| previous_status | string | no | — |
| reassigned_by | string | no | — |
Create a workflow — an AI operator's job: validates definition_json (a { nodes, edges, schedule? } graph) against the platform's node vocabulary, refusing unknown node types and any comms/message-shaped step that isn't a prepare_output node, since the platform prepares outputs but never sends them. trigger_type 'schedule' requires a schedule block; next_run_at is then computed server-side from it,
| Parameter | Type | Required | Notes |
|---|---|---|---|
| name | string | no | — |
| description | string | no | — |
| role_name | string | no | — |
| definition_json | string | no | — |
| trigger_type | string | no | — |
| is_active | integer | no | — |
| next_run_at | integer | no | — |
| imported_from | string | no | — |
List this tenant's APPROVED prepared outputs: drafts a workflow's prepare_output nodes parked for review, which a human then approved in the platform inbox. Pending and rejected drafts never appear here — approval happens only in the inbox, never through this call. Optional limit 1-100 (default 50), newest-decided first. This is the platform-prepares-never-sends handoff: the desktop harness pulls
| Parameter | Type | Required | Notes |
|---|---|---|---|
| name | string | no | — |
| description | string | no | — |
| role_name | string | no | — |
| definition_json | string | no | — |
| trigger_type | string | no | — |
| is_active | integer | no | — |
| next_run_at | integer | no | — |
| imported_from | string | no | — |
| limit | integer | no | Max rows to return, 1-100 (default 50). Out-of-range or non-integer values fall back to 50. |
Your prepaid wallet, period spend, caps, and runway as a compact line DSL (~8 lines). Requires auth (your balance is closed data). Read this BEFORE committing paid actions; pair with ai.estimate_cost to price a specific call first.
No parameter schema on file.
Price an AI task BEFORE running it: provider passthrough at wholesale cost, no markup — the per-token platform fee is retired, so text/reasoning passes through at cost. Anonymous — open catalog includes open pricing. Returns integer micro-USD plus a USD total. NEXT: run the action, then ai.budget to watch the runway.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| task | string | yes | A token-billed task name from the platform task→model map (e.g. 'assistant.ask'). |
| tokens_in | integer | no | Estimated input tokens (default 1000). |
| tokens_out | integer | no | Estimated output tokens (default 500). |
Who owes you, by client: each client's unpaid balance aged by days past its due date — current (not yet due), 1-30, 31-60, 61-90 and over 90 days — counted in the business's own days (the sales_settings time zone), so an invoice due today is still current. Only issued invoices with a balance left count: drafts, cancelled, paid, written-off and fully credited invoices never do. Money is integer CEN
| Parameter | Type | Required | Notes |
|---|---|---|---|
| client_id | string | no | One client's id, from invoice_client_search or invoice_client_list. Leave out to age every client. |
| limit | integer | no | Most client rows to return, 1-200 (default 50). totals always cover every client; truncated says whether rows were left out. |
Show one invoice, quote or receipt as the document itself. When the result has a second content block, it is the document as copy-ready plain text (title, business, billed to, dates, one line per item, the totals as printed, notes, payment terms and details, or on a receipt the day paid and the method) to paste into an email or a chat, and hosts that draw MCP Apps show the page with a Copy button.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | no | The invoice's or quote's id (invoice_list, quote_list or the create result), or a payment's id for its receipt (invoice_payment_list). |
| number | string | no | The document's number as printed, for example 'INV-2026-016' or a receipt's 'RCT-2026-001'. Send id or number, not both. |
| kind | string | no | 'invoice', 'quote' or 'receipt' (one payment's numbered receipt). Leave out to try invoice, then quote, then receipt. |
Prepare what a business sends a client about one issued invoice: purpose 'invoice', 'reminder' (overdue), 'receipt' (paid in full) or 'promise_follow_up' (promised date passed); left out, the one that fits. language 'en', 'ms' or 'zh'; left out, the client's (invoice_client_update message_language), else English. Returns to, subject, body, share_text, a mailto and link_on; share_url only for a mem
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The invoice's id, from invoice_list or invoice_read. |
| purpose | string | no | 'invoice' sends the invoice, 'reminder' asks for payment, 'receipt' thanks the client once it is paid in full, 'promise_follow_up' asks when to expect a payment the client promised by a date that has |
| language | string | no | 'en' English, 'ms' Bahasa Melayu, 'zh' Chinese. Leave out to use the client's message_language (English when none is set). |
Today's collection list, in the business's days (its sales_settings time zone). reminders: each issued invoice still owed that is 3 days before its due date, on it, or 7 or 14 days after, as its client's reminder_cadence allows (standard, from_due, overdue_only or off; set it with invoice_client_update), with the amount owed in CENTS, the step, the language and next_call (the invoice_message_prepa
No parameter schema on file.
A client's statement of account over a period of the business's own days (the sales_settings time zone): the balance they owed before it (opening), each invoice issued, payment received, credit and write-off in it with a running balance, the balance at its end (closing), and what was still owed at its end aged current / 1-30 / 31-60 / 61-90 / over 90 days past due, counted as sales_receivables cou
| Parameter | Type | Required | Notes |
|---|---|---|---|
| client_id | string | yes | The client's id, from invoice_client_search (by name) or invoice_client_list. |
| from | string | no | First day of the period, YYYY-MM-DD in the business's time zone. Default: the first day of the month of to. |
| to | string | no | Last day of the period, YYYY-MM-DD in the business's time zone, today at the latest. Default: today. |
Get one issued invoice ready to give the client, in one call: the document, the client link (made if it has none), the PDF (printed or the stored one) and the prepared message (invoice_message_prepare's words, with the link). ready lists the parts made; missing gives each other part's reason_code, reason and next_call. A turned-off link is never re-issued: invoice_share action 'rotate' waits for t
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The invoice's id, from invoice_list or invoice_read. |
| purpose | string | no | The message's purpose: 'invoice', 'reminder', 'receipt' or 'promise_follow_up' (a promised payment date has passed). Leave out to get the one that fits the invoice's state. |
| language | string | no | The message's language: 'en', 'ms' or 'zh'. Leave out to use the client's message_language (English when none is set). |
WHAT-IF / scenario lane: runs monthly data YOU supply through a seeded 5,000-path simulation of monthly revenue and costs; bands are simulation outputs, not calibrated probabilities. The paths are clustered into 3-7 outcome bands for the next 6 months, with per-month revenue and cost percentiles and deathRisk, the share of paths the engine marks closed (a distress signal, not a cash-out date). Amo
| Parameter | Type | Required | Notes |
|---|---|---|---|
| monthlyData | array | yes | 2-120 monthly rows, oldest first: { date: 'YYYY-MM', revenue, costs, customers? }. revenue and costs are amounts in currency (major units, default USD): 1500 or "1500.00" - never cents. |
| currency | string | no | The currency of every amount sent, one of 16 codes. Leave it out for USD; the output then says currency_assumed: true. |
| cash_balance | number | no | Optional: the bank balance on cash_as_of in currency (major units, negative for an overdraft). Send it with cash_as_of. |
| cash_as_of | string | no | Optional: the date of cash_balance as YYYY-MM-DD, within the last 45 days. Send it with cash_balance. |
| declared_totals | object | no | Optional: the revenue and costs totals your own source shows for the months sent, in currency. A total more than 0.5% away from the months' sum refuses with SIMPLER_FORECAST_GRID_TOTALS_MISMATCH. |
| drivers | array | no | Optional: at most 20 what-if drivers, applied to the same simulated paths as the base. |
| cash_currency | string | no | Optional: the currency of cash_balance when it is not currency. Send it with cash_balance and cash_as_of. |
| open_receivables | array | no | Optional: invoices your own accounting system shows unpaid, at most 2,000 rows (more refuses with SIMPLER_FORECAST_AGENT_INPUT_TOO_LARGE). Each is paid on the receipt-timing curve from its due date. |
| paid_history | array | no | Optional: invoices already paid, at most 5,000 rows (more refuses with SIMPLER_FORECAST_AGENT_INPUT_TOO_LARGE). The receipt-timing curve learns from the days between due_date and paid_at; with no paid |
| open_payables | array | no | Optional: bills you owe, at most 2,000 rows (more refuses with SIMPLER_FORECAST_AGENT_INPUT_TOO_LARGE). Each is paid on its due date (one already due is paid on the first modelled day). |
| recurring | array | no | Optional: repeating money, at most 100 rows (more refuses with SIMPLER_FORECAST_AGENT_INPUT_TOO_LARGE). direction out leaves on each date; direction in falls due on each date and is paid on the receip |
| cash_on | string | no | Optional, with any of open_receivables, paid_history, open_payables or recurring: a date YYYY-MM-DD inside the 13 weeks; needs cash_balance and cash_as_of within 31 days. The answer adds that day's en |
Run the tenant's REAL forecast from the books — cash receipts (recorded invoice payments by payment date, plus paid invoices with no recorded payment at their paid date, flagged) and expenses by expense date, monthly in the tenant's base currency, up to the last complete month (the current month is left out; months are the business's calendar months in its own time zone, set in sales settings, Asi
| Parameter | Type | Required | Notes |
|---|---|---|---|
| cash_balance | number | no | Optional: the bank balance on cash_as_of in cash_currency (major units, negative for an overdraft). Send cash_balance, cash_currency and cash_as_of together; owner or admin only. Refused with SIMPLER_ |
| cash_currency | string | no | The currency of cash_balance. |
| cash_as_of | string | no | The date of cash_balance as YYYY-MM-DD. |
Read the tenant's STORED forecast — the verify-read for this rail. view picks the answer, one of summary, monthly, variance, scenarios, weekly (default summary). summary: the outcome bands (label, growth_direction, probability_pct, final_month_revenue_low and _high, distress_risk_pct, path_count), the cash block, blend {yours_pct, peers_pct} (the share of the result from this business's own histor
| Parameter | Type | Required | Notes |
|---|---|---|---|
| view | string | no | One of summary, monthly, variance, scenarios, weekly; leave it out for summary. |
| drivers | array | no | Optional, views scenarios and weekly only: at most 20 drivers in each of up to 3 sets, one flat list; weekly takes one set (no set field). |
| cash_on | string | no | View weekly only: a date YYYY-MM-DD inside the 13 weeks; the answer adds that day's end-of-day balance. |
| open_receivables | array | no | Optional, view weekly only, joined with the books' own for this answer: invoices your own accounting system shows unpaid, at most 2,000 rows (more refuses with SIMPLER_FORECAST_AGENT_INPUT_TOO_LARGE). |
| paid_history | array | no | Optional, view weekly only, joined with the books' own for this answer: invoices already paid, at most 5,000 rows (more refuses with SIMPLER_FORECAST_AGENT_INPUT_TOO_LARGE). The receipt-timing curve l |
| open_payables | array | no | Optional, view weekly only, joined with the books' own for this answer: bills you owe, at most 2,000 rows (more refuses with SIMPLER_FORECAST_AGENT_INPUT_TOO_LARGE). Each is paid on its due date (one |
| recurring | array | no | Optional, view weekly only, joined with the books' own for this answer: repeating money, at most 100 rows (more refuses with SIMPLER_FORECAST_AGENT_INPUT_TOO_LARGE). direction out leaves on each date; |
[paid: $0.042/image max] Generate 1-3 images from a text prompt on the first lane that delivers, tried in order: gemini-2.5-flash-image via the Cloudflare AI Gateway, square requests only ($0.0406/image), then @cf/black-forest-labs/flux-2-dev via Cloudflare Workers AI ($0.00/image), then google/nano-banana-2-lite via fal ($0.042/image). Each lane settles its own price per delivered image, so an im
| Parameter | Type | Required | Notes |
|---|---|---|---|
| prompt | string | yes | Image description (max 1500 chars). |
| width | number | no | Desired width px (256-2048; the model outputs 1K-class at the nearest aspect ratio). |
| height | number | no | Desired height px (256-2048; the model outputs 1K-class at the nearest aspect ratio). |
| count | number | no | Number of images (1-3, default 1). |
| request_ref | string | no | Optional idempotency key (1-64 chars: letters, digits, . _ : -). Retrying with the same request_ref and the same arguments within 24 hours returns the first result at $0 with replayed: true; the same |
| preview_format | string | no | Preview block after the JSON, at most 384px on the long edge and never charged: png, jpeg or none. Left out, a PNG result gets a png preview and a JPEG or WebP result a jpeg one. A result with no prev |
Fetch a document from a URL, classify its type (personal/medical/business/unknown) with keyword + PII-pattern heuristics (documents containing actual PII data are NEVER business), and return extracted text capped at 100K chars. Free. STREAMING SUPPORTED: send Accept: text/event-stream for started/fetched/classifying/completed phases.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| document_url | string | yes | Public HTTPS URL (fetched server-side, 30s timeout; text/* formats classify, binary answers unknown). |
Create a spreadsheet in the user's library from CSV content in ONE call: the platform stores the bytes (honest text/csv) and registers the file row. Free — storage costs nothing; only AI lanes bill. Returns the file row including its id. Refuses: VALIDATION_ERROR when title or csv_content is empty (send both), VALIDATION_ERROR when csv_content is over 10 MB (split it into smaller files), NOT_FOUND
| Parameter | Type | Required | Notes |
|---|---|---|---|
| title | string | yes | Library title for the file (≤255 chars). |
| csv_content | string | yes | The complete CSV content (first row = headers). At most 10 MB. |
| folder_id | string | no | Optional spreadsheet_folder id to file it under. |
Confirm receipt of a note in your cross-tenant agent_note inbox — the ONLY edit a recipient holds, moving status unread to read under the registry's transition guard. Idempotent: re-confirming an already-read note is a no-op, and the subject/body stay fixed forever so a recipient can never rewrite what the sender said. NEXT: agent_note_list to see the rest of the inbox.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| from_tenant_id | string | no | — |
| consent_grant_id | string | no | — |
| subject | string | no | — |
| body | string | no | — |
| related_entity_type | string | no | — |
| related_entity_id | string | no | — |
| status | string | no | — |
| id | string | yes | The agent_note id to confirm (agent_note_list shows your inbox). |
List your agent_note rows (newest first).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| limit | integer | no | Page size 1-200. Omit BOTH limit and cursor for the legacy bare-array first page of 200; pass either to get { items, next_cursor, limit } instead. |
| cursor | string | no | Opaque page cursor — pass a previous response's next_cursor verbatim. null next_cursor means no further pages. |
Read one agent_note by id.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The agent_note id. |
Read one brand_assets by id.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The brand_assets id. |
List your brand_assets rows (newest first).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| limit | integer | no | Page size 1-200. Omit BOTH limit and cursor for the legacy bare-array first page of 200; pass either to get { items, next_cursor, limit } instead. |
| cursor | string | no | Opaque page cursor — pass a previous response's next_cursor verbatim. null next_cursor means no further pages. |
List your consent_grant rows (newest first).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| limit | integer | no | Page size 1-200. Omit BOTH limit and cursor for the legacy bare-array first page of 200; pass either to get { items, next_cursor, limit } instead. |
| cursor | string | no | Opaque page cursor — pass a previous response's next_cursor verbatim. null next_cursor means no further pages. |
Read one consent_grant by id.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The consent_grant id. |
Create a contact and, in the same call, log its first note and/or first interaction — the composite first-touch door. Children validate before the contact write; if the contact commits but a child then fails, the error names the contact's id plus the exact call to finish it, never a silent orphan. A contact with the same email or phone already in this tenant refuses with CONFLICT. NEXT: contact_up
| Parameter | Type | Required | Notes |
|---|---|---|---|
| name | string | no | — |
| company | string | no | — |
| string | no | — | |
| phone | string | no | — |
| address | string | no | — |
| status | string | no | — |
| source | string | no | — |
| tags | string | no | — |
| last_contact_at | integer | no | — |
| note | string | no | Log a first note in the SAME call — ONE call makes both. |
| notes | string | no | Alias of note. |
| interaction | object | no | Log the first interaction in the same call: {type, summary, occurred_at?} — occurred_at takes "YYYY-MM-DD". |
| first_interaction | object | no | Alias of interaction. |
Update a contact you own (optionally compare-and-set via expected_updated_at).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The contact id. |
| name | string | no | — |
| company | string | no | — |
| string | no | — | |
| phone | string | no | — |
| address | string | no | — |
| status | string | no | — |
| source | string | no | — |
| tags | string | no | — |
| last_contact_at | integer | no | — |
| expected_updated_at | integer | no | Optional compare-and-set guard: the updated_at you last read. Mismatch returns CONFLICT with the current value. |
Delete a contact you own.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The contact id. |
Read one contact by id.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The contact id. |
List your contact rows (newest first).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| limit | integer | no | Page size 1-200. Omit BOTH limit and cursor for the legacy bare-array first page of 200; pass either to get { items, next_cursor, limit } instead. |
| cursor | string | no | Opaque page cursor — pass a previous response's next_cursor verbatim. null next_cursor means no further pages. |
Search your contact rows by text.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| q | string | yes | Search text (substring match over the entity's text properties; %/_ are literal). |
| limit | integer | no | Page size 1-200. Omit BOTH limit and cursor for the legacy bare-array first page of 200; pass either to get { items, next_cursor, limit } instead. |
| cursor | string | no | Opaque page cursor — pass a previous response's next_cursor verbatim. null next_cursor means no further pages. |
Add a note to a contact — the same door as the granular tool, extended only to accept contact_name, contact_email or contact_phone in place of contact_id. A name match must be unique: more than one hit refuses, listing the candidate ids; zero matches on every alias refuses with the runnable two-step call to create the contact first, then retry. NEXT: contact_upsert when no contact exists yet.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| contact_id | string | no | — |
| content | string | no | — |
| contact_name | string | no | No contact_id handy? Resolves the contact by exact name — a unique match wins; ambiguity refuses with the candidate ids. |
| contact_email | string | no | Resolves the contact by exact email when contact_id is absent. |
| contact_phone | string | no | Resolves the contact by exact phone when contact_id is absent. |
List your contact_note rows (newest first).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| limit | integer | no | Page size 1-200. Omit BOTH limit and cursor for the legacy bare-array first page of 200; pass either to get { items, next_cursor, limit } instead. |
| cursor | string | no | Opaque page cursor — pass a previous response's next_cursor verbatim. null next_cursor means no further pages. |
Read one contact_note by id.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The contact_note id. |
Delete a contact_note you own.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The contact_note id. |
Pins one widget or a saved artifact onto the operator's home canvas. kind='widget' requires widget_key from the shipped enum; kind='artifact' requires content_ref (an assistant artifact id) — the door enforces whichever pair the kind demands, since the schema alone cannot express it. Rows are private to the creating user, even though teammates share the same tenant. NEXT: desk_surface_list reads t
| Parameter | Type | Required | Notes |
|---|---|---|---|
| kind | string | no | — |
| widget_key | string | no | — |
| content_ref | string | no | — |
| x | integer | no | — |
| y | integer | no | — |
| w | integer | no | — |
| h | integer | no | — |
| z_index | integer | no | — |
Moves, resizes, or restacks a surface already on the desk canvas — x/y/w/h/z_index are real column writes, not a layout cache. The surface's identity is frozen here: kind, widget_key, and content_ref never change through this door, only via delete then re-create. NEXT: desk_surface_list to find the id to move.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| kind | string | no | — |
| widget_key | string | no | — |
| content_ref | string | no | — |
| x | integer | no | — |
| y | integer | no | — |
| w | integer | no | — |
| h | integer | no | — |
| z_index | integer | no | — |
| id | string | yes | The desk_surface id (desk_surface_list shows them). |
| expected_updated_at | integer | no | Optional compare-and-set guard: the updated_at from a prior desk_surface_list/read. Mismatch returns CONFLICT — another tab already moved this surface. |
Read one desk_surface by id.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The desk_surface id. |
List your desk_surface rows (newest first).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| limit | integer | no | Page size 1-200. Omit BOTH limit and cursor for the legacy bare-array first page of 200; pass either to get { items, next_cursor, limit } instead. |
| cursor | string | no | Opaque page cursor — pass a previous response's next_cursor verbatim. null next_cursor means no further pages. |
Delete a desk_surface you own.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The desk_surface id. |
Create a canvas project from a Fabric.js toJSON serialization (canvas_json, required): every embedded data:image src is pulled out, hashed, and written to a tenant-scoped, content-addressed R2 key before the row is saved, so canvas_json never carries image bytes and identical images dedupe across projects. SVG, an unrecognized image type, an oversized embedded image, or a canvas still too large af
| Parameter | Type | Required | Notes |
|---|---|---|---|
| name | string | no | — |
| canvas_json | string | no | — |
| thumbnail_key | string | no | — |
| width | integer | no | — |
| height | integer | no | — |
| version | integer | no | — |
| thumbnail_data_url | string | no | Optional thumbnail as a data: URL (PNG/JPEG/WebP/GIF, max 2MB) — externalized into thumbnail_key the same way embedded canvas images are. Omit to skip thumbnail externalization (create: no thumbnail_k |
Save changes to an existing canvas project by id — the autosave door: send only the fields that changed (name, canvas_json, width, height, thumbnail_data_url), everything else on the row is left alone. A canvas_json you send goes through the same image-externalization and hygiene refusal as edit_project_create (embedded images become R2 keys; SVG, unrecognized types, oversized images, or a still-t
| Parameter | Type | Required | Notes |
|---|---|---|---|
| name | string | no | — |
| canvas_json | string | no | — |
| thumbnail_key | string | no | — |
| width | integer | no | — |
| height | integer | no | — |
| version | integer | no | — |
| id | string | yes | The edit_project id (edit_project_list shows them). |
| expected_updated_at | integer | no | Optional compare-and-set guard: the updated_at you last read. Mismatch returns CONFLICT with the current value. |
| thumbnail_data_url | string | no | Optional thumbnail as a data: URL (PNG/JPEG/WebP/GIF, max 2MB) — externalized into thumbnail_key the same way embedded canvas images are. Omit to skip thumbnail externalization (create: no thumbnail_k |
Read one edit_project by id.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The edit_project id. |
List your edit_project rows (newest first).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| limit | integer | no | Page size 1-200. Omit BOTH limit and cursor for the legacy bare-array first page of 200; pass either to get { items, next_cursor, limit } instead. |
| cursor | string | no | Opaque page cursor — pass a previous response's next_cursor verbatim. null next_cursor means no further pages. |
Delete a edit_project you own.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The edit_project id. |
Edits an expense's own fields only — status and approval stamps refuse with VALIDATION_ERROR here since those are transitions (expense_submit, expense_approve, expense_reject, expense_reimburse). amount_cents, if changed, must stay integer CENTS. Only the expense's own creator may edit it, and content freezes once the row is 'pending', reimbursed, or approved by someone else — draft, rejected, and
| Parameter | Type | Required | Notes |
|---|---|---|---|
| vendor | string | no | — |
| amount_cents | integer | no | — |
| currency | string | no | — |
| category_id | string | no | — |
| expense_date | integer | no | — |
| receipt_key | string | no | — |
| ocr_json | string | no | — |
| notes | string | no | — |
| tags_json | string | no | — |
| subtotal_cents | integer | no | — |
| tax_amount_cents | integer | no | — |
| tax_rate_bps | integer | no | — |
| tax_type | string | no | — |
| status | string | no | — |
| submitted_at | integer | no | — |
| approved_by | string | no | — |
| approved_at | integer | no | — |
| rejection_reason | string | no | — |
| rejected_at | integer | no | — |
| reimbursed_at | integer | no | — |
Deletes an expense you created — draft and rejected rows only. Pending, approved, and reimbursed rows are approval-trail records and refuse with CONFLICT (approval_locked: true), and the lock is pinned into the delete itself so a status change racing your read still refuses instead of silently deleting. NEXT: expense_reject it first (admin+) if it must leave the books.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| vendor | string | no | — |
| amount_cents | integer | no | — |
| currency | string | no | — |
| category_id | string | no | — |
| expense_date | integer | no | — |
| receipt_key | string | no | — |
| ocr_json | string | no | — |
| notes | string | no | — |
| tags_json | string | no | — |
| subtotal_cents | integer | no | — |
| tax_amount_cents | integer | no | — |
| tax_rate_bps | integer | no | — |
| tax_type | string | no | — |
| status | string | no | — |
| submitted_at | integer | no | — |
| approved_by | string | no | — |
| approved_at | integer | no | — |
| rejection_reason | string | no | — |
| rejected_at | integer | no | — |
| reimbursed_at | integer | no | — |
Rejects a submitted expense claim — requires the admin or owner role, and only a 'pending' expense qualifies (CONFLICT otherwise). rejection_reason (up to 500 chars) is optional but records why; rejected is terminal and never counts as spend, so a corrected claim is a fresh expense_create, never a resubmit.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| vendor | string | no | — |
| amount_cents | integer | no | — |
| currency | string | no | — |
| category_id | string | no | — |
| expense_date | integer | no | — |
| receipt_key | string | no | — |
| ocr_json | string | no | — |
| notes | string | no | — |
| tags_json | string | no | — |
| subtotal_cents | integer | no | — |
| tax_amount_cents | integer | no | — |
| tax_rate_bps | integer | no | — |
| tax_type | string | no | — |
| status | string | no | — |
| submitted_at | integer | no | — |
| approved_by | string | no | — |
| approved_at | integer | no | — |
| rejection_reason | string | no | — |
| rejected_at | integer | no | — |
| reimbursed_at | integer | no | — |
Marks an approved expense as paid out — restricted to the tenant owner because it moves real money, and only an 'approved' expense qualifies (CONFLICT otherwise). Stamps reimbursed_at, after which the row's content freezes unconditionally since the amount approved is the amount recorded as paid. Records the payout only — no funds move automatically.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| vendor | string | no | — |
| amount_cents | integer | no | — |
| currency | string | no | — |
| category_id | string | no | — |
| expense_date | integer | no | — |
| receipt_key | string | no | — |
| ocr_json | string | no | — |
| notes | string | no | — |
| tags_json | string | no | — |
| subtotal_cents | integer | no | — |
| tax_amount_cents | integer | no | — |
| tax_rate_bps | integer | no | — |
| tax_type | string | no | — |
| status | string | no | — |
| submitted_at | integer | no | — |
| approved_by | string | no | — |
| approved_at | integer | no | — |
| rejection_reason | string | no | — |
| rejected_at | integer | no | — |
| reimbursed_at | integer | no | — |
Read one expense by id.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The expense id. |
List your expense rows (newest first).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| limit | integer | no | Page size 1-200. Omit BOTH limit and cursor for the legacy bare-array first page of 200; pass either to get { items, next_cursor, limit } instead. |
| cursor | string | no | Opaque page cursor — pass a previous response's next_cursor verbatim. null next_cursor means no further pages. |
Search your expense rows by text.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| q | string | yes | Search text (substring match over the entity's text properties; %/_ are literal). |
| limit | integer | no | Page size 1-200. Omit BOTH limit and cursor for the legacy bare-array first page of 200; pass either to get { items, next_cursor, limit } instead. |
| cursor | string | no | Opaque page cursor — pass a previous response's next_cursor verbatim. null next_cursor means no further pages. |
Aggregate (count/sum) over your expense rows.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| function | string | yes | — |
| property | string | no | Required for sum: a declared numeric property of the entity. |
Create a expense_budget.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| category_id | string | no | — |
| monthly_limit_cents | integer | yes | — |
| currency | string | no | — |
| alert_at_pct | integer | no | — |
| is_active | integer | no | — |
Update a expense_budget you own (optionally compare-and-set via expected_updated_at).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The expense_budget id. |
| category_id | string | no | — |
| monthly_limit_cents | integer | no | — |
| currency | string | no | — |
| alert_at_pct | integer | no | — |
| is_active | integer | no | — |
| expected_updated_at | integer | no | Optional compare-and-set guard: the updated_at you last read. Mismatch returns CONFLICT with the current value. |
Delete a expense_budget you own.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The expense_budget id. |
Read one expense_budget by id.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The expense_budget id. |
List your expense_budget rows (newest first).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| limit | integer | no | Page size 1-200. Omit BOTH limit and cursor for the legacy bare-array first page of 200; pass either to get { items, next_cursor, limit } instead. |
| cursor | string | no | Opaque page cursor — pass a previous response's next_cursor verbatim. null next_cursor means no further pages. |
Adds a custom category to your tenant's category table — slug must be 1-50 chars of lowercase a-z, 0-9, '-' or '_' and unique per tenant (CONFLICT if taken). is_default is server-owned: supplying it at all refuses with VALIDATION_ERROR, and this door always creates with is_default 0 — the 9 seeded defaults exist only via expense_category_ensure_defaults. sort_order defaults to the next open slot w
| Parameter | Type | Required | Notes |
|---|---|---|---|
| slug | string | no | — |
| name | string | no | — |
| icon | string | no | — |
| color | string | no | — |
| sort_order | integer | no | — |
| is_default | integer | no | — |
Edits a category's name, icon, color, or sort_order — slug and is_default are the category's fixed identity, and any attempt to change either refuses with VALIDATION_ERROR. color, when given, must be a #rrggbb hex value. Create a new category instead of trying to rename an existing slug.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| slug | string | no | — |
| name | string | no | — |
| icon | string | no | — |
| color | string | no | — |
| sort_order | integer | no | — |
| is_default | integer | no | — |
| id | string | yes | The expense_category id (expense_category_list shows them). |
| expected_updated_at | integer | no | Optional compare-and-set guard: the updated_at you last read. Mismatch returns CONFLICT with the current value. |
Deletes a custom category — categories are tenant-shared, so any tenant member can remove one regardless of who created it; the 9 seeded defaults are undeletable and refuse with CONFLICT (default_category: true). Expenses already carrying the deleted category keep their category_id untouched and simply render as Uncategorized; nothing is reassigned or blocked.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| slug | string | no | — |
| name | string | no | — |
| icon | string | no | — |
| color | string | no | — |
| sort_order | integer | no | — |
| is_default | integer | no | — |
| id | string | yes | The expense_category id (expense_category_list shows them). |
Seeds the 9 canonical default categories (Food & Dining, Transport, Utilities, Shopping, Entertainment, Healthcare, Travel, Office & Supplies, Other) into your tenant, skipping any slug that already exists. Takes no arguments and is safe to call repeatedly or concurrently — it converges rather than duplicating. NEXT: expense_category_list to see the result.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| slug | string | no | — |
| name | string | no | — |
| icon | string | no | — |
| color | string | no | — |
| sort_order | integer | no | — |
| is_default | integer | no | — |
Read one expense_category by id.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The expense_category id. |
List your expense_category rows (newest first).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| limit | integer | no | Page size 1-200. Omit BOTH limit and cursor for the legacy bare-array first page of 200; pass either to get { items, next_cursor, limit } instead. |
| cursor | string | no | Opaque page cursor — pass a previous response's next_cursor verbatim. null next_cursor means no further pages. |
Create a expense_recurrence.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| vendor | string | yes | — |
| amount_cents | integer | yes | — |
| currency | string | no | — |
| category_id | string | no | — |
| notes | string | no | — |
| frequency | string | yes | — |
| day_of_month | integer | no | — |
| day_of_week | integer | no | — |
| next_due | integer | yes | — |
| is_active | integer | no | — |
| last_generated_at | integer | no | — |
| total_generated | integer | no | — |
Update a expense_recurrence you own (optionally compare-and-set via expected_updated_at).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The expense_recurrence id. |
| vendor | string | no | — |
| amount_cents | integer | no | — |
| currency | string | no | — |
| category_id | string | no | — |
| notes | string | no | — |
| frequency | string | no | — |
| day_of_month | integer | no | — |
| day_of_week | integer | no | — |
| next_due | integer | no | — |
| is_active | integer | no | — |
| last_generated_at | integer | no | — |
| total_generated | integer | no | — |
| expected_updated_at | integer | no | Optional compare-and-set guard: the updated_at you last read. Mismatch returns CONFLICT with the current value. |
Delete a expense_recurrence you own.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The expense_recurrence id. |
Read one expense_recurrence by id.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The expense_recurrence id. |
List your expense_recurrence rows (newest first).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| limit | integer | no | Page size 1-200. Omit BOTH limit and cursor for the legacy bare-array first page of 200; pass either to get { items, next_cursor, limit } instead. |
| cursor | string | no | Opaque page cursor — pass a previous response's next_cursor verbatim. null next_cursor means no further pages. |
Create-or-update a interaction keyed on source_ref.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| contact_id | string | yes | — |
| interaction_type | string | yes | — |
| summary | string | yes | — |
| occurred_at | integer | no | — |
| source_ref | string | yes | — |
List your interaction rows (newest first).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| limit | integer | no | Page size 1-200. Omit BOTH limit and cursor for the legacy bare-array first page of 200; pass either to get { items, next_cursor, limit } instead. |
| cursor | string | no | Opaque page cursor — pass a previous response's next_cursor verbatim. null next_cursor means no further pages. |
Read one interaction by id.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The interaction id. |
Edits an invoice's header fields and status. status 'paid' cannot be set here — it derives from the payment ledger, so call invoice_payment_record instead. Status moves are machine-checked (draft to sent/cancelled, sent to cancelled); cancelled is terminal and a paid invoice never reopens by hand. A move to 'sent' stamps sent_at automatically when omitted, and currency is ledger-locked once any li
| Parameter | Type | Required | Notes |
|---|---|---|---|
| client_id | string | no | — |
| invoice_number | string | no | — |
| status | string | no | — |
| issue_date | integer | no | — |
| due_date | integer | no | — |
| currency | string | no | — |
| tax_rate_bps | integer | no | — |
| notes | string | no | — |
| payment_terms | string | no | — |
| source_type | string | no | — |
| source_id | string | no | — |
| cash_sale | integer | no | — |
| payment_method | string | no | — |
| sent_at | integer | no | — |
| paid_at | integer | no | — |
| tax_scheme | string | no | — |
| prices_include_tax | integer | no | — |
| fx_rate_to_sgd_ppm | integer | no | — |
| fx_rate_date | string | no | The date the fx rate is for, YYYY-MM-DD. Send with fx_rate_to_sgd. |
| id | string | yes | The invoice id (invoice_list shows them). |
Returns share_url, the client's view link for this invoice, and the full document (parties, lines, totals in integer CENTS) in one call. action: 'get' (default) returns the live link; 'rotate' replaces it and the old link stops working; 'revoke' turns it off. A link the owner turned off stays off for agents: 'get' never re-issues it, and an agent's 'rotate' waits for the owner's approval. Anyone w
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The invoice id (invoice_list shows them). |
| invoice_id | string | no | Alias of id. |
| action | string | no | get (default): the live link, made the first time. rotate: replace it with a new link; the old one stops working. revoke: turn the link off. |
| fresh_after | integer | no | Omit it. Only when an error's next_call includes fresh_after, send that call exactly as given. |
Acts on a payer's report, sent from the invoice's client page, that they have paid. action 'accept' records the payment with the same writer as invoice_payment_record, graded counterparty_confirmed: the amount is amount_cents (or amount) when given, else the balance still owed; occurred_at defaults to when the payer reported. An agent's accept waits for the owner's approval. action 'dismiss' close
| Parameter | Type | Required | Notes |
|---|---|---|---|
| action | string | yes | accept: record the payment the payer reported. dismiss: the money did not arrive. |
| id | string | no | The confirmation id from invoice_read's payer_confirmations. |
| invoice_id | string | no | Instead of id: the invoice, when exactly one report on it is pending. |
| amount_cents | integer | no | accept only: the amount received in integer CENTS. Omit it to record the balance still owed. |
| amount | string | no | accept only: the amount as a decimal STRING ("250.00") instead of amount_cents. |
| method | string | no | accept only: how the money arrived. |
| occurred_at | integer | no | accept only: epoch milliseconds the money arrived. Omit it to use the time the payer reported. |
| note | string | no | accept only: your own note on the payment (max 500). |
| force | boolean | no | accept only: confirms a genuine second payment of the same amount on the same day. |
| allow_overpayment | boolean | no | accept only: record more than the balance still owed. |
[REQUIRES APPROVAL] Issues a numbered debit note that raises what an issued ('sent' or 'paid') invoice is owed: an extra charge, or a price or tax correction. It is numbered from the debit note series and adds amount_cents (or a decimal STRING amount), tax at the invoice's rate inside, in its currency; a 'paid' invoice goes back to 'sent' until the rest is paid. Refuses a draft (change its lines i
| Parameter | Type | Required | Notes |
|---|---|---|---|
| invoice_id | string | no | The invoice the debit note raises (invoice_list shows ids); its invoice_number works too. |
| invoice_number | string | no | Alias of invoice_id — the invoice's own number. |
| amount_cents | integer | no | The amount the debit note adds, in integer CENTS. |
| amount | string | no | The amount as a decimal STRING ("25.00") instead of amount_cents — never convert units yourself. |
| debit_kind | string | no | What the debit note is for. Omit it for additional_charge. |
| reason | string | no | Why the customer owes more, as the debit note prints it (max 500). |
| occurred_at | integer | no | Epoch milliseconds the debit note takes effect. Omit it for now. |
| currency | string | no | Must be the invoice's own currency; omit it to use that currency. |
Voids a 'sent' invoice with no money on it and reissues it under the next number: 'sent', dated today, same client, currency, notes, terms and lines, tax on today's rules, the old days to pay unless due_date is sent. A foreign-currency sg_gst invoice issued before today needs fx_rate_to_sgd and fx_rate_date for today unless its rate is dated today. The old one is cancelled, its client link stops w
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | no | The invoice to cancel and issue again (invoice_list shows ids); its invoice_number works too. |
| invoice_number | string | no | Alias of id — the invoice's own number. |
| expected_updated_at | integer | no | Optional compare-and-set guard: the updated_at you last read. A mismatch returns CONFLICT and changes nothing. |
| due_date | integer | no | Epoch milliseconds of the new due date, today or later. Omit it to give the new invoice the old one's days to pay, counted from today. |
| reason | string | no | Why the invoice is reissued, kept in both invoices' activity (max 500). |
| fx_rate_to_sgd | string | no | sg_gst invoices in a currency other than SGD: Singapore dollars per 1 unit of the invoice currency for today, the new invoice's date of supply ("1.3502", up to 6 decimals, from MAS, a local bank, Bloo |
| fx_rate_to_sgd_ppm | integer | no | fx_rate_to_sgd in millionths (1.3502 → 1350200), instead of fx_rate_to_sgd. Send with fx_rate_date. |
| fx_rate_date | string | no | The date the fx rate is for, YYYY-MM-DD. Send with fx_rate_to_sgd. |
Records the date a client promised to pay an issued invoice that still has money owed: promised_payment_date 'YYYY-MM-DD', the business's own date, today or later. clear true removes it. invoice_read then shows promise_status: pending until that business day ends, kept when paid in full by then, broken after it. A broken promise makes promise_follow_up the default purpose of invoice_message_prepar
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | no | The invoice the client promised to pay (invoice_list shows ids); its invoice_number works too. |
| invoice_number | string | no | Alias of id — the invoice's own number. |
| promised_payment_date | string | no | The business-local date the client promised to pay by, YYYY-MM-DD, today or later. Leave it out with clear true. |
| clear | boolean | no | true removes the promised date instead of setting one. |
| note | string | no | What the client said, kept in the invoice's activity (max 500). |
| expected_updated_at | integer | no | Optional compare-and-set guard: the updated_at you last read. A mismatch returns CONFLICT and changes nothing. |
Returns one invoice with its money and state worked out on read, in integer CENTS: subtotal_cents, tax_cents, total_cents, paid_cents, credited_cents, adjusted_cents, remaining_cents (copy remaining_cents, never compute it). state: draft, sent, partially_paid, overdue, written_off, paid or cancelled. Overdue means issued, still owed and due before today in the business time zone (sales_settings.ti
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The invoice id. |
Lists your invoices, newest first (200 at most; pass limit and cursor to page). Every row carries the same worked-out money and state as invoice_read: total_cents, remaining_cents, state, is_overdue, days_overdue (integer CENTS, business days). To find what to chase, pass state 'overdue': only invoices issued, still owed and due before today in the business time zone come back. payer_confirmations
| Parameter | Type | Required | Notes |
|---|---|---|---|
| state | string | no | Only invoices in this worked-out state, still newest first and paged the same way. Leave it out for every invoice. |
| limit | integer | no | Page size 1-200. Omit BOTH limit and cursor for the legacy bare-array first page of 200; pass either to get { items, next_cursor, limit } instead. |
| cursor | string | no | Opaque page cursor — pass a previous response's next_cursor verbatim. null next_cursor means no further pages. |
Finds invoices whose text fields (invoice number, notes, payment terms) contain every word of q. Rows carry the same worked-out money and state as invoice_read: total_cents, remaining_cents, state, is_overdue (integer CENTS), and payer_confirmations_pending. Refuses an empty q with VALIDATION_ERROR: send the invoice number, such as INV-2026-0001, or a word from its notes.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| q | string | yes | Search text (substring match over the entity's text properties; %/_ are literal). |
| limit | integer | no | Page size 1-200. Omit BOTH limit and cursor for the legacy bare-array first page of 200; pass either to get { items, next_cursor, limit } instead. |
| cursor | string | no | Opaque page cursor — pass a previous response's next_cursor verbatim. null next_cursor means no further pages. |
Read one invoice_adjustment by id.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The invoice_adjustment id. |
List your invoice_adjustment rows (newest first).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| limit | integer | no | Page size 1-200. Omit BOTH limit and cursor for the legacy bare-array first page of 200; pass either to get { items, next_cursor, limit } instead. |
| cursor | string | no | Opaque page cursor — pass a previous response's next_cursor verbatim. null next_cursor means no further pages. |
[REQUIRES APPROVAL] Retires a dilution fact row — the only correction lane (adjustments are append-only; amounts are never edited). If the retired row was a credit that settled the invoice, the status rolls from 'paid' back to 'sent' and paid_at clears; the remaining balance and the derived 'written_off' state re-derive from the live rows immediately. An agent's call parks here for human approval.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| invoice_id | string | no | — |
| adjustment_type | string | no | — |
| amount_cents | integer | no | — |
| currency | string | no | — |
| reason | string | no | — |
| occurred_at | integer | no | — |
| reason_code | string | no | — |
| credit_outcome | string | no | — |
| id | string | yes | The adjustment id (invoice_adjustment_list shows them). |
| adjustment_id | string | no | Alias of id. |
Create a invoice_client.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| name | string | yes | — |
| company | string | no | — |
| string | no | — | |
| phone | string | no | — |
| address | string | no | — |
| notes | string | no | — |
| contact_id | string | no | — |
| reminder_cadence | string | no | — |
| message_language | string | no | — |
Create-or-update a invoice_client keyed on email.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| name | string | yes | — |
| company | string | no | — |
| string | yes | — | |
| phone | string | no | — |
| address | string | no | — |
| notes | string | no | — |
| contact_id | string | no | — |
| reminder_cadence | string | no | — |
| message_language | string | no | — |
Update a invoice_client you own (optionally compare-and-set via expected_updated_at).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The invoice_client id. |
| name | string | no | — |
| company | string | no | — |
| string | no | — | |
| phone | string | no | — |
| address | string | no | — |
| notes | string | no | — |
| contact_id | string | no | — |
| reminder_cadence | string | no | — |
| message_language | string | no | — |
| expected_updated_at | integer | no | Optional compare-and-set guard: the updated_at you last read. Mismatch returns CONFLICT with the current value. |
Delete a invoice_client you own.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The invoice_client id. |
Read one invoice_client by id.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The invoice_client id. |
List your invoice_client rows (newest first).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| limit | integer | no | Page size 1-200. Omit BOTH limit and cursor for the legacy bare-array first page of 200; pass either to get { items, next_cursor, limit } instead. |
| cursor | string | no | Opaque page cursor — pass a previous response's next_cursor verbatim. null next_cursor means no further pages. |
Search your invoice_client rows by text.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| q | string | yes | Search text (substring match over the entity's text properties; %/_ are literal). |
| limit | integer | no | Page size 1-200. Omit BOTH limit and cursor for the legacy bare-array first page of 200; pass either to get { items, next_cursor, limit } instead. |
| cursor | string | no | Opaque page cursor — pass a previous response's next_cursor verbatim. null next_cursor means no further pages. |
[REQUIRES APPROVAL] Asserts that a billing client IS an on-platform tenant (or pass counterparty_tenant_id null to unlink) and retro-stamps that client's existing invoices with the link in the same call — invoices_stamped in the result is the count. Linking requires the counterparty's 'cross_tenant_settlement' consent AND a live network relationship (an active match or a deal thread); unlinking pa
| Parameter | Type | Required | Notes |
|---|---|---|---|
| name | string | no | — |
| company | string | no | — |
| string | no | — | |
| phone | string | no | — |
| address | string | no | — |
| notes | string | no | — |
| contact_id | string | no | — |
| reminder_cadence | string | no | — |
| message_language | string | no | — |
| id | string | yes | The invoice_client id (invoice_client_list shows them). |
| client_id | string | no | Alias of id. |
| counterparty_tenant_id | string | yes | The on-platform business this client IS (their tenant id). Pass null to unlink. |
Adds one line item to an invoice. unit_price_cents is integer CENTS, 0 or more ($15.00 → 1500); quantity is 0.001 to 1,000,000 with up to 3 decimals (1.5 hours → 1.5); unit is an optional label (hr, kg); discount_bps is an optional line discount (10% → 1000). quantity × unit_price_cents is at most 10,000,000,000. Refuses a negative price (send discount_bps instead), a 'paid' parent (retire the pay
| Parameter | Type | Required | Notes |
|---|---|---|---|
| invoice_id | string | no | — |
| description | string | no | — |
| quantity | number | no | How many, up to 3 decimals (1.5 hours → 1.5). A new line defaults to 1. |
| unit_price_cents | integer | no | — |
| position | integer | no | — |
| unit | string | no | — |
| discount_bps | integer | no | Optional line discount in basis points: 10% → 1000, none → 0. A discount is never a lower or negative price. |
| tax_code | string | no | — |
Edits a line item's description, quantity, unit, price or discount, or re-parents it to another invoice. expected_updated_at is required: the line's updated_at from your read; without it nothing is written and the refusal names the current value; a line changed since then answers CONFLICT. Bounds: unit_price_cents is integer CENTS, 0 or more; quantity 0.001 to 1,000,000 (3 decimals); discount_bps
| Parameter | Type | Required | Notes |
|---|---|---|---|
| invoice_id | string | no | — |
| description | string | no | — |
| quantity | number | no | How many, up to 3 decimals (1.5 hours → 1.5). A new line defaults to 1. |
| unit_price_cents | integer | no | — |
| position | integer | no | — |
| unit | string | no | — |
| discount_bps | integer | no | Optional line discount in basis points: 10% → 1000, none → 0. A discount is never a lower or negative price. |
| tax_code | string | no | — |
| id | string | yes | The invoice_item id (invoice_item_list shows them). |
| expected_updated_at | integer | yes | Required: the line's updated_at from your last read (invoice_item_read, invoice_item_list or the create answer). Left out, the call is refused and names the current value; a line changed since then re |
Soft-deletes a line item — it leaves the invoice and its derived total immediately, but the row is retired for audit history, never removed. expected_updated_at is required: the line's updated_at from your read (invoice_item_read); without it the removal is refused and the refusal names the current value. Refuses when the parent invoice is 'paid' (ledger-locked: retire the payment first) or 'cance
| Parameter | Type | Required | Notes |
|---|---|---|---|
| invoice_id | string | no | — |
| description | string | no | — |
| quantity | integer | no | — |
| unit_price_cents | integer | no | — |
| position | integer | no | — |
| unit | string | no | — |
| discount_bps | integer | no | — |
| tax_code | string | no | — |
| id | string | yes | The invoice_item id (invoice_item_list shows them). |
| expected_updated_at | integer | yes | Required: the line's updated_at from your last read (invoice_item_read, invoice_item_list or the create answer). Left out, the call is refused and names the current value; a line changed since then re |
Read one invoice_item by id.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The invoice_item id. |
List your invoice_item rows (newest first).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| limit | integer | no | Page size 1-200. Omit BOTH limit and cursor for the legacy bare-array first page of 200; pass either to get { items, next_cursor, limit } instead. |
| cursor | string | no | Opaque page cursor — pass a previous response's next_cursor verbatim. null next_cursor means no further pages. |
Read one invoice_payment by id.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The invoice_payment id. |
List your invoice_payment rows (newest first).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| limit | integer | no | Page size 1-200. Omit BOTH limit and cursor for the legacy bare-array first page of 200; pass either to get { items, next_cursor, limit } instead. |
| cursor | string | no | Opaque page cursor — pass a previous response's next_cursor verbatim. null next_cursor means no further pages. |
[REQUIRES APPROVAL] Retires a payment fact row — the only correction lane (payments are append-only; amounts are never edited). If retiring it un-settles the invoice, the reversal itself rolls the status from 'paid' back to 'sent' and clears paid_at. An agent's call parks here for a human to approve in the Simpler UI; a human's call is its own approval. NEXT: invoice_payment_record to re-record th
| Parameter | Type | Required | Notes |
|---|---|---|---|
| invoice_id | string | no | — |
| amount_cents | integer | no | — |
| currency | string | no | — |
| occurred_at | integer | no | — |
| method | string | no | — |
| note | string | no | — |
| id | string | yes | The payment id (invoice_payment_list shows them). |
| payment_id | string | no | Alias of id. |
Create a invoice_recurring.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| client_id | string | no | — |
| title | string | yes | — |
| items_json | string | yes | — |
| currency | string | no | — |
| tax_rate_bps | integer | no | — |
| frequency | string | yes | — |
| day_of_month | integer | no | — |
| day_of_week | integer | no | — |
| next_due | integer | yes | — |
| is_active | integer | no | — |
| notes | string | no | — |
| last_generated_at | integer | no | — |
| total_generated | integer | no | — |
| tax_scheme | string | no | — |
| ends_on | integer | no | — |
| max_invoices | integer | no | — |
Update a invoice_recurring you own (optionally compare-and-set via expected_updated_at).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The invoice_recurring id. |
| client_id | string | no | — |
| title | string | no | — |
| items_json | string | no | — |
| currency | string | no | — |
| tax_rate_bps | integer | no | — |
| frequency | string | no | — |
| day_of_month | integer | no | — |
| day_of_week | integer | no | — |
| next_due | integer | no | — |
| is_active | integer | no | — |
| notes | string | no | — |
| last_generated_at | integer | no | — |
| total_generated | integer | no | — |
| tax_scheme | string | no | — |
| ends_on | integer | no | — |
| max_invoices | integer | no | — |
| expected_updated_at | integer | no | Optional compare-and-set guard: the updated_at you last read. Mismatch returns CONFLICT with the current value. |
Delete a invoice_recurring you own.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The invoice_recurring id. |
Read one invoice_recurring by id.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The invoice_recurring id. |
List your invoice_recurring rows (newest first).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| limit | integer | no | Page size 1-200. Omit BOTH limit and cursor for the legacy bare-array first page of 200; pass either to get { items, next_cursor, limit } instead. |
| cursor | string | no | Opaque page cursor — pass a previous response's next_cursor verbatim. null next_cursor means no further pages. |
Skips a recurring template's next invoice: next_due moves one period on (the template's own weekly, monthly or yearly day) and no invoice is made. A skip does not count toward max_invoices. Refuses NOT_FOUND for an id outside your tenant (call invoice_recurring_list) and CONFLICT when the template has ended (raise ends_on or max_invoices with invoice_recurring_update) or changed since expected_upd
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The recurring template whose next invoice to skip (invoice_recurring_list shows ids). |
| expected_updated_at | integer | no | Optional compare-and-set guard: the updated_at you last read. A mismatch returns CONFLICT and changes nothing. |
Post to one of the tenant's 8 market-signal wish-bar slots — a buy, sell, swap, capacity-offer or capacity-request visible ONLY to platform-matched partners, never the wider network. The door counts your OPEN signals server-side before writing: the 9th is refused with slots_used/slots_max in the error rather than silently queued. NEXT: market_signal_update to close or fulfil a signal and free a sl
| Parameter | Type | Required | Notes |
|---|---|---|---|
| signal_type | string | no | — |
| product | string | no | — |
| quantity | string | no | — |
| price_cents | integer | no | — |
| currency | string | no | — |
| deadline | integer | no | — |
| location | string | no | — |
| notes | string | no | — |
| status | string | no | — |
Update a market_signal you own (optionally compare-and-set via expected_updated_at).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The market_signal id. |
| signal_type | string | no | — |
| product | string | no | — |
| quantity | string | no | — |
| price_cents | integer | no | — |
| currency | string | no | — |
| deadline | integer | no | — |
| location | string | no | — |
| notes | string | no | — |
| status | string | no | — |
| expected_updated_at | integer | no | Optional compare-and-set guard: the updated_at you last read. Mismatch returns CONFLICT with the current value. |
List your market_signal rows (newest first).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| limit | integer | no | Page size 1-200. Omit BOTH limit and cursor for the legacy bare-array first page of 200; pass either to get { items, next_cursor, limit } instead. |
| cursor | string | no | Opaque page cursor — pass a previous response's next_cursor verbatim. null next_cursor means no further pages. |
Read one market_signal by id.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The market_signal id. |
Register a buyer in the LHDN buyer registry so it attaches to future e-invoices with one pick (customer_id) instead of typing the party every time. Validates the TIN format, and validates state_code against the LHDN state table when you send one — a buyer with no real TIN uses the LHDN generic TIN (EI00000000010 Malaysian public, EI00000000020 foreign) instead. NEXT: myinvois_invoice_generate with
| Parameter | Type | Required | Notes |
|---|---|---|---|
| name | string | no | — |
| tin | string | no | — |
| brn | string | no | — |
| sst_number | string | no | — |
| contact_number | string | no | — |
| string | no | — | |
| address | string | no | — |
| city | string | no | — |
| state_code | string | no | — |
| postal_code | string | no | — |
| country_code | string | no | — |
| notes | string | no | — |
Edit a registered buyer's LHDN details — send only the fields you are changing. When tin is included it is re-checked against the same format gate create runs, and when state_code is included it is re-checked against the LHDN state table, so an edited buyer stays valid to generate against. Never touches e-invoices already generated for this buyer; each one sealed its own copy of the buyer party. N
| Parameter | Type | Required | Notes |
|---|---|---|---|
| name | string | no | — |
| tin | string | no | — |
| brn | string | no | — |
| sst_number | string | no | — |
| contact_number | string | no | — |
| string | no | — | |
| address | string | no | — |
| city | string | no | — |
| state_code | string | no | — |
| postal_code | string | no | — |
| country_code | string | no | — |
| notes | string | no | — |
| id | string | yes | The myinvois_customer id (myinvois_customer_list shows them). |
| expected_updated_at | integer | no | Optional compare-and-set guard: the updated_at from a prior myinvois_customer_list/read. Mismatch returns CONFLICT with the current value. |
Delete a registered buyer. E-invoices already generated for this buyer keep their sealed copy of the buyer party and are never touched. Refuses an id outside your tenant with NOT_FOUND: call myinvois_customer_list for valid ids.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The myinvois_customer id. |
Read one registered buyer by id: name, TIN, BRN, SST number, address and contact. myinvois_invoice_generate seals the name, TIN, BRN, address and contact; the buyer's SST number stays on this record and is not sealed on the e-invoice. Refuses an id outside your tenant with NOT_FOUND: call myinvois_customer_list or myinvois_customer_search for valid ids. NEXT: myinvois_invoice_generate with this id
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The myinvois_customer id. |
List registered buyers, newest first, to pick a customer_id for myinvois_invoice_generate. An empty list means none are registered yet: call myinvois_customer_create, or send an inline buyer {name, tin} to myinvois_invoice_generate instead.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| limit | integer | no | Page size 1-200. Omit BOTH limit and cursor for the legacy bare-array first page of 200; pass either to get { items, next_cursor, limit } instead. |
| cursor | string | no | Opaque page cursor — pass a previous response's next_cursor verbatim. null next_cursor means no further pages. |
Find registered buyers by text: every word must match one of the buyer's text fields, such as name, TIN, BRN, email or address. Refuses an empty q with VALIDATION_ERROR. No match returns an empty list: call myinvois_customer_create to register the buyer. NEXT: myinvois_invoice_generate with the id as customer_id.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| q | string | yes | Search text (substring match over the entity's text properties; %/_ are literal). |
| limit | integer | no | Page size 1-200. Omit BOTH limit and cursor for the legacy bare-array first page of 200; pass either to get { items, next_cursor, limit } instead. |
| cursor | string | no | Opaque page cursor — pass a previous response's next_cursor verbatim. null next_cursor means no further pages. |
List your myinvois_invoice rows (newest first).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| limit | integer | no | Page size 1-200. Omit BOTH limit and cursor for the legacy bare-array first page of 200; pass either to get { items, next_cursor, limit } instead. |
| cursor | string | no | Opaque page cursor — pass a previous response's next_cursor verbatim. null next_cursor means no further pages. |
Find generated e-invoices by text: every word must match one of the document's text fields, such as invoice number, buyer name or buyer TIN. Refuses an empty q with VALIDATION_ERROR. Rows carry no field sheet: call myinvois_invoice_read with the id for portal_field_sheet. No match returns an empty list: call myinvois_invoice_list to browse the newest.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| q | string | yes | Search text (substring match over the entity's text properties; %/_ are literal). |
| limit | integer | no | Page size 1-200. Omit BOTH limit and cursor for the legacy bare-array first page of 200; pass either to get { items, next_cursor, limit } instead. |
| cursor | string | no | Opaque page cursor — pass a previous response's next_cursor verbatim. null next_cursor means no further pages. |
[REQUIRES APPROVAL] Save the one-time LHDN supplier profile — the door checks for an existing row on your tenant and creates or updates in place, so this is the only write you ever call. Validates the TIN format, checks msic_code is a 5-digit MSIC code, and checks state_code against the LHDN state table before the row moves. NEXT: myinvois_invoice_generate reads this profile as the supplier party
| Parameter | Type | Required | Notes |
|---|---|---|---|
| scope | string | no | — |
| company_name | string | no | — |
| tin | string | no | — |
| brn | string | no | — |
| sst_number | string | no | — |
| tourism_tax_number | string | no | — |
| contact_number | string | no | — |
| string | no | — | |
| msic_code | string | no | — |
| business_activity | string | no | — |
| address_line1 | string | no | — |
| address_line2 | string | no | — |
| city | string | no | — |
| postal_code | string | no | — |
| state_code | string | no | — |
| country_code | string | no | — |
| invoice_prefix | string | no | — |
| default_currency | string | no | — |
| default_payment_terms | string | no | — |
Read the supplier profile by id: the party printed on every e-invoice (company, TIN, BRN, SST and tourism tax numbers, MSIC code, address). Refuses an id outside your tenant with NOT_FOUND: call myinvois_settings_list, which returns the one profile row. NEXT: myinvois_settings_save to change it.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The myinvois_settings id. |
List the supplier profile: at most one row per tenant. An empty list means setup is not done, and myinvois_invoice_generate refuses until it is: call myinvois_settings_save with the company, TIN, BRN, MSIC code and address. NEXT: myinvois_invoice_generate.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| limit | integer | no | Page size 1-200. Omit BOTH limit and cursor for the legacy bare-array first page of 200; pass either to get { items, next_cursor, limit } instead. |
| cursor | string | no | Opaque page cursor — pass a previous response's next_cursor verbatim. null next_cursor means no further pages. |
Save a reusable line-item preset so a repeat invoice's items do not get re-typed. line_items_json is parsed and each item validated by the SAME checker myinvois_invoice_generate uses (description, quantity, unit_price_cents in integer CENTS, tax_rate_bps in basis points, tax_type/classification_code/unit_code against the LHDN code tables) and re-serialized canonically, so a saved template's items
| Parameter | Type | Required | Notes |
|---|---|---|---|
| name | string | no | — |
| description | string | no | — |
| line_items_json | string | no | — |
| payment_terms | string | no | — |
| notes | string | no | — |
Edit a saved line-item preset. When line_items_json is included it is re-parsed and every item re-validated exactly as create does, so an edited template cannot drift into a shape myinvois_invoice_generate would reject. NEXT: myinvois_template_list to find the id.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| name | string | no | — |
| description | string | no | — |
| line_items_json | string | no | — |
| payment_terms | string | no | — |
| notes | string | no | — |
| id | string | yes | The myinvois_template id (myinvois_template_list shows them). |
| expected_updated_at | integer | no | Optional compare-and-set guard: the updated_at from a prior myinvois_template_list/read. Mismatch returns CONFLICT with the current value. |
Delete a saved line-item preset. E-invoices generated from it are never touched: each one sealed its own lines. Refuses an id outside your tenant with NOT_FOUND: call myinvois_template_list for valid ids.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The myinvois_template id. |
Read one line-item preset by id. Its line_items_json holds generate-ready items: pass them as line_items to myinvois_invoice_generate. Refuses an id outside your tenant with NOT_FOUND: call myinvois_template_list for valid ids.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The myinvois_template id. |
List saved line-item presets, newest first. Each line_items_json is generate-ready: pass its items as line_items to myinvois_invoice_generate. An empty list means none are saved yet: call myinvois_template_create.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| limit | integer | no | Page size 1-200. Omit BOTH limit and cursor for the legacy bare-array first page of 200; pass either to get { items, next_cursor, limit } instead. |
| cursor | string | no | Opaque page cursor — pass a previous response's next_cursor verbatim. null next_cursor means no further pages. |
Edits a quote's header fields and bookkeeping status (draft, sent, accepted, declined move freely). status 'converted' and converted_invoice_id are convert-flow-owned — hand-setting either refuses, and a converted quote is frozen: no status move and no header edit (it could convert again and double-bill; its invoice is the live document, so edit that). tax_scheme and prices_include_tax are fixed a
| Parameter | Type | Required | Notes |
|---|---|---|---|
| client_id | string | no | — |
| quote_number | string | no | — |
| status | string | no | — |
| issue_date | integer | no | — |
| valid_until | integer | no | — |
| currency | string | no | — |
| tax_rate_bps | integer | no | — |
| notes | string | no | — |
| converted_invoice_id | string | no | — |
| tax_scheme | string | no | — |
| prices_include_tax | integer | no | — |
| id | string | yes | The quote id (quote_list shows them). |
| expected_updated_at | integer | no | Optional compare-and-set guard: the updated_at you last read. Mismatch returns CONFLICT with the current value. |
Returns share_url, the client's view link for this quote, and the full document (parties, lines, totals in integer CENTS) in one call. action: 'get' (default) returns the live link; 'rotate' replaces it and the old link stops working; 'revoke' turns it off. A link the owner turned off stays off for agents: 'get' never re-issues it, and an agent's 'rotate' waits for the owner's approval. Anyone wit
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The quote id (quote_list shows them). |
| quote_id | string | no | Alias of id. |
| action | string | no | get (default): the live link, made the first time. rotate: replace it with a new link; the old one stops working. revoke: turn the link off. |
| fresh_after | integer | no | Omit it. Only when an error's next_call includes fresh_after, send that call exactly as given. |
Returns one quote with subtotal_cents, tax_cents and total_cents worked out from its live lines (integer CENTS) and effective_status, which reads 'expired' once a sent quote's valid_until has passed (the stored status never says so). A quote with a tax_scheme also returns tax_summary (each line's tax code, net, tax and gross, and the per-code totals). Refuses an unknown id with NOT_FOUND: find the
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The quote id. |
Lists your quotes, newest first (200 at most; pass limit and cursor to page). Every row carries total_cents (integer CENTS) and effective_status, so an expired quote reads 'expired'. Refuses a limit outside 1-200 or a malformed cursor with VALIDATION_ERROR: resend without them, or with next_cursor exactly as returned.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| limit | integer | no | Page size 1-200. Omit BOTH limit and cursor for the legacy bare-array first page of 200; pass either to get { items, next_cursor, limit } instead. |
| cursor | string | no | Opaque page cursor — pass a previous response's next_cursor verbatim. null next_cursor means no further pages. |
Finds quotes whose text fields (quote number, notes) contain every word of q; rows carry total_cents (integer CENTS) and effective_status. Refuses an empty q with VALIDATION_ERROR: send the quote number, such as QUO-2026-0001, or a word from its notes.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| q | string | yes | Search text (substring match over the entity's text properties; %/_ are literal). |
| limit | integer | no | Page size 1-200. Omit BOTH limit and cursor for the legacy bare-array first page of 200; pass either to get { items, next_cursor, limit } instead. |
| cursor | string | no | Opaque page cursor — pass a previous response's next_cursor verbatim. null next_cursor means no further pages. |
Adds one line item to a quote. unit_price_cents is integer CENTS, 0 or more ($15.00 → 1500); quantity is 0.001 to 1,000,000 with up to 3 decimals (1.5 hours → 1.5); unit is an optional label (hr, kg); discount_bps is an optional line discount (10% → 1000). quantity × unit_price_cents is at most 10,000,000,000. Refuses a negative price (send discount_bps instead), a line above the ceiling (split it
| Parameter | Type | Required | Notes |
|---|---|---|---|
| quote_id | string | no | — |
| description | string | no | — |
| quantity | number | no | How many, up to 3 decimals (1.5 hours → 1.5). A new line defaults to 1. |
| unit_price_cents | integer | no | — |
| position | integer | no | — |
| unit | string | no | — |
| discount_bps | integer | no | Optional line discount in basis points: 10% → 1000, none → 0. A discount is never a lower or negative price. |
| tax_code | string | no | — |
Edits a quote line's description, quantity, unit, price or discount, or moves it to another quote. expected_updated_at is required: the line's updated_at from your read; without it nothing is written and the refusal names the current value; a line changed since then answers CONFLICT. Refuses a line of a converted quote or a move onto one (CONFLICT: change its invoice instead). Bounds: unit_price_c
| Parameter | Type | Required | Notes |
|---|---|---|---|
| quote_id | string | no | — |
| description | string | no | — |
| quantity | number | no | How many, up to 3 decimals (1.5 hours → 1.5). A new line defaults to 1. |
| unit_price_cents | integer | no | — |
| position | integer | no | — |
| unit | string | no | — |
| discount_bps | integer | no | Optional line discount in basis points: 10% → 1000, none → 0. A discount is never a lower or negative price. |
| tax_code | string | no | — |
| id | string | yes | The quote_item id (quote_item_list shows them). |
| expected_updated_at | integer | yes | Required: the line's updated_at from your last read (quote_item_read, quote_item_list or the create answer). Left out, the call is refused and names the current value; a line changed since then return |
Soft-deletes a quote line — it leaves the quote and its totals immediately, but the row is retired for audit history, never removed. expected_updated_at is required: the line's updated_at from your read (quote_item_read); without it the removal is refused and the refusal names the current value. Refuses with CONFLICT when the line changed since that read (read it again and decide on the current li
| Parameter | Type | Required | Notes |
|---|---|---|---|
| quote_id | string | no | — |
| description | string | no | — |
| quantity | integer | no | — |
| unit_price_cents | integer | no | — |
| position | integer | no | — |
| unit | string | no | — |
| discount_bps | integer | no | — |
| tax_code | string | no | — |
| id | string | yes | The quote_item id (quote_item_list shows them). |
| expected_updated_at | integer | yes | Required: the line's updated_at from your last read (quote_item_read, quote_item_list or the create answer). Left out, the call is refused and names the current value; a line changed since then return |
Read one quote_item by id.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The quote_item id. |
List your quote_item rows (newest first).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| limit | integer | no | Page size 1-200. Omit BOTH limit and cursor for the legacy bare-array first page of 200; pass either to get { items, next_cursor, limit } instead. |
| cursor | string | no | Opaque page cursor — pass a previous response's next_cursor verbatim. null next_cursor means no further pages. |
[REQUIRES APPROVAL] Saves your business identity and document defaults (one row per business; scope is 'default'). timezone is the business clock: an invoice turns overdue at midnight in that zone after its due day, and days_overdue counts days there; unset means Asia/Singapore. Left out, timezone and the text fields keep their saved value, but defaulted fields (default_currency, default_tax_rate_
| Parameter | Type | Required | Notes |
|---|---|---|---|
| scope | string | yes | — |
| business_name | string | no | — |
| business_address | string | no | — |
| business_email | string | no | — |
| business_phone | string | no | — |
| tax_id | string | no | — |
| default_currency | string | no | — |
| default_tax_rate_bps | integer | no | — |
| payment_terms_days | integer | no | — |
| invoice_prefix | string | no | — |
| quote_prefix | string | no | — |
| payment_instructions | string | no | — |
| bank_name | string | no | — |
| bank_account | string | no | — |
| template_style | string | no | — |
| brand_primary_color | string | no | — |
| brand_accent_color | string | no | — |
| timezone | string | no | — |
| tax_scheme | string | no | — |
[REQUIRES APPROVAL] Sets where a document type's numbers continue, for example after moving from another invoicing tool. doc_type: invoice, quote, credit_note, debit_note or receipt. next_number is the sequence number the next document gets (42 prints as INV-2026-042). Numbering only moves forward: a number at or below the last one used or skipped is refused with VALIDATION_ERROR naming that numbe
| Parameter | Type | Required | Notes |
|---|---|---|---|
| doc_type | string | yes | Which document type's numbering to change. |
| next_number | integer | no | The sequence number the next document of this type gets. Must be above the last number used or skipped. |
| prefix | string | no | credit_note, debit_note or receipt only: 1-10 letters or digits (plus . _ / -), printed before the year. |
List your sales_settings rows (newest first).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| limit | integer | no | Page size 1-200. Omit BOTH limit and cursor for the legacy bare-array first page of 200; pass either to get { items, next_cursor, limit } instead. |
| cursor | string | no | Opaque page cursor — pass a previous response's next_cursor verbatim. null next_cursor means no further pages. |
Read one sales_settings by id.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The sales_settings id. |
Accept a settlement obligation recorded against your tenant as payee — moves status proposed to accepted and stamps accepted_at under the registry's transition guard. Calling it again on an already-accepted row is idempotent (accepted_at simply re-stamps); once a proposal reaches settled the guard refuses any further move, since settled is terminal. Recording agreement only: no money moves here, s
| Parameter | Type | Required | Notes |
|---|---|---|---|
| payer_tenant_id | string | no | — |
| consent_grant_id | string | no | — |
| amount_cents | integer | no | — |
| currency | string | no | — |
| description | string | no | — |
| related_entity_type | string | no | — |
| related_entity_id | string | no | — |
| status | string | no | — |
| accepted_at | integer | no | — |
| id | string | yes | The settlement_proposal id to accept, recorded against your tenant as payee (settlement_proposal_list shows them). |
List your settlement_proposal rows (newest first).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| limit | integer | no | Page size 1-200. Omit BOTH limit and cursor for the legacy bare-array first page of 200; pass either to get { items, next_cursor, limit } instead. |
| cursor | string | no | Opaque page cursor — pass a previous response's next_cursor verbatim. null next_cursor means no further pages. |
Read one settlement_proposal by id.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The settlement_proposal id. |
Register a spreadsheet file row in the library for bytes that already sit in R2: r2_key must be a spreadsheets/<your tenant>/ key minted by the upload route or spreadsheet.create_with_content — a caller-invented, foreign-tenant, or wrong-domain key is refused. sheet_count, row_count, and column_count are unverified client-reported hints, since nothing server-side parses the binary. NEXT: spreadshe
| Parameter | Type | Required | Notes |
|---|---|---|---|
| r2_key | string | no | — |
| title | string | no | — |
| original_filename | string | no | — |
| file_size | integer | no | — |
| sheet_count | integer | no | — |
| row_count | integer | no | — |
| column_count | integer | no | — |
| sheet_names | string | no | — |
| folder_id | string | no | — |
| tags | string | no | — |
| source | string | no | — |
| ai_prompt | string | no | — |
| last_analyzed_at | integer | no | — |
| analysis_summary | string | no | — |
| deleted_at | integer | no | — |
Edit a spreadsheet file's metadata — title, tags, folder_id, or the AI-analysis fields — without touching the underlying R2 object. r2_key and source are birth facts: including either field in the call at all, even set to its current value, is refused — re-upload as a new file to change custody or provenance. Moving folder_id re-verifies the target folder belongs to your tenant. NEXT: spreadsheet_
| Parameter | Type | Required | Notes |
|---|---|---|---|
| r2_key | string | no | — |
| title | string | no | — |
| original_filename | string | no | — |
| file_size | integer | no | — |
| sheet_count | integer | no | — |
| row_count | integer | no | — |
| column_count | integer | no | — |
| sheet_names | string | no | — |
| folder_id | string | no | — |
| tags | string | no | — |
| source | string | no | — |
| ai_prompt | string | no | — |
| last_analyzed_at | integer | no | — |
| analysis_summary | string | no | — |
| deleted_at | integer | no | — |
| id | string | yes | The spreadsheet_file id (spreadsheet_file_list shows them). |
| expected_updated_at | integer | no | Optional compare-and-set guard: the updated_at you last read. Mismatch returns CONFLICT with the current value. |
Soft-delete a spreadsheet file: stamps deleted_at on the row so it drops out of the library and folder listings, while the row and its R2 object both survive untouched — there is no purge or restore lane yet, so this cannot be reversed through any current door. Requires the file id; an empty id is refused before anything is touched. NEXT: spreadsheet_file_read to confirm deleted_at is now set — th
| Parameter | Type | Required | Notes |
|---|---|---|---|
| r2_key | string | no | — |
| title | string | no | — |
| original_filename | string | no | — |
| file_size | integer | no | — |
| sheet_count | integer | no | — |
| row_count | integer | no | — |
| column_count | integer | no | — |
| sheet_names | string | no | — |
| folder_id | string | no | — |
| tags | string | no | — |
| source | string | no | — |
| ai_prompt | string | no | — |
| last_analyzed_at | integer | no | — |
| analysis_summary | string | no | — |
| deleted_at | integer | no | — |
| id | string | yes | The spreadsheet_file id (spreadsheet_file_list shows them). |
Read one spreadsheet_file by id.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The spreadsheet_file id. |
List your spreadsheet_file rows (newest first).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| limit | integer | no | Page size 1-200. Omit BOTH limit and cursor for the legacy bare-array first page of 200; pass either to get { items, next_cursor, limit } instead. |
| cursor | string | no | Opaque page cursor — pass a previous response's next_cursor verbatim. null next_cursor means no further pages. |
Search your spreadsheet_file rows by text.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| q | string | yes | Search text (substring match over the entity's text properties; %/_ are literal). |
| limit | integer | no | Page size 1-200. Omit BOTH limit and cursor for the legacy bare-array first page of 200; pass either to get { items, next_cursor, limit } instead. |
| cursor | string | no | Opaque page cursor — pass a previous response's next_cursor verbatim. null next_cursor means no further pages. |
Create a spreadsheet_folder.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| name | string | yes | — |
| color | string | no | — |
Update a spreadsheet_folder you own (optionally compare-and-set via expected_updated_at).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The spreadsheet_folder id. |
| name | string | no | — |
| color | string | no | — |
| expected_updated_at | integer | no | Optional compare-and-set guard: the updated_at you last read. Mismatch returns CONFLICT with the current value. |
Delete a spreadsheet_folder you own.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The spreadsheet_folder id. |
Read one spreadsheet_folder by id.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The spreadsheet_folder id. |
List your spreadsheet_folder rows (newest first).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| limit | integer | no | Page size 1-200. Omit BOTH limit and cursor for the legacy bare-array first page of 200; pass either to get { items, next_cursor, limit } instead. |
| cursor | string | no | Opaque page cursor — pass a previous response's next_cursor verbatim. null next_cursor means no further pages. |
List your sticky_note rows (newest first).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| limit | integer | no | Page size 1-200. Omit BOTH limit and cursor for the legacy bare-array first page of 200; pass either to get { items, next_cursor, limit } instead. |
| cursor | string | no | Opaque page cursor — pass a previous response's next_cursor verbatim. null next_cursor means no further pages. |
Update a sticky_note you own (optionally compare-and-set via expected_updated_at).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The sticky_note id. |
| content | string | no | — |
| color | string | no | — |
| position_x | integer | no | — |
| position_y | integer | no | — |
| triggers_at | integer | no | — |
| z_index | integer | no | — |
| width | integer | no | — |
| height | integer | no | — |
| expected_updated_at | integer | no | Optional compare-and-set guard: the updated_at you last read. Mismatch returns CONFLICT with the current value. |
Delete a sticky_note you own.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The sticky_note id. |
Read this tenant's sticky notes whose reminder time (triggers_at) has arrived — the poll the desktop host runs to know what to fire as a local notification, since the web itself has no send channel. Read-only, no arguments: now is always the server's clock, never a caller-supplied value, and only notes with triggers_at set and <= now come back, soonest-due first, capped at 200. NEXT: sticky_note_d
| Parameter | Type | Required | Notes |
|---|---|---|---|
| content | string | no | — |
| color | string | no | — |
| position_x | integer | no | — |
| position_y | integer | no | — |
| triggers_at | integer | no | — |
| z_index | integer | no | — |
| width | integer | no | — |
| height | integer | no | — |
Clear a sticky note's reminder (triggers_at back to NULL) so it drops out of the sticky_note_due poll — call this after the host fires the local notification for it. Runs through the same tenant-scoped write path as every entity update, but via a clear-properties op: ordinary updates ignore null values, so this is the only way to null the column. Idempotent — dismissing an already-cleared note jus
| Parameter | Type | Required | Notes |
|---|---|---|---|
| content | string | no | — |
| color | string | no | — |
| position_x | integer | no | — |
| position_y | integer | no | — |
| triggers_at | integer | no | — |
| z_index | integer | no | — |
| width | integer | no | — |
| height | integer | no | — |
| id | string | yes | The sticky note id to dismiss (sticky_note_due or sticky_note_list shows them). |
Create a stock_item.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| name | string | yes | — |
| quantity | integer | no | — |
| unit | string | no | — |
| low_stock_threshold | integer | no | — |
| cost_per_unit_cents | integer | no | — |
| sell_price_cents | integer | no | — |
| category | string | no | — |
| expiry_date | string | no | — |
| notes | string | no | — |
| is_active | integer | no | — |
Update a stock_item you own (optionally compare-and-set via expected_updated_at).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The stock_item id. |
| name | string | no | — |
| quantity | integer | no | — |
| unit | string | no | — |
| low_stock_threshold | integer | no | — |
| cost_per_unit_cents | integer | no | — |
| sell_price_cents | integer | no | — |
| category | string | no | — |
| expiry_date | string | no | — |
| notes | string | no | — |
| is_active | integer | no | — |
| expected_updated_at | integer | no | Optional compare-and-set guard: the updated_at you last read. Mismatch returns CONFLICT with the current value. |
Soft-delete a stock item by id: sets is_active to 0 while its movements-ledger history stays intact. stock_item_adjust then refuses the id as NOT_FOUND and stops resolving it by name, so a later delivery under the same name creates a fresh item instead of reviving this one. stock_item_list and stock_item_read still return it with is_active: 0 — only the dashboard's stats header excludes it. Restor
| Parameter | Type | Required | Notes |
|---|---|---|---|
| name | string | no | — |
| quantity | integer | no | — |
| unit | string | no | — |
| low_stock_threshold | integer | no | — |
| cost_per_unit_cents | integer | no | — |
| sell_price_cents | integer | no | — |
| category | string | no | — |
| expiry_date | string | no | — |
| notes | string | no | — |
| is_active | integer | no | — |
| id | string | yes | The stock item id to soft-delete (stock_item_list shows them). |
Read one stock_item by id.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The stock_item id. |
List your stock_item rows (newest first).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| limit | integer | no | Page size 1-200. Omit BOTH limit and cursor for the legacy bare-array first page of 200; pass either to get { items, next_cursor, limit } instead. |
| cursor | string | no | Opaque page cursor — pass a previous response's next_cursor verbatim. null next_cursor means no further pages. |
Search your stock_item rows by text.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| q | string | yes | Search text (substring match over the entity's text properties; %/_ are literal). |
| limit | integer | no | Page size 1-200. Omit BOTH limit and cursor for the legacy bare-array first page of 200; pass either to get { items, next_cursor, limit } instead. |
| cursor | string | no | Opaque page cursor — pass a previous response's next_cursor verbatim. null next_cursor means no further pages. |
Create a studio_character.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| name | string | yes | — |
| description | string | yes | — |
| prompt_suffix | string | no | — |
| reference_image_key | string | no | — |
| color_tag | string | no | — |
Read one studio_character by id.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The studio_character id. |
List your studio_character rows (newest first).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| limit | integer | no | Page size 1-200. Omit BOTH limit and cursor for the legacy bare-array first page of 200; pass either to get { items, next_cursor, limit } instead. |
| cursor | string | no | Opaque page cursor — pass a previous response's next_cursor verbatim. null next_cursor means no further pages. |
Update a studio_character you own (optionally compare-and-set via expected_updated_at).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The studio_character id. |
| name | string | no | — |
| description | string | no | — |
| prompt_suffix | string | no | — |
| reference_image_key | string | no | — |
| color_tag | string | no | — |
| expected_updated_at | integer | no | Optional compare-and-set guard: the updated_at you last read. Mismatch returns CONFLICT with the current value. |
Delete a studio_character you own.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The studio_character id. |
Create a studio_environment.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| name | string | yes | — |
| description | string | yes | — |
| prompt_suffix | string | no | — |
| reference_image_key | string | no | — |
| color_tag | string | no | — |
Read one studio_environment by id.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The studio_environment id. |
List your studio_environment rows (newest first).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| limit | integer | no | Page size 1-200. Omit BOTH limit and cursor for the legacy bare-array first page of 200; pass either to get { items, next_cursor, limit } instead. |
| cursor | string | no | Opaque page cursor — pass a previous response's next_cursor verbatim. null next_cursor means no further pages. |
Update a studio_environment you own (optionally compare-and-set via expected_updated_at).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The studio_environment id. |
| name | string | no | — |
| description | string | no | — |
| prompt_suffix | string | no | — |
| reference_image_key | string | no | — |
| color_tag | string | no | — |
| expected_updated_at | integer | no | Optional compare-and-set guard: the updated_at you last read. Mismatch returns CONFLICT with the current value. |
Delete a studio_environment you own.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The studio_environment id. |
Create a video studio project — the composition document (scenes, tracks, clips, captions) starts empty and is built up afterward through the studio.* director tools. thumbnail_key is server-owned: send thumbnail_data_url instead, and this door externalizes it into a content-addressed R2 key through the media hygiene kit (magic bytes decide the type; SVG refuses). Free. NEXT: studio_project_read t
| Parameter | Type | Required | Notes |
|---|---|---|---|
| name | string | no | — |
| status | string | no | — |
| thumbnail_key | string | no | — |
| thumbnail_data_url | string | no | Data URL (data:image/...) of the project thumbnail — the door externalizes it into a content-addressed R2 key through the media hygiene kit (magic bytes decide the type; SVG refuses). Never send thumb |
Read one studio_project by id.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The studio_project id. |
List your studio_project rows (newest first).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| limit | integer | no | Page size 1-200. Omit BOTH limit and cursor for the legacy bare-array first page of 200; pass either to get { items, next_cursor, limit } instead. |
| cursor | string | no | Opaque page cursor — pass a previous response's next_cursor verbatim. null next_cursor means no further pages. |
Rename a project, change its status, or replace its thumbnail on a project you own — send thumbnail_data_url, never thumbnail_key, which is server-owned and computed by this door the same way studio_project_create does. status here is UI-summary-only by design: it never gates render or generation, which are tracked separately by the export job row and the composition document's own scene status. F
| Parameter | Type | Required | Notes |
|---|---|---|---|
| name | string | no | — |
| status | string | no | — |
| thumbnail_key | string | no | — |
| id | string | yes | The studio project id to update (studio_project_list shows them). |
| expected_updated_at | integer | no | Optional compare-and-set guard: the updated_at you last read. Mismatch returns CONFLICT with the current value. |
| thumbnail_data_url | string | no | Data URL (data:image/...) of the project thumbnail — the door externalizes it into a content-addressed R2 key through the media hygiene kit (magic bytes decide the type; SVG refuses). Never send thumb |
Delete a studio_project you own.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The studio_project id. |
Edits an assignment's content (title/description/priority/due_at/attachment) — only the assigner may call this, and only before the job reaches a terminal state. assigned_to cannot move here even though it is a writable column: reassigning is a separate transition that also opens a 30-second undo window. NEXT: team_assignment_reassign to hand the job to someone else.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| assigned_to | string | no | — |
| title | string | no | — |
| description | string | no | — |
| priority | string | no | — |
| status | string | no | — |
| due_at | integer | no | — |
| accepted_at | integer | no | — |
| started_at | integer | no | — |
| completed_at | integer | no | — |
| declined_at | integer | no | — |
| decline_reason | string | no | — |
| completion_notes | string | no | — |
| attachment_key | string | no | — |
| attachment_name | string | no | — |
| attachment_type | string | no | — |
| photos_json | string | no | — |
| artifact_id | string | no | — |
| previous_assignee | string | no | — |
| previous_status | string | no | — |
| reassigned_by | string | no | — |
Deletes an assignment outright — only the assigner may call this. The row is removed first, then its attachment and any job photos are best-effort deleted from R2 afterward, so a storage hiccup never leaves the assignment stranded. NEXT: team_assignment_list to confirm it is gone.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| assigned_to | string | no | — |
| title | string | no | — |
| description | string | no | — |
| priority | string | no | — |
| status | string | no | — |
| due_at | integer | no | — |
| accepted_at | integer | no | — |
| started_at | integer | no | — |
| completed_at | integer | no | — |
| declined_at | integer | no | — |
| decline_reason | string | no | — |
| completion_notes | string | no | — |
| attachment_key | string | no | — |
| attachment_name | string | no | — |
| attachment_type | string | no | — |
| photos_json | string | no | — |
| artifact_id | string | no | — |
| previous_assignee | string | no | — |
| previous_status | string | no | — |
| reassigned_by | string | no | — |
Accepts a pending job — only the assignee may call this, and only while the assignment is still 'pending'; it stamps accepted_at and moves status to 'accepted'. NEXT: team_assignment_start once you begin the work.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| assigned_to | string | no | — |
| title | string | no | — |
| description | string | no | — |
| priority | string | no | — |
| status | string | no | — |
| due_at | integer | no | — |
| accepted_at | integer | no | — |
| started_at | integer | no | — |
| completed_at | integer | no | — |
| declined_at | integer | no | — |
| decline_reason | string | no | — |
| completion_notes | string | no | — |
| attachment_key | string | no | — |
| attachment_name | string | no | — |
| attachment_type | string | no | — |
| photos_json | string | no | — |
| artifact_id | string | no | — |
| previous_assignee | string | no | — |
| previous_status | string | no | — |
| reassigned_by | string | no | — |
Marks a job as started — only the assignee, and only from status 'accepted'; it stamps started_at and moves status to 'in_progress'. NEXT: team_assignment_add_photo for proof, then team_assignment_complete when done.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| assigned_to | string | no | — |
| title | string | no | — |
| description | string | no | — |
| priority | string | no | — |
| status | string | no | — |
| due_at | integer | no | — |
| accepted_at | integer | no | — |
| started_at | integer | no | — |
| completed_at | integer | no | — |
| declined_at | integer | no | — |
| decline_reason | string | no | — |
| completion_notes | string | no | — |
| attachment_key | string | no | — |
| attachment_name | string | no | — |
| attachment_type | string | no | — |
| photos_json | string | no | — |
| artifact_id | string | no | — |
| previous_assignee | string | no | — |
| previous_status | string | no | — |
| reassigned_by | string | no | — |
Finishes a job — only the assignee, and only from status 'in_progress'; it stamps completed_at, moves status to 'completed', and stores completion_notes when you supply them. Completed is terminal: the row can no longer be edited or reassigned (deletion by the assigner is still possible).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| assigned_to | string | no | — |
| title | string | no | — |
| description | string | no | — |
| priority | string | no | — |
| status | string | no | — |
| due_at | integer | no | — |
| accepted_at | integer | no | — |
| started_at | integer | no | — |
| completed_at | integer | no | — |
| declined_at | integer | no | — |
| decline_reason | string | no | — |
| completion_notes | string | no | — |
| attachment_key | string | no | — |
| attachment_name | string | no | — |
| attachment_type | string | no | — |
| photos_json | string | no | — |
| artifact_id | string | no | — |
| previous_assignee | string | no | — |
| previous_status | string | no | — |
| reassigned_by | string | no | — |
Declines a job — only the assignee, and only while it is 'pending' or 'accepted'; decline_reason is required and is stamped alongside declined_at. Declined is terminal, same as completed: the assignment cannot be edited or reassigned afterward.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| assigned_to | string | no | — |
| title | string | no | — |
| description | string | no | — |
| priority | string | no | — |
| status | string | no | — |
| due_at | integer | no | — |
| accepted_at | integer | no | — |
| started_at | integer | no | — |
| completed_at | integer | no | — |
| declined_at | integer | no | — |
| decline_reason | string | no | — |
| completion_notes | string | no | — |
| attachment_key | string | no | — |
| attachment_name | string | no | — |
| attachment_type | string | no | — |
| photos_json | string | no | — |
| artifact_id | string | no | — |
| previous_assignee | string | no | — |
| previous_status | string | no | — |
| reassigned_by | string | no | — |
Hands an assignment to a different tenant member — only the original assigner or an admin+, never the current assignee reassigning themself, and never onto a terminal (completed/declined) row. It resets status to 'pending' for the new assignee and records the prior assignee/status so the move can be undone. NEXT: team_assignment_undo_reassign within 30 seconds reverts it.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| assigned_to | string | no | — |
| title | string | no | — |
| description | string | no | — |
| priority | string | no | — |
| status | string | no | — |
| due_at | integer | no | — |
| accepted_at | integer | no | — |
| started_at | integer | no | — |
| completed_at | integer | no | — |
| declined_at | integer | no | — |
| decline_reason | string | no | — |
| completion_notes | string | no | — |
| attachment_key | string | no | — |
| attachment_name | string | no | — |
| attachment_type | string | no | — |
| photos_json | string | no | — |
| artifact_id | string | no | — |
| previous_assignee | string | no | — |
| previous_status | string | no | — |
| reassigned_by | string | no | — |
Reverts an assignment's most recent reassignment — restores the previous assignee and status. Only the person who performed that reassignment may call it, and only within the 30-second window after it happened; past that, CONFLICT says to reassign again instead.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| assigned_to | string | no | — |
| title | string | no | — |
| description | string | no | — |
| priority | string | no | — |
| status | string | no | — |
| due_at | integer | no | — |
| accepted_at | integer | no | — |
| started_at | integer | no | — |
| completed_at | integer | no | — |
| declined_at | integer | no | — |
| decline_reason | string | no | — |
| completion_notes | string | no | — |
| attachment_key | string | no | — |
| attachment_name | string | no | — |
| attachment_type | string | no | — |
| photos_json | string | no | — |
| artifact_id | string | no | — |
| previous_assignee | string | no | — |
| previous_status | string | no | — |
| reassigned_by | string | no | — |
Attaches a job photo to an assignment — only the assignee, and only while the job is 'accepted', 'in_progress', or 'completed'. photo_key must be one minted by POST /api/desk/assignments/upload for this tenant; re-attaching the same key is a no-op, and the row holds at most 20 photos. NEXT: team_assignment_complete once proof is attached.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| assigned_to | string | no | — |
| title | string | no | — |
| description | string | no | — |
| priority | string | no | — |
| status | string | no | — |
| due_at | integer | no | — |
| accepted_at | integer | no | — |
| started_at | integer | no | — |
| completed_at | integer | no | — |
| declined_at | integer | no | — |
| decline_reason | string | no | — |
| completion_notes | string | no | — |
| attachment_key | string | no | — |
| attachment_name | string | no | — |
| attachment_type | string | no | — |
| photos_json | string | no | — |
| artifact_id | string | no | — |
| previous_assignee | string | no | — |
| previous_status | string | no | — |
| reassigned_by | string | no | — |
Read one team_assignment by id.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The team_assignment id. |
List your team_assignment rows (newest first).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| limit | integer | no | Page size 1-200. Omit BOTH limit and cursor for the legacy bare-array first page of 200; pass either to get { items, next_cursor, limit } instead. |
| cursor | string | no | Opaque page cursor — pass a previous response's next_cursor verbatim. null next_cursor means no further pages. |
Create-or-update a user_interest keyed on interest.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| interest | string | yes | — |
List your user_interest rows (newest first).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| limit | integer | no | Page size 1-200. Omit BOTH limit and cursor for the legacy bare-array first page of 200; pass either to get { items, next_cursor, limit } instead. |
| cursor | string | no | Opaque page cursor — pass a previous response's next_cursor verbatim. null next_cursor means no further pages. |
Delete a user_interest you own.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The user_interest id. |
Create-or-update a user_setting keyed on key.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| key | string | yes | — |
| value | string | yes | — |
| value_type | string | no | — |
Read one user_setting by id.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The user_setting id. |
List your user_setting rows (newest first).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| limit | integer | no | Page size 1-200. Omit BOTH limit and cursor for the legacy bare-array first page of 200; pass either to get { items, next_cursor, limit } instead. |
| cursor | string | no | Opaque page cursor — pass a previous response's next_cursor verbatim. null next_cursor means no further pages. |
Search your user_setting rows by text.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| q | string | yes | Search text (substring match over the entity's text properties; %/_ are literal). |
| limit | integer | no | Page size 1-200. Omit BOTH limit and cursor for the legacy bare-array first page of 200; pass either to get { items, next_cursor, limit } instead. |
| cursor | string | no | Opaque page cursor — pass a previous response's next_cursor verbatim. null next_cursor means no further pages. |
Delete a user_setting you own.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The user_setting id. |
Edit a workflow's fields or its definition graph: every call re-validates the definition — yours if resent, else the stored one decoded back — against the resulting trigger_type, so a plain rename can fail if that stored graph no longer validates, and flipping to 'schedule' without a schedule block fails here rather than at the scheduler. When trigger_type ends as 'schedule' and is_active as 1, ne
| Parameter | Type | Required | Notes |
|---|---|---|---|
| name | string | no | — |
| description | string | no | — |
| role_name | string | no | — |
| definition_json | string | no | — |
| trigger_type | string | no | — |
| is_active | integer | no | — |
| next_run_at | integer | no | — |
| imported_from | string | no | — |
| id | string | yes | The workflow id (workflow_list shows them). |
| expected_updated_at | integer | no | Optional compare-and-set guard: the updated_at from a prior workflow_read/workflow_list. Mismatch returns CONFLICT with the current value. |
Read one workflow by id.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The workflow id. |
List your workflow rows (newest first).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| limit | integer | no | Page size 1-200. Omit BOTH limit and cursor for the legacy bare-array first page of 200; pass either to get { items, next_cursor, limit } instead. |
| cursor | string | no | Opaque page cursor — pass a previous response's next_cursor verbatim. null next_cursor means no further pages. |
Delete a workflow you own.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The workflow id. |
Make the PDF of an issued invoice (or of its receipt once paid): the same document as its print-ready page, printed on A4 with the business's fonts, brand colours and logo, and kept, so asking again for an unchanged invoice returns the stored file (cached: true) without printing it again. Totals are the stored figures (the same numbers invoice_read gives). It prepares a file and sends nothing. Ret
| Parameter | Type | Required | Notes |
|---|---|---|---|
| id | string | yes | The invoice's id, from invoice_list or invoice_read. |
How each numbered document type counts, one row each for invoice, quote, credit_note, debit_note and receipt: prefix, last_number (the highest number already used or skipped), next_number, and next_preview, the number the next one prints (this year's form, such as INV-2026-042). Copy next_preview, never build it. Change a next number, or a credit note, debit note or receipt prefix, with sales_sett
No parameter schema on file.
Make the PDF of a client's statement of account (the same page statement_prepare's document_path shows), printed on A4 with the business's fonts, brand colours and logo, and kept, so asking again for an unchanged statement returns the stored file (cached: true) without printing it again. It prepares a file and sends nothing. Returns version, pdf_path (downloads while signed in) and closing_balance
| Parameter | Type | Required | Notes |
|---|---|---|---|
| client_id | string | yes | The client's id, from invoice_client_search (by name) or invoice_client_list. |
| from | string | no | First day of the period, YYYY-MM-DD in the business's time zone. Default: the first day of the month of to. |
| to | string | no | Last day of the period, YYYY-MM-DD in the business's time zone, today at the latest. Default: today. |
Import one bank account's statement as CSV text (CSV today, PDF later) so the forecast starts from the bank's own balance. Owner or admin only. Stores each line and each day's closing balance for the account named by bank_label, account_last4 and currency; uploading the same statement again adds nothing. Name an account the same way every time (the label is matched ignoring case). Before anything
| Parameter | Type | Required | Notes |
|---|---|---|---|
| csv_text | string | yes | The statement exported from online banking as CSV, at most 2,000,000 bytes. A title block above the header row is fine. |
| bank_label | string | yes | The bank's name, such as DBS or Maybank. No account number. |
| account_last4 | string | yes | The account number's last 4 digits as text, such as "0123". A longer number is cut to its last 4. |
| currency | string | yes | The account's currency. |
| mapping | object | no | Optional: 1-based column numbers, sent after a refusal lists the file's columns. Needs date and balance, plus amount (money in positive) or both debit and credit. |
| date_order | string | no | Optional: send only when a refusal says every date can be read two ways. day_first reads 03/04/2026 as 3 April. |
| new_account | boolean | no | Optional: send true only after a SIMPLER_BANKING_ACCOUNT_LABEL_CONFLICT refusal, when this statement is from a different account that shares the saved account's last 4 digits and currency. Leave it ou |
[paid: $0.04/image] Generate 1-3 variations of a reference image guided by a prompt (FLUX Pro Kontext, context-aware). Pass image_asset_key (an earlier result) or image_url (public https or data:image) plus a prompt describing the change. Each image is stored in this workspace's image library and returned as JSON {images:[{url, asset_key, download_url?, width, height}], price, next} plus a preview
| Parameter | Type | Required | Notes |
|---|---|---|---|
| image_url | string | no | The reference image: a public https URL, a data:image/...;base64 URL, or the url/url_path of an earlier image result (max 20MB; PNG, JPEG, WebP or GIF; SVG is refused). Pass this or the matching *_ass |
| image_asset_key | string | no | The reference image, as the asset_key of an earlier image result for this workspace (edit-projects/<tenant>/... or images/<tenant>/...). A key from another workspace is refused (SIMPLER_MEDIA_FOREIGN_ |
| prompt | string | yes | How to vary the image (max 1500 chars). |
| count | number | no | Number of variations (1-3, default 1). |
| request_ref | string | no | Optional idempotency key (1-64 chars: letters, digits, . _ : -). Retrying with the same request_ref and the same arguments within 24 hours returns the first result at $0 with replayed: true; the same |
| preview_format | string | no | Preview block after the JSON, at most 384px on the long edge and never charged: png, jpeg or none. Left out, a PNG result gets a png preview and a JPEG or WebP result a jpeg one. A result with no prev |
[paid: $0.0005] Convert an image to PNG, JPEG or WebP, and optionally bound its size, with the Cloudflare Images service: a PNG, JPEG, WebP, GIF or HEIC goes in and the result is stored in this workspace. format is png, jpeg, webp (AVIF is not offered). quality (1-100, default 85) applies to jpeg and webp. width and height (16-4096 px) bound the result and fit picks how: scale-down (the default) s
| Parameter | Type | Required | Notes |
|---|---|---|---|
| image_url | string | no | The image to convert: a public https URL, a data:image/...;base64 URL, or the url/url_path of an earlier image result (max 20MB; PNG, JPEG, WebP, GIF or HEIC; SVG is refused). Pass this or image_asset |
| image_asset_key | string | no | The image to convert, as the asset_key of an earlier image result for this workspace (edit-projects/<tenant>/... or images/<tenant>/...). A key from another workspace is refused (SIMPLER_MEDIA_FOREIGN |
| format | string | yes | The result's file type: png (lossless, keeps transparency), jpeg (smallest for photos, no transparency) or webp. |
| quality | integer | no | jpeg and webp only: 1-100, default 85. Refused with png. |
| width | integer | no | Bounding width in pixels; leave width and height out to keep the size. |
| height | integer | no | Bounding height in pixels; leave width and height out to keep the size. |
| fit | string | no | How the image fits width and height (default scale-down). Needs width or height. |
| background | string | no | #RRGGBB under transparent pixels and around a padded image. A jpeg defaults to #FFFFFF. |
| request_ref | string | no | Optional idempotency key (1-64 chars: letters, digits, . _ : -). Retrying with the same request_ref and the same arguments within 24 hours returns the first result at $0 with replayed: true; the same |
| preview_format | string | no | Preview block after the JSON, at most 384px on the long edge and never charged: png, jpeg or none. Left out, a PNG result gets a png preview and a JPEG or WebP result a jpeg one. A result with no prev |
[paid: $0.02] Remove the background from a photo, returning the subject on transparency (BiRefNet). Returns JSON {images:[{url, asset_key, download_url?, width, height}], price, next} plus a preview; images are stored in this workspace, never provider links, and a result with no download_url says why in download_url_unavailable. Refuses: SIMPLER_MEDIA_INPUT_MISSING (pass the url or the asset_key),
| Parameter | Type | Required | Notes |
|---|---|---|---|
| image_url | string | no | Source photo: a public https URL, a data:image/...;base64 URL, or the url/url_path of an earlier image result (max 20MB; PNG, JPEG, WebP or GIF; SVG is refused). Pass this or the matching *_asset_key, |
| image_asset_key | string | no | Source photo, as the asset_key of an earlier image result for this workspace (edit-projects/<tenant>/... or images/<tenant>/...). A key from another workspace is refused (SIMPLER_MEDIA_FOREIGN_KEY). |
| request_ref | string | no | Optional idempotency key (1-64 chars: letters, digits, . _ : -). Retrying with the same request_ref and the same arguments within 24 hours returns the first result at $0 with replayed: true; the same |
| preview_format | string | no | Preview block after the JSON, at most 384px on the long edge and never charged: png, jpeg or none. Left out, a PNG result gets a png preview and a JPEG or WebP result a jpeg one. A result with no prev |
[paid: $0.06] Upscale a photo 4x via aura-sr super-resolution. Returns JSON {images:[{url, asset_key, download_url?, width, height}], price, next} plus a preview; images are stored in this workspace, never provider links, and a result with no download_url says why in download_url_unavailable. Refuses: SIMPLER_MEDIA_INPUT_MISSING (pass the url or the asset_key), SIMPLER_MEDIA_FOREIGN_KEY (use this
| Parameter | Type | Required | Notes |
|---|---|---|---|
| image_url | string | no | Source photo: a public https URL, a data:image/...;base64 URL, or the url/url_path of an earlier image result (max 20MB; PNG, JPEG, WebP or GIF; SVG is refused). Pass this or the matching *_asset_key, |
| image_asset_key | string | no | Source photo, as the asset_key of an earlier image result for this workspace (edit-projects/<tenant>/... or images/<tenant>/...). A key from another workspace is refused (SIMPLER_MEDIA_FOREIGN_KEY). |
| request_ref | string | no | Optional idempotency key (1-64 chars: letters, digits, . _ : -). Retrying with the same request_ref and the same arguments within 24 hours returns the first result at $0 with replayed: true; the same |
| preview_format | string | no | Preview block after the JSON, at most 384px on the long edge and never charged: png, jpeg or none. Left out, a PNG result gets a png preview and a JPEG or WebP result a jpeg one. A result with no prev |
[paid: $0.07] Remove or replace a masked region of a photo (FLUX Fill). White mask pixels = edit region. Returns JSON {images:[{url, asset_key, download_url?, width, height}], price, next} plus a preview; images are stored in this workspace, never provider links, and a result with no download_url says why in download_url_unavailable. Refuses: SIMPLER_MEDIA_INPUT_MISSING (pass the url or the asset_
| Parameter | Type | Required | Notes |
|---|---|---|---|
| image_url | string | no | Source photo: a public https URL, a data:image/...;base64 URL, or the url/url_path of an earlier image result (max 20MB; PNG, JPEG, WebP or GIF; SVG is refused). Pass this or the matching *_asset_key, |
| image_asset_key | string | no | Source photo, as the asset_key of an earlier image result for this workspace (edit-projects/<tenant>/... or images/<tenant>/...). A key from another workspace is refused (SIMPLER_MEDIA_FOREIGN_KEY). |
| mask_url | string | no | Mask (white = edit region): a public https URL, a data:image/...;base64 URL, or the url/url_path of an earlier image result (max 20MB; PNG, JPEG, WebP or GIF; SVG is refused). Pass this or the matchin |
| mask_asset_key | string | no | Mask (white = edit region), as the asset_key of an earlier image result for this workspace (edit-projects/<tenant>/... or images/<tenant>/...). A key from another workspace is refused (SIMPLER_MEDIA_F |
| prompt | string | no | What to paint in; empty removes. |
| request_ref | string | no | Optional idempotency key (1-64 chars: letters, digits, . _ : -). Retrying with the same request_ref and the same arguments within 24 hours returns the first result at $0 with replayed: true; the same |
| preview_format | string | no | Preview block after the JSON, at most 384px on the long edge and never charged: png, jpeg or none. Left out, a PNG result gets a png preview and a JPEG or WebP result a jpeg one. A result with no prev |
[paid: $0.07] Replace a photo's sky (FLUX Fill). Pass a mask covering the sky (white = sky). Returns JSON {images:[{url, asset_key, download_url?, width, height}], price, next} plus a preview; images are stored in this workspace, never provider links, and a result with no download_url says why in download_url_unavailable. Refuses: SIMPLER_MEDIA_INPUT_MISSING (pass the url or the asset_key), SIMPLE
| Parameter | Type | Required | Notes |
|---|---|---|---|
| image_url | string | no | Source photo: a public https URL, a data:image/...;base64 URL, or the url/url_path of an earlier image result (max 20MB; PNG, JPEG, WebP or GIF; SVG is refused). Pass this or the matching *_asset_key, |
| image_asset_key | string | no | Source photo, as the asset_key of an earlier image result for this workspace (edit-projects/<tenant>/... or images/<tenant>/...). A key from another workspace is refused (SIMPLER_MEDIA_FOREIGN_KEY). |
| mask_url | string | no | Sky mask (white = sky): a public https URL, a data:image/...;base64 URL, or the url/url_path of an earlier image result (max 20MB; PNG, JPEG, WebP or GIF; SVG is refused). Pass this or the matching *_ |
| mask_asset_key | string | no | Sky mask (white = sky), as the asset_key of an earlier image result for this workspace (edit-projects/<tenant>/... or images/<tenant>/...). A key from another workspace is refused (SIMPLER_MEDIA_FOREI |
| prompt | string | no | Sky description. |
| request_ref | string | no | Optional idempotency key (1-64 chars: letters, digits, . _ : -). Retrying with the same request_ref and the same arguments within 24 hours returns the first result at $0 with replayed: true; the same |
| preview_format | string | no | Preview block after the JSON, at most 384px on the long edge and never charged: png, jpeg or none. Left out, a PNG result gets a png preview and a JPEG or WebP result a jpeg one. A result with no prev |
[paid: $0.07] Replace a photo's background with a generated scene (FLUX Fill). Pass a mask covering the background (white = background). Returns JSON {images:[{url, asset_key, download_url?, width, height}], price, next} plus a preview; images are stored in this workspace, never provider links, and a result with no download_url says why in download_url_unavailable. Refuses: SIMPLER_MEDIA_INPUT_MIS
| Parameter | Type | Required | Notes |
|---|---|---|---|
| image_url | string | no | Source photo: a public https URL, a data:image/...;base64 URL, or the url/url_path of an earlier image result (max 20MB; PNG, JPEG, WebP or GIF; SVG is refused). Pass this or the matching *_asset_key, |
| image_asset_key | string | no | Source photo, as the asset_key of an earlier image result for this workspace (edit-projects/<tenant>/... or images/<tenant>/...). A key from another workspace is refused (SIMPLER_MEDIA_FOREIGN_KEY). |
| mask_url | string | no | Background mask (white = background): a public https URL, a data:image/...;base64 URL, or the url/url_path of an earlier image result (max 20MB; PNG, JPEG, WebP or GIF; SVG is refused). Pass this or t |
| mask_asset_key | string | no | Background mask (white = background), as the asset_key of an earlier image result for this workspace (edit-projects/<tenant>/... or images/<tenant>/...). A key from another workspace is refused (SIMPL |
| prompt | string | yes | Scene description. |
| request_ref | string | no | Optional idempotency key (1-64 chars: letters, digits, . _ : -). Retrying with the same request_ref and the same arguments within 24 hours returns the first result at $0 with replayed: true; the same |
| preview_format | string | no | Preview block after the JSON, at most 384px on the long edge and never charged: png, jpeg or none. Left out, a PNG result gets a png preview and a JPEG or WebP result a jpeg one. A result with no prev |
Match a pasted subject's light and colour to its scene: a Reinhard colour transfer in CIELAB moves the subject's mean and spread toward the scene's, weighted by the subject mask, at strength 0..100 (default 60). Pixels outside the mask never change. Pass the composite plus a subject mask (white = subject, black = scene). Free: runs on the platform's own deterministic kernel, so the same input and
| Parameter | Type | Required | Notes |
|---|---|---|---|
| image_url | string | no | Composite image: a public https URL, a data:image/...;base64 URL, or the url/url_path of an earlier image result (max 20MB; PNG, JPEG, WebP or GIF; SVG is refused). Pass this or the matching *_asset_k |
| image_asset_key | string | no | Composite image, as the asset_key of an earlier image result for this workspace (edit-projects/<tenant>/... or images/<tenant>/...). A key from another workspace is refused (SIMPLER_MEDIA_FOREIGN_KEY) |
| subject_mask_url | string | no | Subject mask (white = subject): a public https URL, a data:image/...;base64 URL, or the url/url_path of an earlier image result (max 20MB; PNG, JPEG, WebP or GIF; SVG is refused). Pass this or the mat |
| subject_mask_asset_key | string | no | Subject mask (white = subject), as the asset_key of an earlier image result for this workspace (edit-projects/<tenant>/... or images/<tenant>/...). A key from another workspace is refused (SIMPLER_MED |
| strength | integer | no | How far to move the subject toward the scene, 0..100 (default 60). |
| request_ref | string | no | Optional idempotency key (1-64 chars: letters, digits, . _ : -). Retrying with the same request_ref and the same arguments within 24 hours returns the first result at $0 with replayed: true; the same |
| preview_format | string | no | Preview block after the JSON, at most 384px on the long edge and never charged: png, jpeg or none. Left out, a PNG result gets a png preview and a JPEG or WebP result a jpeg one. A result with no prev |
Add a product shadow to a cut-out (subject on transparency), cast from its alpha: kind drop, contact or reflection. angle 0..359 is the light direction counterclockwise from 3 o'clock (default 120; the shadow falls the other way); distance 0..200 px (default 12; the gap under the base for a reflection); blur 0..100 px (default 16); opacity 0..100 (default 50); transparent true (default) keeps the
| Parameter | Type | Required | Notes |
|---|---|---|---|
| image_url | string | no | Cut-out subject on transparency: a public https URL, a data:image/...;base64 URL, or the url/url_path of an earlier image result (max 20MB; PNG, JPEG, WebP or GIF; SVG is refused). Pass this or the ma |
| image_asset_key | string | no | Cut-out subject on transparency, as the asset_key of an earlier image result for this workspace (edit-projects/<tenant>/... or images/<tenant>/...). A key from another workspace is refused (SIMPLER_ME |
| kind | string | no | Shadow kind (default drop). |
| angle | integer | no | Light direction in degrees, counterclockwise from 3 o'clock (default 120). |
| distance | integer | no | Offset in pixels, 0..200 (default 12). |
| blur | integer | no | Edge softness in pixels, 0..100 (default 16). |
| opacity | integer | no | Shadow strength, 0..100 (default 50). |
| transparent | boolean | no | true (default) keeps the backdrop see-through; false fills background behind the shadow. |
| background | string | no | #RRGGBB backdrop used when transparent is false (default #ffffff). The word transparent is also accepted and means transparent true; it cannot be combined with transparent false. |
| request_ref | string | no | Optional idempotency key (1-64 chars: letters, digits, . _ : -). Retrying with the same request_ref and the same arguments within 24 hours returns the first result at $0 with replayed: true; the same |
| preview_format | string | no | Preview block after the JSON, at most 384px on the long edge and never charged: png, jpeg or none. Left out, a PNG result gets a png preview and a JPEG or WebP result a jpeg one. A result with no prev |
Apply 1..10 adjustments to a photo in order, with the editor's own kernels: a one-op stack returns the same pixels as that tool in the editor. ops is a list of {op, params}; each op takes only its own params keys, and a key left out takes that op's default: brightness_contrast (brightness, contrast), exposure (stops), temperature_tint (temperature, tint), vibrance_saturation (vibrance, saturation)
| Parameter | Type | Required | Notes |
|---|---|---|---|
| image_url | string | no | Photo to adjust: a public https URL, a data:image/...;base64 URL, or the url/url_path of an earlier image result (max 20MB; PNG, JPEG, WebP or GIF; SVG is refused). Pass this or the matching *_asset_k |
| image_asset_key | string | no | Photo to adjust, as the asset_key of an earlier image result for this workspace (edit-projects/<tenant>/... or images/<tenant>/...). A key from another workspace is refused (SIMPLER_MEDIA_FOREIGN_KEY) |
| ops | array | yes | Adjustments applied in order, 1..10. Each op takes only its own params keys: brightness_contrast (brightness, contrast), exposure (stops), temperature_tint (temperature, tint), vibrance_saturation (vi |
| output_format | string | no | Result encoding: png (the default, free), jpeg or webp ($0.0005, one Images encode at quality 85; a JPEG has no transparency, so transparent pixels come out white). |
| request_ref | string | no | Optional idempotency key (1-64 chars: letters, digits, . _ : -). Retrying with the same request_ref and the same arguments within 24 hours returns the first result at $0 with replayed: true; the same |
| preview_format | string | no | Preview block after the JSON, at most 384px on the long edge and never charged: png, jpeg or none. Left out, a PNG result gets a png preview and a JPEG or WebP result a jpeg one. A result with no prev |
[paid: $0.04] Apply a style to a photo while preserving the content (FLUX img2img, strength 0.55). Returns JSON {images:[{url, asset_key, download_url?, width, height}], price, next} plus a preview; images are stored in this workspace, never provider links, and a result with no download_url says why in download_url_unavailable. Refuses: SIMPLER_MEDIA_INPUT_MISSING (pass the url or the asset_key),
| Parameter | Type | Required | Notes |
|---|---|---|---|
| image_url | string | no | Source photo: a public https URL, a data:image/...;base64 URL, or the url/url_path of an earlier image result (max 20MB; PNG, JPEG, WebP or GIF; SVG is refused). Pass this or the matching *_asset_key, |
| image_asset_key | string | no | Source photo, as the asset_key of an earlier image result for this workspace (edit-projects/<tenant>/... or images/<tenant>/...). A key from another workspace is refused (SIMPLER_MEDIA_FOREIGN_KEY). |
| prompt | string | yes | Style descriptor. |
| request_ref | string | no | Optional idempotency key (1-64 chars: letters, digits, . _ : -). Retrying with the same request_ref and the same arguments within 24 hours returns the first result at $0 with replayed: true; the same |
| preview_format | string | no | Preview block after the JSON, at most 384px on the long edge and never charged: png, jpeg or none. Left out, a PNG result gets a png preview and a JPEG or WebP result a jpeg one. A result with no prev |
[paid: $0.01] Segment the object at pixel (x, y) via SAM 2 and return its mask image. Returns JSON {images:[{url, asset_key, download_url?, width, height}], price, next} plus a preview; images are stored in this workspace, never provider links, and a result with no download_url says why in download_url_unavailable. Refuses: SIMPLER_MEDIA_INPUT_MISSING (pass the url or the asset_key), SIMPLER_MEDIA
| Parameter | Type | Required | Notes |
|---|---|---|---|
| image_url | string | no | Source photo: a public https URL, a data:image/...;base64 URL, or the url/url_path of an earlier image result (max 20MB; PNG, JPEG, WebP or GIF; SVG is refused). Pass this or the matching *_asset_key, |
| image_asset_key | string | no | Source photo, as the asset_key of an earlier image result for this workspace (edit-projects/<tenant>/... or images/<tenant>/...). A key from another workspace is refused (SIMPLER_MEDIA_FOREIGN_KEY). |
| x | number | yes | Pixel X of a point on the object (0..16384). |
| y | number | yes | Pixel Y of a point on the object (0..16384). |
| request_ref | string | no | Optional idempotency key (1-64 chars: letters, digits, . _ : -). Retrying with the same request_ref and the same arguments within 24 hours returns the first result at $0 with replayed: true; the same |
| preview_format | string | no | Preview block after the JSON, at most 384px on the long edge and never charged: png, jpeg or none. Left out, a PNG result gets a png preview and a JPEG or WebP result a jpeg one. A result with no prev |
[paid: $0.04] Generate an image from a text prompt (google/nano-banana-2-lite) sized for editing. Returns JSON {images:[{url, asset_key, download_url?, width, height}], price, next} plus a preview; images are stored in this workspace, never provider links, and a result with no download_url says why in download_url_unavailable. Refuses: VALIDATION_ERROR on an empty prompt (describe the image), SIMP
| Parameter | Type | Required | Notes |
|---|---|---|---|
| prompt | string | yes | Full image description. |
| image_size | string | no | — |
| request_ref | string | no | Optional idempotency key (1-64 chars: letters, digits, . _ : -). Retrying with the same request_ref and the same arguments within 24 hours returns the first result at $0 with replayed: true; the same |
| preview_format | string | no | Preview block after the JSON, at most 384px on the long edge and never charged: png, jpeg or none. Left out, a PNG result gets a png preview and a JPEG or WebP result a jpeg one. A result with no prev |
Analyze a photo with vision (subjects, defects, OCR text, composition) and return a description. Token-billed at the platform's vision rates. Returns JSON {text, price, next}. Refuses: SIMPLER_MEDIA_INPUT_MISSING (pass the url or the asset_key), SIMPLER_MEDIA_FOREIGN_KEY (use this workspace's asset_key), SIMPLER_MEDIA_URL_REFUSED (use https, data:image or an asset_key), SIMPLER_MEDIA_PIN_TOO_LARGE
| Parameter | Type | Required | Notes |
|---|---|---|---|
| image_url | string | no | Photo to analyze: a public https URL, a data:image/...;base64 URL, or the url/url_path of an earlier image result (max 20MB; PNG, JPEG, WebP or GIF; SVG is refused). Pass this or the matching *_asset_ |
| image_asset_key | string | no | Photo to analyze, as the asset_key of an earlier image result for this workspace (edit-projects/<tenant>/... or images/<tenant>/...). A key from another workspace is refused (SIMPLER_MEDIA_FOREIGN_KEY |
| question | string | no | Optional focused question. |
| request_ref | string | no | Optional idempotency key (1-64 chars: letters, digits, . _ : -). Retrying with the same request_ref and the same arguments within 24 hours returns the first result at $0 with replayed: true; the same |
Check a product photo against a marketplace's listing-image rules before the seller uploads it: shopee, lazada or tiktok_shop. Free and read-only: the platform's own deterministic check, which stores nothing, calls no marketplace and uploads nothing. Returns JSON {images: [], price ($0.00), output: {verdict (pass, fail or partial), failed, advice, skipped, file: {width, height, format, bytes}, rul
| Parameter | Type | Required | Notes |
|---|---|---|---|
| image_url | string | no | Product photo to check: a public https URL, a data:image/...;base64 URL, or the url/url_path of an earlier image result (max 20MB; PNG, JPEG, WebP or GIF; SVG is refused). Pass this or the matching *_ |
| image_asset_key | string | no | Product photo to check, as the asset_key of an earlier image result for this workspace (edit-projects/<tenant>/... or images/<tenant>/...). A key from another workspace is refused (SIMPLER_MEDIA_FOREI |
| platform | string | yes | The marketplace whose listing-image rules to check: shopee, lazada or tiktok_shop. |
Start rendering a studio project to a file: a video, a GIF, the sound mix alone or one poster still (format). Returns job_id immediately; call video.export with job_id to follow progress and receive a download link valid for 24 hours. Refuses, naming the fix, when the project is not exportable, the preset's aspect differs from the project, or the tenant's active-job or daily limit is reached. form
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_...) to render. |
| preset | string | no | Encoder profile; default original (the project's own size and aspect). A preset whose aspect differs from the project is refused. |
| caption_mode | string | no | none (default), burned_in (drawn into the video), srt (a separate captions file), or both. |
| format | string | no | The output file; default mp4_h264_aac. mp4_h264_aac: H.264 video with AAC sound; plays everywhere and takes the platform presets. webm_vp9_opus: VP9 video with Opus sound; smaller files for the web, b |
| poster_time_ms | integer | no | Required with format "poster_jpg", refused with any other: the timeline millisecond to capture, from 0 to the timeline length minus 1. |
| composition_version | integer | no | Optional: the composition_version you reviewed (studio.get_composition). If a newer version is saved, the export is refused instead of rendering something you have not seen. |
Follow one video export to completion and return its download links. Start the export with video.export_create, then pass the job_id it returned (without job_id this follows the project's newest export). Polls the durable job row every 3s through queued -> processing -> uploading -> completed. On completion it returns download_path (for a session signed in to this workspace) and, when signed links
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_...) the export belongs to. |
| job_id | string | no | The export job (vx_...) video.export_create returned. Omit it to follow the project's newest export. |
Delete a finished video export's files (the mp4 and any SRT) now, before the automatic deletion 30 days after the export finished. Every download link for that job stops working at once; the job record stays, so the daily export limit still counts it. Refuses a job that is still rendering (SIMPLER_STUDIO_EXPORT_DELETE_ACTIVE): stop it with video.export_cancel, or follow it to the end with video.ex
| Parameter | Type | Required | Notes |
|---|---|---|---|
| job_id | string | yes | The export job (vx_...) whose files to delete. |
Stop a video export that is queued or rendering. The job ends as failed with "Cancelled by user.", anything it charged is refunded, the render stops, and any partial file is deleted. Cancelling a job that already finished or failed changes nothing (cancelled: false), so a repeat is safe. Refuses an unknown job (SIMPLER_STUDIO_EXPORT_JOB_NOT_FOUND): video.export_create returns job ids. Refuses a re
| Parameter | Type | Required | Notes |
|---|---|---|---|
| job_id | string | yes | The export job (vx_...) to stop. |
Start uploading a video, audio or image file (up to 2 GB) into a studio project. Returns upload_id and the plan: one PUT for a file up to 64 MB, else fixed 64 MB parts, each a PUT to this server with the same Bearer token this MCP connection uses and the part's exact Content-Length. The file's bytes are reserved against the workspace's 20 GB studio upload quota until the upload finishes or is canc
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_...) the file belongs to. |
| filename | string | yes | The file's name, shown in the project's media list. |
| bytes | integer | yes | The file's exact size in bytes. |
| mime | string | yes | The file's type. The stored bytes are checked when the upload finishes; a file that is not what it declares is deleted and refused. |
Finish an upload started with studio.begin_asset_upload once every part is PUT: the stored bytes are checked (the moov box is read wherever it sits), counted against the 20 GB quota, and added to the project's media. Returns {asset_id, media_type, probe}. Calling it again returns the same asset. Refuses: parts not yet sent (SIMPLER_STUDIO_UPLOAD_PARTS_MISSING lists them): PUT them, then finish aga
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_...) the upload belongs to. |
| upload_id | string | yes | The upload (vup_...) studio.begin_asset_upload returned. |
Copy a video, audio or image file from a public http(s) link into a studio project's media (up to 2 GB, within the 20 GB quota). Returns {asset_id, media_type, probe}, the same as studio.finish_asset_upload. The link is only downloaded; nothing is posted to it. Refuses: localhost, private, link-local or cloud-metadata addresses, or a redirect to one (SIMPLER_STUDIO_IMPORT_URL_REFUSED): give a publ
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_...) to add the file to. |
| url | string | yes | A public http(s) link that downloads the media file itself. |
List a studio project's stored versions, newest first: {version, created_at, label, current}, plus every named version (snapshots) and how many of the 20 names are used. A project keeps its newest 20 saved versions, one per 10 minutes for the last day, one per day for the last 30 days, and every named snapshot (up to 20); older unnamed versions are deleted. Refuses: a project_id outside your scope
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_...) whose history to use. |
| limit | integer | no | How many of the newest versions to return (default 20). Named versions are always all listed under snapshots. |
Bring back an earlier version of a studio project: it saves that version as a new version; history is never rewritten, so the version it replaces stays listed and restoring that one undoes this. Returns {version, restored_from, previous_version}. A person editing the project in the browser is told at their next save that a newer version is on the server and reloads. Refuses: a project_id outside y
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_...) whose history to use. |
| version | integer | yes | A version number studio.list_versions lists. |
Name a studio project's version (the current one unless version is given) so it is never deleted by retention; naming a named version renames it. At most 20 named versions per project. Adds no new version, so an editor open on the project keeps saving. Refuses: a project_id outside your scope (NOT_FOUND): studio_project_list lists your projects; pass one of their ids; a label that is empty, over 8
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_...) whose history to use. |
| label | string | yes | The version's name, one line, for example "Approved by client". |
| version | integer | no | The version to name; the current version when left out. |
Remove the name from a studio project's named version, freeing one of its 20 names. The version stays stored; from the next save it follows the normal retention and may be deleted. A version without a name answers removed: false. Refuses: a project_id outside your scope (NOT_FOUND): studio_project_list lists your projects; pass one of their ids; a version the project no longer stores (SIMPLER_STUD
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_...) whose history to use. |
| version | integer | yes | A version number studio.list_versions lists. |
Read the current composition: scenes in order (with derived start times and generation status; length_estimated: true marks a scene sized by an estimate because its video file reported no length), tracks (id, role, name, locked, muted) and clips, overlays, caption count, total duration, and the assets (the ids every asset_id argument takes). Call when you need fresh truth after edits.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
Read the caption rows in time order with the ids edit_caption, move_caption and cut_transcript_span take. Each row gives id, type (speech, filler, silence or manual), source (transcription or manual), start_ms, end_ms, speaker when the transcription labelled one, hidden: true for a row remove_fillers hid, text, and words. words lists a transcribed row's words in order, so a word's index is its pos
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| from_row | integer | no | 0-based row to start reading from; 0 when left out. |
Add a PLANNED scene (storyboard placeholder) to the primary lane — free; no pixels are generated. The prompt is the scene's recipe. NEVER mention camera equipment (crane, dolly, rig) — describe what to SHOW. Say 'camera rises' NOT 'crane shot'. Include: subject, action, lighting, color palette, mood.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| prompt | string | yes | Detailed visual description for the scene. |
| duration_seconds | number | no | Scene duration in seconds (1-30). |
| position | number | no | 0-based index in scene order; appends when omitted. |
Append an uploaded video or image asset to the main track as a finished scene, or insert it at at_index. Assets longer than 10 minutes become consecutive scenes. A video with no measured length lands as one untrimmed 5s scene marked length_estimated: true, here and in get_composition, until the file is measured in the studio editor. Audio assets are refused; use add_audio_to_timeline.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| asset_id | string | yes | A video or image asset id (vas_...) from get_composition's assets list. |
| at_index | integer | no | 0-based position in scene order; appends when omitted. |
Delete several scenes, timeline clips, stickers and captions in one edit: pass 1 to 200 ids in element_ids. All or nothing: an unknown id, a clip on a locked track, or a locked track a scene's cut would move refuses the whole call, names the first offender, and deletes nothing (unlock it with lock_track, or pass ripple_secondary "none"). Scenes follow ripple_secondary as in delete_element: "shift"
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| element_ids | array | yes | Scene (vs_), clip (vcl_), sticker (vov_) or caption (vc_) ids; duplicates count once. |
| ripple_secondary | string | no | For deleted scenes: "shift" (default) removes their time from every lane; "none" closes the main track alone. Clips, stickers and captions ignore it. |
Move 1 to 200 timeline clips by the same delta_ms (negative moves earlier), keeping their spacing and their tracks. All or nothing: an unknown clip id, a clip on a locked track, a clip pushed before 0 or past the timeline cap, or a landing that overlaps a clip you did not list refuses the whole call, names the first offending clip, and moves nothing; an overlap refusal gives the nearest delta_ms t
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| clip_ids | array | yes | Timeline clip ids (vcl_) from get_composition's tracks; duplicates count once. |
| delta_ms | integer | yes | Milliseconds to move every listed clip; negative moves them earlier. |
Copy 1 to 200 timeline clips so the earliest copy starts at at_ms and the others keep their offsets from it, each copy on its original's track. All or nothing: an unknown clip id, a clip on a locked track, copies that would run past the timeline cap, a track that would pass its clip cap, or a copy that overlaps any existing clip (the originals included) refuses the whole call, names the first offe
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| clip_ids | array | yes | Timeline clip ids (vcl_) to copy; duplicates count once. |
| at_ms | integer | yes | Timeline millisecond where the earliest copy starts. |
Open length_ms of empty time at at_ms on every lane, so everything at or after at_ms moves later together. The main track receives a placeholder scene there (a pending scene with the prompt "Gap"; fill it with update_scene and generate_scene, or add footage). A scene or voice clip at_ms lands inside is split around the new time; text, stills, captions and stickers that span it stretch. Refuses, na
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| at_ms | integer | yes | Timeline millisecond where the new time opens, from 0 to the main track's end. |
| length_ms | integer | yes | How much time to insert, 100 to 600000ms (one placeholder scene). |
Delete a scene or timeline clip AND close the time it held. scope "all_tracks" (the default) removes that span of time from every lane, so everything after it moves earlier together and stays in sync; clips and captions over the span go with it, and one that crosses its edge is split or shortened. scope "own_track" closes the gap on the element's own lane only (for a scene, the other tracks then d
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| element_id | string | yes | A scene (vs_) or timeline clip (vcl_) id from get_composition. |
| scope | string | no | "all_tracks" (default) closes the time on every lane; "own_track" closes it on the element's own lane only. |
Move the cut between two neighbours by delta_ms (positive moves it later): left_id's end and right_id's start move together, and their footage in/out points follow. The pair's total length and every other element stay where they are. The neighbours are a scene and the next scene, or two touching clips on one track, left one first. Refuses, naming the fix: an unknown id, ids that do not share a cut
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| left_id | string | yes | The scene or clip before the cut. |
| right_id | string | yes | The scene or clip right after the cut. |
| delta_ms | integer | yes | Milliseconds to move the cut; negative moves it earlier. |
Show a different part of a clip's or scene's footage without moving it: its in and out points move by delta_ms of timeline (positive shows later footage), while its position and length stay. Works on video and audio clips and on scenes with finished video. Refuses, naming the fix: an unknown id, text or a still image or a scene with no footage yet (only video and audio can slip), a locked track, o
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| clip_id | string | yes | A video or audio clip (vcl_) or a scene (vs_) with finished video. |
| delta_ms | integer | yes | Milliseconds to move the footage window; positive shows later footage. |
Move a video or audio clip by delta_ms between its neighbours on its track: the clip touching its start gets longer or shorter at its end, the clip touching its end at its start, so the three-clip span and every other track stay put. A side with a gap instead lets the clip move into the gap and no further. Refuses, naming the fix: an unknown id, a scene (scenes reorder with reorder_scenes), text o
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| clip_id | string | yes | A video or audio clip (vcl_) on a secondary track. |
| delta_ms | integer | yes | Milliseconds to move the clip; negative moves it earlier. |
Move ONE whole caption row along the timeline by delta_ms (negative moves it earlier): its start, its end and every word timing move together, so the words keep their spacing. Pick the row by caption_id, or by at_ms: the visible caption showing at that timeline millisecond (hidden rows are skipped). The row stops at 0, at the timeline cap and at the visible caption on either side, so a move never
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| caption_id | string | no | The caption row (vc_) to move. Leave it out and pass at_ms instead to pick the row showing then. |
| at_ms | integer | no | A timeline millisecond inside the visible caption to move; used when caption_id is left out. |
| delta_ms | integer | yes | Milliseconds to move the whole row; negative moves it earlier. |
Cut the words of a transcript span out of the whole video, the way deleting text in a transcript editor does. The span runs from from_caption_id to to_caption_id (row ids from get_transcript) and takes both rows whole; from_word_index and to_word_index narrow it to a word inside the from row and the to row (0-based, in the order get_transcript lists a row's words). The span's time comes out of eve
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| from_caption_id | string | yes | The caption row (vc_) the span starts in. |
| to_caption_id | string | yes | The caption row (vc_) the span ends in; the same id as from_caption_id for a span inside one row. |
| from_word_index | integer | no | 0-based index of the first word to cut in the from row; the row's start when left out. |
| to_word_index | integer | no | 0-based index of the last word to cut in the to row; the row's end when left out. |
Add an empty track of a role (video-broll, text, audio-music or audio-voice), up to 16 tracks in the project. The new track lands on top of its role: a video-broll or text track draws over the ones before it (picture-in-picture, a second title layer), an audio track mixes in beside the others. Place clips on it by passing the returned track_id to add_clip_to_timeline, add_audio_to_timeline or add_
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| role | string | yes | The kind of track: video-broll, text, audio-music or audio-voice. |
| name | string | no | A display name up to 40 characters; the role's label shows when left out. |
Remove one track by track_id. A track that still holds clips is refused unless delete_clips is true, which removes its clips with it. Refuses, naming the fix: an unknown track_id, a locked track, a track with clips and no delete_clips, or the last track of its role (every project keeps one of each).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| track_id | string | yes | The track (vtr_) from get_composition's tracks. |
| delete_clips | boolean | no | true removes the track's clips with it; left out, a track with clips is refused. |
Move a track to position within its own role. Position 0 is the lowest: its pictures draw first, so every later video-broll or text track draws over it. Tracks of other roles keep their order; text always draws over video. Locked tracks may be reordered. Refuses an unknown track_id or a position past the role's last track, naming the fix.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| track_id | string | yes | The track (vtr_) from get_composition's tracks. |
| position | integer | yes | 0-based position among the tracks of the same role; 0 draws lowest. |
Give a track a display name up to 40 characters, or pass an empty name to go back to the role's label. Names are for people and never address a track: tools take track_id. Locked tracks may be renamed. Refuses an unknown track_id, naming the fix.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| track_id | string | yes | The track (vtr_) from get_composition's tracks. |
| name | string | yes | The new name; an empty string clears it. |
Mute or unmute a whole track. A muted audio track plays nothing and a muted voice track stops ducking the music; a muted video-broll track keeps its pictures and drops its clips' own sound. The preview and the export both honor it, and each clip keeps its own muted and volume. Locked tracks may be muted. Refuses an unknown track_id or a text track, naming the fix.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| track_id | string | yes | The track (vtr_) from get_composition's tracks. |
| muted | boolean | yes | true silences the track; false plays it again. |
Move 1 to 200 timeline clips onto another track of the same kind (a b-roll clip to a video-broll track, a title to a text track, music to an audio-music track, a voice clip to an audio-voice track), keeping their spacing; delta_ms also moves them in time (default 0). Stacking follows the track: get_composition lists tracks in stacking order, and a clip on a later video-broll or text track draws ov
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| clip_ids | array | yes | Timeline clip ids (vcl_) from get_composition's tracks; duplicates count once. |
| track_id | string | yes | The target track (vtr_) from get_composition's tracks, of the same role as every listed clip's track. |
| delta_ms | integer | no | Milliseconds to move the clips in time as they change track; negative moves them earlier. 0 when left out. |
Place a product card: a price_tag text clip showing a stock item's name and price, built from values you already hold. studio.insert_product_card reads them from the stock record for you; use this op inside studio.apply_ops or when the values come from elsewhere. The price prints as the currency code and the amount with two decimals (SGD 12.90), never a symbol. style: tag (name over price, lower l
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| stock_item_id | string | yes | The stock item's id from stock_item_list; kept on the card so it can be refreshed from the record. |
| product_name | string | yes | The item's name as the stock record holds it. |
| sell_price_cents | integer | yes | The selling price in cents (1290 prints as 12.90). |
| currency | string | yes | The ISO code the price prints with; the business's sales_settings default_currency. |
| start_ms | integer | no | Timeline millisecond where the card appears; 0 when left out. |
| duration_ms | integer | no | How long the card shows, in milliseconds; 4000 when left out. |
| style | string | no | The card's layout; tag when left out. |
| track_id | string | no | A text track (vtr_) from get_composition; the first text track when left out. |
Update a scene's prompt or duration. EDIT-INVALIDATES-ASSET: changing the prompt of a generated scene resets it to pending and drops its footage (a stale render cannot survive a prompt edit) — say so before doing it. With ripple_secondary "shift" (the default) the other lanes follow the footage: time the scene loses at its start or end is cut from every lane at that edge, and time it gains is inse
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| scene_id | string | yes | — |
| prompt | string | no | New prompt (optional). |
| duration_seconds | number | no | New duration in seconds (optional). |
| ripple_secondary | string | no | "shift" (default) keeps clips, captions and stickers in sync with the scenes; "none" edits the main track alone. |
[$0.10/sec at provider cost] Generate video for a scene from its prompt (text-to-video). Pass scene_id to fill a planned scene, or prompt to create-and-generate in one step. NEVER mention camera equipment (crane, dolly, rig) — describe what to SHOW. Say 'camera rises' NOT 'crane shot'. Include: subject, action, lighting, color palette, mood.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| scene_id | string | no | Planned scene to generate (optional). |
| prompt | string | no | Visual description; required when scene_id is omitted. |
| duration_seconds | number | no | Whole seconds (3-10). |
| style | string | no | Visual style: cinematic, corporate, playful, dramatic |
[$0.05/track at provider cost] Generate a background music track from a mood/style description. Returns an audio asset id — place it with add_audio_to_timeline.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| mood | string | yes | Mood/style: uplifting, dramatic, corporate, chill, energetic — or free text. |
| duration_seconds | number | yes | Track length in seconds. |
Generate narration audio from a script. voice_tier is the REAL choice the user makes: 'standard' ($0.015/1K chars at provider cost) vs 'premium' ($0.15/1K chars at provider cost) — quote both prices when proposing; never pick silently. Returns an audio asset id.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| script | string | yes | The narration text (max 5000 chars). |
| voice_tier | string | yes | REQUIRED — the user's explicit price-visible choice. |
| voice | string | no | Provider voice id/name (optional). |
Place an existing video/image asset on a b-roll track at a position: the first b-roll track, or the one track_id names (a later b-roll track draws over an earlier one, for picture-in-picture). Overlap on that track is refused with the conflicting range so you can re-place or stack it on another track.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| asset_id | string | yes | — |
| start_time_ms | number | yes | — |
| duration_ms | number | no | Defaults to the asset's duration. |
| track_id | string | no | A video-broll track (vtr_) from get_composition; defaults to the first one. |
Place an audio asset on a role track: 'audio-music' (background, default volume 0.3 — voice ducks music by role) or 'audio-voice' (narration, volume 1.0). It lands on the role's first track, or on the one track_id names (a second music bed, a second voice).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| asset_id | string | yes | — |
| track | string | no | — |
| start_time_ms | number | no | — |
| volume | number | no | 0-2; defaults 0.3 for music, 1.0 for voice. |
| track_id | string | no | An audio track (vtr_) from get_composition; its role wins when track is left out. Defaults to the role's first track. |
Add a text clip to the first text track, or to the one track_id names (a later text track draws over an earlier one). Pick a semantic preset (title/subtitle/lower_third/callout/price_tag) — it carries complete opinionated styling; override only what matters. Keep text SHORT (max 5-7 words).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| content | string | yes | The text (max 500 chars; aim for 5-7 words). |
| preset | string | no | — |
| start_time_ms | number | no | — |
| duration_ms | number | no | Visible time; keep text readable (3-5s minimum). |
| position | object | no | Normalized 0-1; 0.5,0.5 is center. |
| animation | string | no | — |
| track_id | string | no | A text track (vtr_) from get_composition; defaults to the first one. |
Update an existing text clip: content, position, timing.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| clip_id | string | yes | Text clip id (from get_composition). |
| content | string | no | — |
| position | object | no | — |
| start_time_ms | number | no | — |
| duration_ms | number | no | — |
Add a sticker/element overlay (creator CTAs, emojis, shapes) at a normalized position with its own time range and animation.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| sticker | string | yes | Catalog key (e.g. subscribe, sale, live) or emoji name. |
| emoji | string | no | Emoji glyph when the sticker is an emoji. |
| x | number | yes | 0-1 |
| y | number | yes | 0-1 |
| start_time_ms | number | no | — |
| duration_ms | number | no | — |
| animation | string | no | — |
Set a scene's transition (in = how it enters, out = how it leaves). Dissolve creates connection (500-800ms); fade for scene breaks; cut clears the transition.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| scene_id | string | yes | — |
| direction | string | no | — |
| type | string | yes | — |
| duration_ms | number | no | — |
Trim a generated scene's footage: cut milliseconds off its start and/or end. With ripple_secondary "shift" (the default) the other lanes follow the footage: time the scene loses at its start or end is cut from every lane at that edge, and time it gains is inserted there, so clips, captions and stickers stay over the frames they were placed on (one that spans that edge is split or stretched). "none
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| scene_id | string | yes | — |
| trim_start_ms | number | no | Milliseconds to cut from the start. |
| trim_end_ms | number | no | Milliseconds to cut from the end. |
| ripple_secondary | string | no | "shift" (default) keeps clips, captions and stickers in sync with the scenes; "none" edits the main track alone. |
Apply color grading to a scene (each channel -100..100; temperature negative = cool, positive = warm).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| scene_id | string | yes | — |
| brightness | number | no | — |
| contrast | number | no | — |
| saturation | number | no | — |
| temperature | number | no | — |
Adjust an audio role's mix: set every clip's volume on every track of that role (or only on the track track_id names) and/or toggle ducking (voice ducks music BY ROLE — no track ids needed).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| track | string | yes | — |
| volume | number | no | 0-2 linear volume for every clip on the track. |
| track_id | string | no | One audio track (vtr_) of that role from get_composition; left out, every track of the role. |
| apply_ducking | boolean | no | Enable/disable voice-over-music ducking. |
Move a clip or adjust its volume/mute on any secondary track.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| clip_id | string | yes | — |
| start_time_ms | number | no | — |
| volume | number | no | — |
| muted | boolean | no | — |
Delete a scene, clip, or sticker by id (captions soft-delete reversibly). Deleting a scene with ripple_secondary "shift" (the default) removes its span of time from every lane, so clips, captions and stickers over the scene go with it and everything after it moves earlier in sync; "none" closes the main track alone. A deleted clip still leaves its gap open whatever ripple_secondary says; ripple_de
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| element_id | string | yes | — |
| ripple_secondary | string | no | "shift" (default) keeps clips, captions and stickers in sync with the scenes; "none" edits the main track alone. |
Delete every '[silence]' row from the TRANSCRIPT. This cleans up the caption text only - the footage keeps its full length and the pauses still play. To cut the pauses out of the video for real, use remove_dead_air. Silence rows are derived markers, not content, so this is a HARD delete and is not undoable - re-run transcription to get them back.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
Hide filler words (um, uh, you know, kind of) from the transcript. REVERSIBLE: rows are soft-deleted, excluded from burn-in and SRT, and restore_fillers brings them back. Read the composition afterwards if you need to see which rows went.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
Un-hide transcript rows that were soft-deleted. Scope is EVERY hidden row, not only filler words - a caption hidden by delete_element comes back too. There is no per-row restore.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
Cut a scene or a timeline clip in two at a timeline millisecond. The left half keeps the id; the right half is new and is returned. Both halves must keep at least 100ms of footage or the split refuses. Transitions stay on the outer edges - the new seam is a hard cut.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| target_id | string | yes | A scene id or a timeline clip id. |
| at_ms | number | yes | TIMELINE position of the cut, not an offset into the element. |
Replace the transcript with fresh rows from your own transcription. Rows the operator hand-edited (source 'manual') SURVIVE - only machine-transcribed rows are replaced, so a re-transcribe never silently discards someone's correction. Rows are re-sorted by start time.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| captions | array | yes | The new transcript, in any order. |
Set project output settings: aspect ratio, resolution, frame rate, background colour, caption style. Every field is optional - only what you pass changes. Changing aspect does NOT re-crop existing footage (it letterboxes); reframe the scenes if you need the framing to follow.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| aspect | string | no | — |
| resolution | string | no | — |
| fps | integer | no | Frame rate - 24, 25, 30 or 60 only. |
| background_color | string | no | Hex #RRGGBB - what shows in letterbox bars. |
| caption_preset | string | no | — |
Move a scene to a different position in the primary lane. Positions are 0-based, so to_index 0 makes it the opening scene. Scene start times are DERIVED from order, so every scene after the move shifts in time. With ripple_secondary "shift" (the default) every clip, caption and sticker that sits wholly inside a scene moves with that scene; one that spans a scene edge stays put and is listed in str
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| scene_id | string | yes | — |
| to_index | integer | yes | 0-based destination position. |
| ripple_secondary | string | no | "shift" (default) keeps clips, captions and stickers in sync with the scenes; "none" edits the main track alone. |
Trim a timeline clip's start or end edge to an absolute TIMELINE millisecond. The clip keeps its id and its source in/out points move with the edge, so the footage stays in sync. Refuses if the trim would leave under 100ms, cross a neighbouring clip, or run past the source media.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| clip_id | string | yes | — |
| edge | string | yes | — |
| at_ms | integer | yes | Absolute TIMELINE position for the new edge, not an offset. |
Copy a timeline clip and place the copy immediately after the original on the same track. Refuses if there is no room after it. Returns the new clip id.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| clip_id | string | yes | — |
Lock or unlock a track. A locked track refuses every edit - move, trim, split, duplicate, delete - until it is unlocked. Lock a finished voiceover before restructuring the picture so the timing cannot drift underneath it. track names the role and locks every track of it; add track_id to lock only that one.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| track | string | yes | — |
| locked | boolean | yes | — |
| track_id | string | no | One track (vtr_) of that role from get_composition; left out, every track of the role. |
Edit ONE transcript row: its text, its start, its end, or any combination. Times are timeline milliseconds. Editing the TEXT marks the row hand-edited, so a later replace_transcribed will not overwrite it - which is exactly how you correct a name the recognizer got wrong.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| caption_id | string | yes | — |
| text | string | no | — |
| start_ms | integer | no | — |
| end_ms | integer | no | — |
Move, resize, rotate, fade or re-time a sticker overlay. Only the fields you pass change. Positions are normalized 0-1 of the frame.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| overlay_id | string | yes | — |
| x | number | no | 0-1 |
| y | number | no | 0-1 |
| scale | number | no | 0.1-10, 1 is native size. |
| rotation_deg | number | no | -360 to 360. |
| opacity | number | no | 0-1. |
| start_time_ms | integer | no | — |
| duration_ms | integer | no | — |
| animation | string | no | — |
Cut a span of TIME out of the whole video. Everything after it moves earlier by the same amount, on every lane at once - scenes, clips, captions and stickers stay in sync. A scene or voice clip the cut lands inside is SPLIT, so the material after the cut still plays. A scene piece the cut would leave under 100ms merges into the scene beside it; when no scene beside it has the footage, the cut wide
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| start_ms | number | yes | Where the cut starts, in ms on the timeline. |
| end_ms | number | yes | Where the cut ends, in ms on the timeline. |
Cut every silent pause the transcript found OUT OF THE FOOTAGE, keeping a little breathing room at each one. This is the real edit, not a transcript cleanup: the video gets shorter. Needs a transcript first (transcribe). Not undoable.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| min_silence_ms | number | no | Only cut pauses at least this long. Below ~400ms you are cutting natural speech rhythm. |
| keep_ms | number | no | Breathing room left at the end of each pause. 0 makes speech run together. |
[$0.0043/min at provider cost] Transcribe an audio or video asset into word-timed captions. REPLACES every previously transcribed caption on this project; captions you wrote by hand survive. Speaker labels are asked for: a row carries speaker (Speaker 1, Speaker 2, ...) only when the recognizer labelled its words, and the reply's speaker_count is 0 when it labelled none. Read the rows with get_tra
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| asset_id | string | yes | Asset to transcribe (audio or video) - read the ids from get_composition. |
| language | string | no | Language hint such as 'en' or 'ms'. Omit to auto-detect. |
Re-frame one scene for a different aspect ratio. method 'analytic' re-centers and scales the EXISTING footage on a focus point (cheap, no new pixels, needs the source dimensions); method 'generative' outpaints new edges [$0.10/sec at provider cost].
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| scene_id | string | yes | Scene to re-frame. |
| target_aspect | string | yes | Aspect to frame for. |
| method | string | no | analytic = crop/scale existing footage; generative = outpaint new edges. |
| focus_x | number | no | Focus point across the frame, 0-1 (analytic only). |
| focus_y | number | no | Focus point down the frame, 0-1 (analytic only). |
| prompt | string | no | What the new edges should contain (generative only). |
[$0.04/sec at provider cost] Restyle a scene's footage, keeping its motion. style must be one of the presets (anime, comic, watercolor, oil_painting, sketch, cinematic, vintage, neon). A free-text style is refused, because free text over the user's footage could change who appears in it; pick the closest preset instead. Mints a NEW asset - the original is never destroyed.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| scene_id | string | yes | Scene whose footage to restyle. |
| style | string | yes | A preset key: anime, comic, watercolor, oil_painting, sketch, cinematic, vintage, neon. Free text is refused. |
[$0.001/sec at provider cost] Generate sound effects and ambience FOR a scene from its own footage (foley). Different from generate_music: this is the sound the shot itself would make.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| scene_id | string | yes | Scene to add sound to. |
| prompt | string | no | What it should sound like ('sizzling wok, street chatter'). Omit for natural ambience. |
Clean up an audio clip on the timeline: noise removal, voice shaping, loudness normalization. FREE (platform compute, no provider). Mints an enhanced asset beside the original - the original is never destroyed.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| clip_id | string | yes | Audio clip on the timeline to enhance. |
| noise | boolean | no | Remove background noise. |
| voice | boolean | no | Shape for speech (high-pass, compress, de-ess). |
| normalize | boolean | no | Normalize loudness to broadcast level. |
Append a stored choreography - its scenes (as PENDING prompts, nothing generated yet) plus its text timing - onto this composition. FREE. Templates: tpl_product_showcase (Perfect for product demos and commercials); tpl_social_clip (Vertical format perfect for TikTok, Reels, and Shorts); tpl_explainer (Classic explainer video structure); tpl_testimonial (Square format ideal for customer testimonial
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| template_id | string | yes | Which choreography to apply. |
Configure the voice-over-music ducking mix intent (by role; the renderer honors it).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| enabled | boolean | yes | — |
| duck_level | number | no | Music level under voice, 0-1 (default 0.3). |
Look at a generated scene's actual frames (vision) and describe subject, lighting, composition, mood. Make editing decisions based on what you SEE, not assumptions. Refuses with SIMPLER_STUDIO_VISION_NONE while no model on this platform can look at video frames (nothing is sent or spent): judge the scene from its prompt and the composition instead.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| scene_id | string | yes | — |
| focus | string | no | composition, lighting, mood, pacing, all |
Flag a generated scene that does not match intent: record WHY and an improved prompt. This stages the improved prompt on the scene (regeneration is a separate paid, user-approved step — it never silently destroys footage or spends).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this tool acts on. |
| scene_id | string | yes | — |
| reason | string | yes | Why it needs regeneration. |
| improved_prompt | string | yes | The improved prompt. |
Apply several edits atomically against base_version; any refusal applies nothing and names the failing op. Small models: prefer the single-purpose verbs. Each op is {op, args}; the ops and their args are: add_scene_from_asset {asset_id, at_index?}; delete_elements {element_ids, ripple_secondary?}; shift_clips {clip_ids, delta_ms}; duplicate_clips {clip_ids, at_ms}; insert_time {at_ms, length_ms};
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_…) this batch edits. |
| base_version | integer | yes | The composition_version your ops were planned against (0 for a project with no saved composition). |
| ops | array | yes | The edits, applied in order; all land or none do. |
Find the best short-form moments in a long studio video and return them as ranges with a title, a hook line, a one-sentence rationale and measured evidence (captioned words, words per second, whether it starts on a scene cut). It creates and changes nothing. To make a suggestion into a project, call studio.create_social_clip with its start_ms and end_ms; then render that project with video.export_
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_...) holding the long video. studio_project_list shows your projects. |
| asset_id | string | no | Optional: suggest only from the scenes cut from this video asset (vas_...). studio.get_composition lists the assets; the asset must already be on the timeline (studio.add_scene_from_asset places it). |
| count | integer | no | How many suggestions to return, 1 to 10 (default 3). Fewer can come back when the video has fewer distinct moments. |
| target_preset | string | no | The export preset the shorts are for (default shorts_9x16). It sets the shape and the longest allowed length; pass the same preset to studio.create_social_clip and video.export_create. |
| focus | string | no | Optional: what to look for, such as 'the product demo'. It only ranks moments; it is never treated as an instruction. |
Make one short as a NEW studio project from a range of an existing project: the finished scenes in the range are trimmed copies (no footage is generated or billed again), the captions move with them and the new project takes the target preset's shape. The source project is not changed. Free. Use the start_ms, end_ms and composition_version from studio.suggest_social_clips. Calling again within 24
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The source studio project (vp_...) the suggestion came from. |
| start_ms | integer | yes | Where the short starts on the source timeline, in milliseconds (a suggestion's start_ms). |
| end_ms | integer | yes | Where the short ends on the source timeline, in milliseconds (a suggestion's end_ms). |
| target_preset | string | no | The export preset the short is for (default shorts_9x16); the new project takes its shape. |
| title | string | no | Optional name for the new project (a suggestion's title). |
| composition_version | integer | no | The source composition_version the range was chosen on (the suggest result carries it). When the source has changed since, nothing is created and the answer names the current version. |
Put a stock item's name and selling price on the video as a product card: a price_tag text clip on the first text track (or the one track_id names), from start_ms for duration_ms. It reads the stock record as you, so the card shows what stock_item_read shows; the values are copied into the project, and later stock edits do not change a card already placed. The price prints with the currency code (
| Parameter | Type | Required | Notes |
|---|---|---|---|
| project_id | string | yes | The studio project (vp_...) the card goes into. |
| stock_item_id | string | yes | The stock item to show, from stock_item_list; its name and sell_price_cents are copied onto the card. |
| start_ms | integer | yes | Timeline millisecond where the card appears. |
| duration_ms | integer | no | How long the card shows, in milliseconds; 4000 when left out. |
| style | string | no | The card's layout; tag when left out. |
| currency | string | no | The ISO code the price prints with; the business's sales_settings default_currency when left out. |
| track_id | string | no | A text track (vtr_) from studio.get_composition; the first text track when left out. |
File a missing-capability report when no available tool can accomplish your task. The platform operator reviews these to decide what gets built next. Free; capped at 10 reports per tenant per day. Refuses: VALIDATION_ERROR when intent is under 10 characters (describe the task in a sentence), RATE_LIMITED after 10 reports in 24 hours (wait the retry_after seconds it carries).
| Parameter | Type | Required | Notes |
|---|---|---|---|
| intent | string | yes | What you were trying to accomplish (plain language). |
| attempted_tools | string | no | Tools you tried, comma-separated. |
| why_insufficient | string | no | Why the existing tools fell short. |
| proposed_shape | string | no | Optional: the tool shape that would have worked. |
- Every tool — any call limit is its publisher’s, not ours
- No card, and mcprush charges nothing for it
- Runs at its publisher’s own address — this marketplace is not in the path
- Nothing to cap, because mcprush bills nothing
What counts against your monthly calls
| Tool | Unit | Calls used | Out of the allowance |
|---|
Nothing here is billable: mcprush charges nothing to install Simpler.Asia or to call it, at any volume.
Two independent axes, because powerful and malicious are different questions. The grade is threat only. The capability level is blast radius, and it is never a penalty on the grade — it is priced as one subtract-only term in the score, where you can see it.
This listing is an address its publisher runs, and you connect to it directly — this marketplace is not in the path. The scanner reads packages and public source, and an address is neither. So there is no grade — not a withheld one, an unmeasured one.
Release history
This is an address its publisher runs: which release it serves is theirs to choose, so there is nothing here to pin. The history below is for reading; the current release on file is 1.0.0.
No release note was published with this version.
One review per account, from a signed-in account that does not publish this listing. Nothing else is asked — you can say what you think before you install it. Publishers can reply once per review, and a review can be edited or deleted by whoever wrote it.
Any signed-in account that does not publish Simpler.Asia can review it, once — before installing it or after. A review from an account that has installed it is marked as one.
Nobody has reviewed this listing. The rating on the card is the mean of the reviews written here and nothing else, so there is no rating until somebody writes the first — which takes a signed-in account that does not publish it, and nothing else.