# Quicksilver Gateway

Use Quicksilver when you need paid HTTP tools for AI-agent workflows. The gateway handles:

- Bearer API key authentication
- prepaid credit billing
- request forwarding to the configured upstream API
- normalized success and error responses

## Base URL

- Production: `https://qs-gateway.iotex.ai/v1`

## Authentication

Use a console-issued API key:

```http
Authorization: Bearer $QUICKSILVER_KEY
```

Apply Bearer auth only to:

- `POST /tools/:slug/invoke`
- `GET /account/balance`
- `GET /account/usage`

Public read routes must not include `Authorization`:

- `GET /tools`
- `GET /tools/:slug`

## Default Workflow

1. If the user prompt contains `Use tool: <slug>`, skip discovery (`GET /tools`) and go straight to step 3.
2. Use `GET /tools` or `GET /tools?q=...` only when the slug is genuinely unknown and you need discovery.
3. `GET /tools/:slug` to retrieve the tool's input schema, pricing, and operations.
4. `POST /tools/:slug/invoke` with parameters that match the input schema.
5. Read `cost.credits`, `meta.balanceAfter`, and `meta.requestId` from the response.

## Invoke Contract

`POST /tools/:slug/invoke` accepts a JSON body with a `params` object:

```json
{ "params": { "q": "iotex", "verified": true, "size": 5 } }
```

For `GET`-style tools, Quicksilver converts `params` into query parameters before forwarding upstream. For `POST`/`PUT`-style tools, Quicksilver forwards the body upstream.

## Success Response

Successful invocations return HTTP `200` with this shape:

```json
{
  "result": {},
  "cost": {
    "credits": 10
  },
  "meta": {
    "requestId": "req_...",
    "usageLogId": "usage_...",
    "latencyMs": 1234,
    "balanceAfter": 4990,
    "provider": {
      "id": "provider_...",
      "name": "Quicksilver",
      "slug": "quicksilver"
    },
    "settledAt": "2026-04-07T00:00:00.000Z"
  }
}
```

Also capture these response headers when present:

- `X-Quicksilver-Request-Id`
- `X-Quicksilver-Billed-Credits`
- `Retry-After`

## Billing Rules

- Only upstream `2xx` responses are billable.
- Upstream `4xx`, `5xx`, timeout, and concurrency-guard failures are not billed.
- If the account balance is too low, Quicksilver returns `402 insufficient_balance` before calling the upstream API.
- Phase 1 allows only one in-flight paid request per account. A concurrent call returns `429 account_request_in_flight`.

## Error Handling

Expect these common errors:

- `401 unauthorized`: missing, invalid, or revoked API key
- `402 insufficient_balance`: not enough credits to invoke the tool
- `400 invalid_tool_params`: request body does not match the tool input schema
- `404 not_found`: tool slug does not exist
- `429 account_request_in_flight`: another paid request is already running for this account
- `502 upstream_request_failed`: upstream provider returned `5xx` or could not be reached
- `504 upstream_timeout`: upstream timed out

When an invoke call fails, log the returned `requestId` if present and surface the `message` to the operator.

## Examples

```bash
curl https://qs-gateway.iotex.ai/v1/tools
```

```bash
curl https://qs-gateway.iotex.ai/v1/tools/depinscan
```

```bash
curl -X POST https://qs-gateway.iotex.ai/v1/tools/depinscan/invoke \
  -H "Authorization: Bearer $QUICKSILVER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"params":{"q":"solana", "size":1}}'
```

```bash
curl https://qs-gateway.iotex.ai/v1/account/balance \
  -H "Authorization: Bearer $QUICKSILVER_KEY"
```

## Agent Behavior

- If the user prompt includes `Use tool: <slug>`, skip discovery and go straight to `GET /tools/:slug` for the schema, then invoke.
- If a slug is already documented in this file for the task, do not do a discovery request first.
- Discovery is fallback only. Avoid `GET /tools?q=...` when a direct `GET /tools/:slug` or `POST /tools/:slug/invoke` is already justified.
- Never attach `Authorization` to public read routes.
- Treat Quicksilver as the paid execution layer: auth, billing, and upstream forwarding are handled by the gateway.
- Return concise summaries to the user, but preserve structured fields from `result` when they matter.
