# Goro
Goro is a tool gateway. One key, one prepaid balance, pay per call. You never
sign up for individual providers or hold their API keys.
Base URL: https://api.usegoro.ai
Auth: send `Authorization: Bearer $GORO_API_KEY` on every request.
## The loop
1. DISCOVER. You do not need to know the catalog. Describe the job.
POST /v1/discover
{"query": "recent posts from a tiktok creator", "limit": 5}
Returns {"items": [...]}, best first. Each item has `slug`, `when_to_use`,
a `price` object, and a `sample_input` you can fill in. An empty `items`
means nothing in the catalog answers that query: say so, do not invent a
slug.
2. INSPECT, when you are unsure of the input shape.
POST /v1/inspect
{"slug": "tiktok.profile"}
Returns `input_schema` (real JSON Schema, validated on every run),
`sample_input`, `output_sample` and `price`. Skip this when discover
already showed you the shape.
3. RUN. This spends real money. Only call it when you intend to execute.
POST /v1/run
{"slug": "tiktok.profile", "input": {...}}
200 means finished: the rows are in `output`, and `cost_usd` is what it
cost. 202 means still running: poll `status_url` until `status` is
COMPLETED, FAILED, STOPPED or TIMED_OUT. 502 means the provider failed and
you were not charged.
4. POLL, only after a 202.
GET /v1/runs/{run_id}
Safe to repeat. A finished run holds its rows until you take them, so a
poll that arrives after it finished still carries them. They are deleted
once collected and 24 hours after the run either way, so keep anything you
need long term. If the result is a media link, download the file: those
expire too.
## Money rules
- Check the balance with GET /v1/wallet/balance before a large job.
- Prices are visible before you spend, but they do not all mean the same
thing. Read `price.type`. Where `billed_on_actual_usage` is true the number
is a MAXIMUM for that request and the real charge is usually lower. Where it
is absent, on the flat-priced image tools, the number IS the price.
- Amounts come as integer micro-USD (1 USD = 1,000,000) plus a human `_usd`
string. Do maths on the integers.
- Failed, stopped and timed-out calls are never charged. Retrying is safe.
- On 402 `insufficient_funds`, stop and tell your human the amount and the
`top_up_url` in the body. Do not keep retrying.
- On 402 `budget_exceeded`, the wallet is fine and a spend cap is the blocker.
Say that instead of asking for a top-up.
## Errors
Every error body is {"code": ..., "message": ...}. Branch on `code`.
400 validation_error carries an `errors` array with a JSON pointer per bad
field: correct all of them and retry once. 404 means the slug does not exist.
429 means slow down. 502 and 503 mean retry later.