Skip to main content

TinyFish Agent

Pass-through endpoints for the TinyFish Agent API, goal-based web automation in native format (no translation). Point the official TinyFish SDK at the proxy and it works unchanged

FeatureSupportedNotes
Cost Tracking✅COMPLETED runs billed as num_of_steps x $0.016 (TinyFish's published rate)
Logging✅Runs logged as model tinyfish/automation-run
End-user Tracking❌Tell us if you need this
Streaming✅run-sse progress events relayed live

Just replace https://agent.tinyfish.ai with LITELLM_PROXY_BASE_URL/tinyfish 🚀

Supported endpoints:

EndpointMethodDescription
/v1/automation/runPOSTRun an automation to completion (blocking)
/v1/automation/run-asyncPOSTSubmit a run, poll for the result
/v1/automation/run-ssePOSTRun with live SSE progress events
/v1/runs/{id}GETRun status and result
/v1/runs/{id}/cancelPOSTCancel a run

Every other Agent API endpoint (vault, wallet, browser profiles) returns 403. All callers share the proxy's one upstream TinyFish key, so the credential and account management surface stays admin-only. The GET /v1/runs listing is also blocked: run ids are unguessable, so withholding the list keeps callers behind the shared key from discovering each other's runs

Quick Start​

1. Add your TinyFish API key to the proxy​

Set the TINYFISH_API_KEY environment variable on the proxy, or add a deployment with use_in_pass_through: true

export TINYFISH_API_KEY="your-tinyfish-api-key"

2. Run an automation​

curl http://localhost:4000/tinyfish/v1/automation/run \
-H "X-API-Key: $LITELLM_VIRTUAL_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://scrapeme.live/shop",
"goal": "Extract the first 2 product names and prices. Return JSON."
}'

Expected response:

{
"run_id": "1e7d076e-c464-4f13-8edf-817e9cd78a8b",
"status": "COMPLETED",
"started_at": "2026-09-14T17:59:19.562Z",
"finished_at": "2026-09-14T18:00:20.438Z",
"num_of_steps": 2,
"result": {"result": [{"name": "Bulbasaur", "price": "£63.00"}, {"name": "Ivysaur", "price": "£87.00"}]},
"error": null
}

3. Or use the official TinyFish SDK​

The SDK accepts a base_url with the /tinyfish prefix and sends the virtual key on the X-API-Key header, which LiteLLM accepts natively

from tinyfish import TinyFish

client = TinyFish(
base_url="http://localhost:4000/tinyfish",
api_key="sk-your-litellm-virtual-key",
)
run = client.agent.run(
url="https://scrapeme.live/shop",
goal="Extract the first 2 product names and prices. Return JSON.",
)
print(run.status, run.num_of_steps, run.result)

4. View logs​

Navigate to Logs in the sidebar and filter by tinyfish. Each run shows model tinyfish/automation-run, the calling key, and the spend

Spend tracking​

Runs are billed num_of_steps x $0.016 to the calling key and team:

  • POST /v1/automation/run bills when the blocking response returns
  • POST /v1/automation/run-async bills exactly once: LiteLLM polls the run in the background and writes one spend log when it reaches a terminal status. Client polls of GET /v1/runs/{id} are never billed, no matter how many
  • POST /v1/automation/run-sse bills exactly once when the run reaches a terminal status, the same way: a client that disconnects mid-stream is still billed once the run completes
  • Only COMPLETED runs carry cost. FAILED and CANCELLED runs write a $0 spend log, matching how TinyFish invoices
  • GET /v1/runs/{id} and cancels never write spend logs

Override the per-step rate with the TINYFISH_COST_PER_STEP environment variable if your TinyFish contract prices steps differently

One operational caveat: run-async and SSE billing runs in an in-memory background poller. It survives client disconnects, but a proxy restart while such a run is in flight loses that run's spend log (the run itself completes upstream unaffected)

Authenticated runs​

Request fields that run with the TinyFish account's saved logins (use_vault, credential_item_ids, use_profile, profile_id) are rejected with a 403 by default, because every caller shares the proxy's upstream key. Set TINYFISH_ALLOW_AUTHENTICATED_RUNS=true on the proxy to allow them

LiteLLM's generic pass-through envelope fields (custom_body, stream, query_params) are rejected with a 400 on this route: send the native TinyFish request body, and streaming is determined by the endpoint you call

Timeouts​

Blocking runs get a 1500 second upstream timeout by default, covering TinyFish's 1200 second maximum run duration. Setting general_settings.pass_through_request_timeout overrides it

Environment variables​

VariableDescription
TINYFISH_API_KEYTinyFish API key the proxy uses upstream
TINYFISH_AGENT_API_BASEBase URL for the TinyFish Agent API. Default is https://agent.tinyfish.ai; a schemeless value is treated as https
TINYFISH_COST_PER_STEPPer-step USD rate used for spend tracking. Default is 0.016
TINYFISH_ALLOW_AUTHENTICATED_RUNSSet to true to allow vault and browser-profile fields in run requests