Constraints API
The Constraints API is how a customer puts a leash on Floopy’s optimization. Two endpoints — GET to read the current set, PUT to replace it.
The semantics are full-replace: a missing key in PUT falls back to the platform default. There is no PATCH.
Authentication and gating (both endpoints)
Section titled “Authentication and gating (both endpoints)”Authorization: Bearer <your-floopy-api-key>- Permission:
read_permissionforGET,write_permissionforPUT. - Pro plan.
- We are rolling this out per organization while we validate quality. Contact support if your organization is not yet enabled.
GET /v1/constraints
Section titled “GET /v1/constraints”Read the current constraint set, with the platform defaults shown alongside.
Endpoint
Section titled “Endpoint”GET https://api.floopy.ai/v1/constraintsResponse (200)
Section titled “Response (200)”{ "max_regression": { "value": 0.02, "window": "rolling_24h" }, "max_cost_increase": { "value": 0.05, "window": "rolling_24h" }, "confidence_threshold": 0.6, "min_samples_before_promotion": 50, "max_outcome_variance": 0.4, "max_cost_drop_without_validation": 0.8, "require_shadow_before_live": true, "defaults": { "max_regression": 0.05, "max_cost_increase": 0.10, "confidence_threshold": 0.0 }}| Field | Type | Description |
|---|---|---|
max_regression | object | null | Cap on the rolling drop in composite quality vs. baseline. null means “use platform default”. |
max_regression.value | number | [0, 0.5]. The fractional drop ceiling (e.g. 0.02 = 2%). |
max_regression.window | string | rolling_24h or rolling_7d. |
max_cost_increase | object | null | Cap on the rolling cost increase vs. baseline. value [0, 5.0]. |
confidence_threshold | number | null | Minimum router confidence to route away from baseline, [0.0, 1.0]. null or 0.0 disables the gate. See Confidence methodology. |
min_samples_before_promotion | integer | null | Minimum historical samples on a candidate before it can win. [1, 100_000]. null disables the gate. |
max_outcome_variance | number | null | Maximum rolling outcome variance the router will tolerate on a candidate. (0.0, 1.0]. null disables the gate. |
max_cost_drop_without_validation | number | null | Maximum fractional cost drop allowed without a passing shadow experiment in the staleness window. (0.0, 1.0]. null disables the gate. |
require_shadow_before_live | boolean | null | When true, no candidate is promoted to live traffic on a route until that (provider, model) has at least one completed shadow experiment in the staleness window (default 30 days, configurable per workspace — contact support). |
defaults | object | Platform defaults that fill in for any unset key. |
The four new fields (min_samples_before_promotion, max_outcome_variance, max_cost_drop_without_validation, require_shadow_before_live) are documented end-to-end on the Constraints feature page.
Errors
Section titled “Errors”| Status | Code | When |
|---|---|---|
403 | read_permission / plan_required | Permission or plan flag missing. |
5xx | internal | Upstream failure. |
Curl example
Section titled “Curl example”curl -s -H "Authorization: Bearer $FLOOPY_API_KEY" \ "https://api.floopy.ai/v1/constraints" | jq .PUT /v1/constraints
Section titled “PUT /v1/constraints”Replace the constraint set. Body cap: 4 KiB.
Endpoint
Section titled “Endpoint”PUT https://api.floopy.ai/v1/constraintsRequest body
Section titled “Request body”{ "max_regression": { "value": 0.02, "window": "rolling_24h" }, "max_cost_increase": { "value": 0.05, "window": "rolling_24h" }, "confidence_threshold": 0.7, "min_samples_before_promotion": 50, "max_outcome_variance": 0.4, "max_cost_drop_without_validation": 0.8, "require_shadow_before_live": true}| Field | Type | Required | Constraints |
|---|---|---|---|
max_regression | object | No | value [0, 0.5], window ∈ rolling_24h/rolling_7d. Omit to fall back to default 0.05. |
max_cost_increase | object | No | value [0, 5.0], same window enum. Omit to fall back to default 0.10. |
confidence_threshold | number | No | [0.0, 1.0]. Omit to disable (0.0). |
min_samples_before_promotion | integer | No | [1, 100_000]. Setting 0 is rejected with 400 out_of_range_min_samples_before_promotion. Omit to disable. |
max_outcome_variance | number | No | (0.0, 1.0], strict-greater-than-zero. is_finite() enforced. Omit to disable. |
max_cost_drop_without_validation | number | No | (0.0, 1.0], strict-greater-than-zero. is_finite() enforced. Omit to disable. |
require_shadow_before_live | boolean | No | Omit or set false to disable. |
The body is deny_unknown_fields — unknown keys return 400 unknown_field. Full-replace semantics: any key omitted from the PUT body is set to the platform default, not preserved. Every numeric field is is_finite() checked — NaN, +Inf, and -Inf are rejected with 400 out_of_range_<field>.
Semantics
Section titled “Semantics”max_regression— when a candidate’s expected regression exceeds the cap, the candidate is filtered withreason: "constraint_max_regression".max_cost_increase— when a candidate’s expected rolling cost increase exceeds the cap, the candidate is filtered withreason: "constraint_max_cost_increase".confidence_threshold— when the router’sconfidenceis below the threshold, the strategy falls back to baseline and emitsreason: "constraint_confidence_below_threshold"for every other candidate.min_samples_before_promotion— a candidate with fewer than this many historical samples is filtered withreason: "constraint_min_samples".max_outcome_variance— a candidate whose rolling outcome variance exceeds this cap is filtered withreason: "constraint_high_variance".max_cost_drop_without_validation— a candidate whose expected fractional cost drop vs. baseline exceeds this cap is filtered withreason: "constraint_cost_drop_requires_validation"unless a passing shadow experiment exists in the staleness window.require_shadow_before_live— whentrue, any candidate without a passing shadow experiment in the staleness window is filtered withreason: "constraint_shadow_required". The cache (constraint_shadow_pass:{org}:{provider}:{model}) isDEL-ed proactively on rollback so a recovery path runs hot.
Constraints compose. The router runs every gate on every candidate in this fixed order: max_cost_increase, max_regression, confidence_threshold, min_samples_before_promotion, max_outcome_variance, max_cost_drop_without_validation, require_shadow_before_live. The first rejection wins and is what the audit row shows.
Response (200)
Section titled “Response (200)”Returns the post-write state, identical shape to GET.
Errors
Section titled “Errors”| Status | Code | When |
|---|---|---|
400 | body_too_large | Body exceeds 4 KiB. |
400 | unknown_field | Unknown top-level key. |
400 | out_of_range_<field> | Field value outside the documented range. |
403 | write_permission / plan_required | Permission or plan flag missing. |
5xx | internal | Upstream failure. |
Curl example
Section titled “Curl example”curl -s -X PUT \ -H "Authorization: Bearer $FLOOPY_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "max_regression": {"value": 0.02, "window": "rolling_24h"}, "max_cost_increase": {"value": 0.05, "window": "rolling_24h"}, "confidence_threshold": 0.6 }' \ "https://api.floopy.ai/v1/constraints"Audit trail
Section titled “Audit trail”Every successful PUT writes a row to constraint_changes with the before snapshot, the after snapshot, the actor_api_key_id, and the timestamp. The audit event metadata carries SHA-256 hashes of before and after so the audit log itself does not duplicate the raw constraint values.
See also
Section titled “See also”- POST /v1/routing/explain — verify a constraint change before applying it.
- Confidence methodology — what
confidence_thresholdactually compares against.