Evaluate a variable
POST /v1/variables/{key} resolves a single variable for a user context and returns the value the platform decided to serve, plus the reason it picked it.
Request
POST /v1/variables/show-banner HTTP/1.1
Host: api.redpennon.dev
X-API-Key: 00000000-0000-0000-0000-000000000000
Content-Type: application/json
{
"user": {
"id": "user-123",
"email": "alice@example.com",
"organisation_id": "org-456",
"ip": "192.0.2.1",
"app_version": "4.12.0",
"platform": "ios",
"country": "AU",
"audiences": ["beta-testers"],
"custom_data": {
"plan": "enterprise",
"trial_days": 7
}
}
}
Path parameter
| Name | Required | Description |
|---|---|---|
key | yes | Variable slug, unique within the API key's project. Case-insensitive; URL-encode special chars. |
Headers
| Header | Required | Description |
|---|---|---|
X-API-Key | yes | Environment API key (UUID). Resolves the environment and (transitively) the project. |
Content-Type | yes | Must be application/json. |
Body
| Field | Type | Required | Description |
|---|---|---|---|
user | object or null | no | Targeting context. Omit (or send {}) for anonymous evaluation. |
The user object's recognised keys are:
| Key | Type | Maps to targeting property |
|---|---|---|
id | string | user_id |
email | string | email |
organisation_id | string | organisation_id |
ip | string | ip_address |
app_version | string | app_version |
platform | string | platform |
country | string | country |
audiences | string[] | audience (SDK-tagged path) |
custom_data | object | custom_property lookups (the targeting rule's custom_key indexes into this object) |
Response
Always 200 on success, including when no value is served (deleted feature, archived feature, targeting disabled, unknown key). SDKs read value and, when it's null, fall back to the developer-supplied code default.
{
"key": "show-banner",
"value": true,
"variation": "on",
"reason": "targeting_rule_matched",
"feature": "marketing-banner"
}
Fields
| Field | Type | Description |
|---|---|---|
key | string | Echoes the request's variable key (lowercased to match the resolver). |
value | bool | number | string | object | array | null | Variable value for the served variation. null whenever no value was served (see reason). |
variation | string | null | Slug of the served variation. null when no value was served. |
reason | string | One of the Reasons below. |
feature | string | null | Slug of the parent feature. null for variable_not_found (the key did not resolve to any feature). |
evaluation_trace | string (optional) | Opaque signed token. Present only when the request included a user with a stable identity (id or email) and a variation was served. Forward this string in a subsequent POST /v1/events call to get evaluation_trace_verified = true on the stored metric event (confirms the event came from a verified evaluation). |
Reasons
| Reason | When |
|---|---|
targeting_rule_matched | A targeting rule's conditions matched; the rule's serve_variation (or split bucket) was served. |
self_targeting_override | A self-targeting override pinned a variation for the SDK-supplied user.id + environment. |
default_variation | No targeting object configured; served the variable's VariableEnvironmentState default. |
no_rule_matched | Targeting was enabled but no rule matched; served the per-env default variation. |
feature_complete | Parent feature was marked Complete; targeting is short-circuited and the env-state default is served. |
targeting_disabled | Targeting toggle is off for this environment. value is null — the SDK should use its code default. |
variable_not_found | The key does not resolve to a variable in this project, or the parent feature is deleted or archived. |
feature_deleted | (Internal) Defence-in-depth branch; the resolver normally surfaces this as variable_not_found. |
feature_archived | (Internal) Same as above. |
Errors
| Status | Body | When |
|---|---|---|
400 | {"error":"Invalid JSON."} | Body did not parse as JSON. |
400 | {"error":"\"user\" must be an object."} | user was sent as a non-object (e.g. a string or array). |
401 | {"error":"Invalid or missing API key."} | X-API-Key missing, malformed, or doesn't resolve. |
405 | Standard Django 405 Method Not Allowed HTML response | Anything other than POST. |
There is no 404 for an unknown variable key — the endpoint always returns 200 with reason: "variable_not_found" so SDK clients can fail open uniformly.
Example: cURL
export REDPENNON_API_KEY=00000000-0000-0000-0000-000000000000
curl -X POST "https://api.redpennon.dev/v1/variables/show-banner" \
-H "X-API-Key: $REDPENNON_API_KEY" \
-H "Content-Type: application/json" \
-d '{"user": {"id": "user-123"}}'
Example: SDK
See the per-language docs for SDK ergonomics: Node, Python, Go.