# Management API

Source: https://inference.raindragon.ai/management-api (Markdown: https://inference.raindragon.ai/management-api.md; index of all docs: https://inference.raindragon.ai/llms.txt)

Configure your fallback providers from scripts and coding agents instead of the dashboard. Authenticate with a **management key**: a separate key type that can manage your account but cannot make inference calls. Your inference keys cannot call these endpoints.

## 1. Create a management key

In [Settings](https://inference.raindragon.ai/settings) → *Management API Keys*, create a key, choose its scopes (`fallbacks:read`, `fallbacks:write`, `usage:read`) and expiry, and copy it. It starts with `rdm_` and is shown once. We store only a hash. Every call is rate-limited (60/min per key by default) and audit-logged with the key id, action and model ids, never your provider key.

```
export RD_MGMT_KEY=rdm_...   # keep it out of your repo
```

## Endpoints

| Method | Path | Scope | Purpose |
| --- | --- | --- | --- |
| GET | /api/v1/management/fallbacks | fallbacks:read | List your fallbacks (keys masked) and the served model ids |
| GET | /api/v1/management/fallbacks/{model_id} | fallbacks:read | Get one fallback |
| PUT | /api/v1/management/fallbacks/{model_id} | fallbacks:write | Create or replace one fallback (idempotent) |
| POST | /api/v1/management/fallbacks/bulk | fallbacks:write | Set the same fallback for many models at once (idempotent, atomic) |
| DELETE | /api/v1/management/fallbacks/{model_id} | fallbacks:write | Remove one fallback |
| POST | /api/v1/management/fallbacks/test | fallbacks:write | Dry-run one 1-token request to the provider; returns ok/error |
| GET | /api/v1/management/usage/metrics?window=24h&model= | usage:read | Your requests, tokens, spend, cache-hit rate, TTFT p50/p90/p99, tok/s, error rate, failover share and fill-or-kill outcomes over 1h / 24h / 7d / 30d |
| GET | /api/v1/management/status | usage:read | Engine status (healthy / degraded / failing_over) and incidents from the past week |

`{model_id}` is one of our model ids (e.g. `google/gemma-4-26B-A4B-it`, any capitalization) or `*`. The request body fields are `fallback_url` (an https base URL), `fallback_api_key`, `fallback_model` (the provider's own id for the model) and `is_active`. Responses show the key only masked, e.g. `••••••••••••abcd`.

## Set an Inworld fallback for all Gemma models in one call

`model_ids` takes our model ids or glob patterns over them. `fallback_models` maps each of our models to the provider's id. Inworld uses Basic auth, so send its *Basic (Base64)* credential from platform.inworld.ai/api-keys with a `Basic ` prefix.

```
curl -X POST https://inference.raindragon.ai/api/v1/management/fallbacks/bulk \
  -H "Authorization: Bearer $RD_MGMT_KEY" -H "Content-Type: application/json" \
  -d '{
    "model_ids": ["google/gemma-*"],
    "fallback_url": "https://api.inworld.ai/v1",
    "fallback_api_key": "Basic '"$INWORLD_BASIC"'",
    "fallback_models": {
      "google/gemma-4-26B-A4B-it": "inworld/models/gemma-4-26b-a4b-it",
      "google/gemma-4-31B-it":     "inworld/models/gemma-4-31b-it"
    }
  }'
# -> {"results":[{"model_id":"google/gemma-4-26B-A4B-it","status":"created",...}, ...]}
# Run it again: every status is "unchanged".
```

Check the Inworld model ids against Inworld's model list. A model with no entry in `fallback_models` uses `fallback_model`, or our own id if that is unset. If any entry is invalid, nothing is written.

## One model, a catch-all default, test, delete

```
# upsert one model (201 created, then 200 "unchanged" on repeat)
curl -X PUT https://inference.raindragon.ai/api/v1/management/fallbacks/google/gemma-4-26B-A4B-it \
  -H "Authorization: Bearer $RD_MGMT_KEY" -H "Content-Type: application/json" \
  -d '{"fallback_url":"https://openrouter.ai/api/v1","fallback_api_key":"'"$OPENROUTER_KEY"'",
       "fallback_model":"google/gemma-4-26b-a4b-it"}'

# default for every model without its own fallback, including models added later.
# It forwards each request's own model id, so it cannot set fallback_model.
curl -X PUT https://inference.raindragon.ai/api/v1/management/fallbacks/* \
  -H "Authorization: Bearer $RD_MGMT_KEY" -H "Content-Type: application/json" \
  -d '{"fallback_url":"https://openrouter.ai/api/v1","fallback_api_key":"'"$OPENROUTER_KEY"'"}'

# test the saved fallback: one max_tokens=1 request to your provider (billed by them)
curl -X POST https://inference.raindragon.ai/api/v1/management/fallbacks/test \
  -H "Authorization: Bearer $RD_MGMT_KEY" -H "Content-Type: application/json" \
  -d '{"model_id":"google/gemma-4-26B-A4B-it"}'
# -> {"ok":true,"status_code":200,"latency_ms":412,...}  (the key is never returned)

# list, then delete
curl https://inference.raindragon.ai/api/v1/management/fallbacks -H "Authorization: Bearer $RD_MGMT_KEY"
curl -X DELETE https://inference.raindragon.ai/api/v1/management/fallbacks/google/gemma-4-26B-A4B-it \
  -H "Authorization: Bearer $RD_MGMT_KEY"
```

A PUT replaces the fallback, so an omitted `fallback_model` is cleared. Omit `fallback_api_key` on an update to keep the saved key. Turning off one model's fallback ( `"is_active": false`) does not hand that model to the catch-all.

## Errors

- **401**: missing, unknown, revoked or expired management key.
- **403**: an inference key was used, or the key lacks the scope.
- **404**: no fallback for that model. **422**: invalid input, e.g. a non-https URL or a model we do not serve. **429**: rate limited; see `Retry-After`.

## For Claude Code, Codex and other agents

- Give the agent a management key, not an inference key, in an environment variable such as `RD_MGMT_KEY`. Grant only `fallbacks:read` if it only needs to inspect.
- Prefer `PUT` and `/bulk`: they are idempotent, so an agent can re-run them safely and read `created` / `updated` / `unchanged` to see what changed.
- Call `/fallbacks/test` after a change, and never print the provider key. Responses never contain it.
- Revoke the key in Settings when the job is done, or give it a short expiry.
