Create guardrails and assign them to your API keys — budgets, model and provider lists, and content filters.
A guardrail is a set of rules you put on your API keys: a budget in DA, the models that may run, the providers that may serve, zero data retention per lab, and content filters. A guardrail binds only the keys it is assigned to. See Guardrails for how the rules behave.
Every guardrail route is free and takes a management key: Authorization: Bearer $OPENDUNES_MANAGEMENT_KEY.
| Method | Path | Does |
|---|---|---|
GET | /v1/guardrails | lists your guardrails |
POST | /v1/guardrails | creates one |
GET | /v1/guardrails/{id} | reads one |
PATCH | /v1/guardrails/{id} | changes one |
DELETE | /v1/guardrails/{id} | deletes one |
GET | /v1/guardrails/assignments/keys | every key assignment on your account |
GET | /v1/guardrails/{id}/assignments/keys | the keys one guardrail is assigned to |
POST | /v1/guardrails/{id}/assignments/keys | assigns keys |
POST | /v1/guardrails/{id}/assignments/keys/remove | unassigns keys |
curl https://opendunes.com/v1/guardrails \
-H "Authorization: Bearer $OPENDUNES_MANAGEMENT_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Souk Bot production",
"limit": 500,
"reset_interval": "monthly",
"allowed_models": ["anthropic/claude-sonnet-5"],
"content_filter_builtins": [{ "slug": "email", "action": "redact" }],
"content_filters": [{ "pattern": "\\bpassword\\b", "action": "block", "label": "passwords" }]
}'| Field | Type | Description |
|---|---|---|
name | string | Required, up to 200 characters |
description | string | Optional, up to 1 000 characters |
limit | number | The budget in DA; null for none |
reset_interval | string | daily, weekly or monthly (Algeria time, the week from Monday); null never resets |
allowed_models | string[] | Only these models run |
ignored_models | string[] | These models never run |
allowed_providers | string[] | Only these providers serve |
ignored_providers | string[] | These providers never serve |
enforce_zdr_anthropic · _openai · _google · _xai · _other | boolean | Only endpoints that keep no data, for that lab |
enforce_zdr | boolean | Sets every lab not set on its own |
content_filter_builtins | object[] | { "slug", "action" } — slug one of email, phone, ssn, credit-card, ip-address, secrets, address, regex-prompt-injection |
content_filters | object[] | { "pattern", "action", "label" } — your own regular expression; a pattern that does not compile is refused |
action is redact (the match is replaced before the model reads it), block (the request answers 403) or flag (recorded; the request passes).
The answer is the guardrail, 201:
{
"data": {
"id": "a2d199a5-b6f5-4e2a-a67d-5695d99e8bb6",
"name": "Souk Bot production",
"description": null,
"limit": 500,
"reset_interval": "monthly",
"allowed_models": ["anthropic/claude-sonnet-5"],
"ignored_models": null,
"allowed_providers": null,
"ignored_providers": null,
"enforce_zdr_anthropic": null,
"enforce_zdr_openai": null,
"enforce_zdr_google": null,
"enforce_zdr_xai": null,
"enforce_zdr_other": null,
"content_filters": [{ "pattern": "\\bpassword\\b", "action": "block", "label": "passwords" }],
"content_filter_builtins": [{ "slug": "email", "action": "redact" }],
"created_at": "2026-09-24T09:12:03+00:00",
"updated_at": "2026-09-24T09:12:03+00:00"
}
}PATCH /v1/guardrails/{id} takes the same fields, each optional. DELETE answers { "deleted": true }. GET /v1/guardrails takes offset and limit (1 to 100, default 50) and answers { "data": [...], "total_count": n }.
Keys are named by their hash — the hash the API keys routes return, the SHA-256 of the key.
curl https://opendunes.com/v1/guardrails/a2d199a5-b6f5-4e2a-a67d-5695d99e8bb6/assignments/keys \
-H "Authorization: Bearer $OPENDUNES_MANAGEMENT_KEY" \
-H "Content-Type: application/json" \
-d '{ "key_hashes": ["9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"] }'{ "assigned_count": 1 }…/assignments/keys/remove takes the same body and answers { "unassigned_count": n }. The two lists answer:
{
"data": [
{
"id": "a2d19a01-7c1e-4f59-9e0a-0b1c2d3e4f50",
"guardrail_id": "a2d199a5-b6f5-4e2a-a67d-5695d99e8bb6",
"key_hash": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08",
"key_name": "Souk Bot",
"key_label": "sk-a1B2c",
"assigned_by": null,
"created_at": "2026-09-24T09:14:40+00:00"
}
],
"total_count": 1
}402 with limit_source: "guardrail" on every key it is assigned to.403 before it reaches a model, and nothing is charged.GET /v1/models/user lists the models your key's guardrails allow.A guardrail you name that is not yours, or does not exist, is a 404.