> For the complete documentation index, see [llms.txt](https://docs.stellic.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.stellic.com/stellic-partner-api/requirements/add-a-constraint-to-a-requirement.md).

# Add a constraint to a requirement

Use this endpoint to put a constraint on a requirement in a draft audit, such as how many of its children must be completed (`anyxof`), a minimum number of units (`minxunits`) or courses (`minxcourses`), or a minimum grade. `{requirement_id}` is a requirement node's `id` from the draft's tree; the audit is found from the requirement. `type` is the constraint name as the tree shows it, and `data` takes the same fields the tree shows for that type. Students aren't affected until you publish.

## POST /requirements/{requirement\_id}/constraints

>

```json
{"openapi":"3.0.0","info":{"title":"Stellic for Developers","version":"1.0"},"tags":[{"name":"Requirements","description":"Add, update, and remove the constraints (rules) on a requirement inside a draft audit."}],"servers":[{"url":"https://{institution}.stellic.com/partnerapi/v1","variables":{"institution":{"default":"{institution}","description":"Your institution's Stellic subdomain: the part before `.stellic.com` in the URL you use to sign in. It becomes the host in every request, as in `https://{institution}.stellic.com/partnerapi/v1/...`. Replace the `{institution}` placeholder with your subdomain before sending."}}}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"Personal Access Token issued by your Stellic integration partner. Send it as `Authorization: Bearer <token>` on every request. One token per institution; do not share across environments."}},"schemas":{"AddConstraintRequest":{"type":"object","required":["type","data"],"properties":{"type":{"type":"string","description":"Constraint type name, for example `minxunits`, `minxcourses`, `anyxof`, `mingrade`, `notcount`, `xfromdepts`, `coderange`. Unknown names are rejected with `Given type {type} is invalid`."},"data":{"type":"object","description":"Type-specific fields. For `minxunits`, `units` (number) and `is_each` (boolean, default `false`). For `anyxof`, `x` (integer) and optionally `is_and` (boolean)."},"is_hidden":{"type":"boolean","description":"Hide the constraint from students in the audit view. Defaults to `false`."}}},"AddConstraintResponse":{"type":"object","properties":{"pending_change":{"$ref":"#/components/schemas/PendingChange"},"constraint":{"$ref":"#/components/schemas/RequirementConstraint"}}},"PendingChange":{"type":"object","description":"A draft change queued for replay onto the published version when the draft is published.","properties":{"user":{"$ref":"#/components/schemas/PendingChangeUser"},"text":{"type":"string","description":"Plain-language summary of the change."},"timestamp":{"type":"string","description":"When the change was recorded, as `YYYY-MM-DD HH:MM:SS.ffffff+00:00`."}}},"PendingChangeUser":{"type":"object","description":"The account that made the change, as recorded on the change record.","properties":{"username":{"type":"string"},"display_username":{"type":"string"},"userid":{"type":"string","nullable":true},"title":{"type":"string","nullable":true},"first_name":{"type":"string"},"last_name":{"type":"string"},"photo_url":{"type":"string","nullable":true},"email":{"type":"string"},"sms_alerts_enabled":{"type":"boolean"},"last_log_in":{"type":"string","nullable":true},"is_active":{"type":"boolean"},"is_admin":{"type":"boolean"},"role":{"type":"string","nullable":true},"mobile_number":{"type":"string","nullable":true},"hash":{"type":"string","description":"Opaque account token. Ignore it."}}},"RequirementConstraint":{"type":"object","description":"One rule on a requirement.","properties":{"id":{"type":"integer","description":"Internal database ID of the constraint; the `constraint_id` for update and remove calls."},"type":{"type":"string","description":"Constraint type name, for example `anyxof`, `minxunits`, `minxcourses`, `mingrade`, `notcount`, `xfromdepts`, `coderange`."},"type_string":{"type":"string","description":"Human-readable rendering of the rule. Present for most constraint types."},"data":{"type":"object","description":"Type-specific fields, in the same shape you send on the add and update calls. For `minxunits` that is `units` and `is_each`; for `anyxof` it is `x` and `is_and`."},"is_hidden":{"type":"boolean","description":"Whether the constraint is hidden from students in the audit view."}}},"ErrorMessage":{"type":"object","description":"Error envelope used by the programs, audits, and requirements endpoints.","properties":{"error":{"type":"string","description":"Human-readable reason. Match on it if you need to branch; the strings on each endpoint page are verbatim."}}}}},"paths":{"/requirements/{requirement_id}/constraints":{"post":{"tags":["Requirements"],"parameters":[{"name":"requirement_id","in":"path","required":true,"description":"Internal numeric ID of a requirement in a draft audit: a node `id` from the draft's `requirement_tree`. The audit is resolved from the requirement, so there is no `audit_id` on this route.","schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddConstraintRequest"}}}},"responses":{"200":{"description":"Constraint added to the draft. `constraint.id` is the `constraint_id` you use to update or remove it. `pending_change` is the change record replayed on publish.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddConstraintResponse"}}}},"400":{"description":"Validation failure.\n\nCommon causes:\n- Missing `type` or `data` - returns `Missing required field(s): 'type', 'data'`\n- Empty `type` - returns `'type' cannot be empty`\n- `data` is not an object - returns `'data' must be a dictionary`\n- Unknown constraint type - returns `['Given type {type} is invalid']`\n- Type-specific constraint broken, for example a second `minxunits` with the same `is_each` - returns `Only one is_each allowed for minxunits in requirement {name} [{id}]`\n- The requirement is a free-electives requirement - returns `['Cannot add constraints to a Free Elective requirement']`\n- The token's account cannot edit this audit - returns `Forbidden Access.`\n- The first constraint on a requirement isn't one that can be primary - returns, for example, `minxunits cannot be a primary constraint of requirement {name} [{id}].`; `anyxof` added after another constraint returns `anyxof needs to be a primary constraint of requirement {name} [{id}].`\n- A second `anyxof` on the requirement - returns `['Only one anyxof constraint is allowed per requirement {name} [{id}]']`\n- The draft's name contains `-draft` but it isn't linked to a published audit - returns `['Cannot edit this audit. Please contact the Stellic team.']`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorMessage"}}}},"401":{"description":"Missing or invalid Bearer token.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"403":{"description":"Your IP address isn't on the allowlist for this endpoint. Contact Stellic to add it; the response includes the `client_ip` Stellic saw. Also returned, with only `error` set, when the requirement's audit isn't a draft (`Can only add constraints to draft audits.`) or belongs to a compliance requirement (`Compliance requirements are not available via the API.`).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"},"client_ip":{"type":"string"}}}}}},"404":{"description":"With a valid request body, an unknown requirement ID returns `{\"detail\": \"No Requirement matches the given query.\"}`. A requirement outside an editable audit, for example a course node outside an audit, returns `{\"error\": \"Requirement not found in an editable audit.\"}`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorMessage"}}}}}}}}}
```

#### What happens after the call

* The constraint is added, and the response returns it with its `id`, the `constraint_id` for updates and removals.
* The change is recorded and applied to the published audit when you publish the draft.

#### Notes

{% hint style="warning" %}
**Add the primary constraint first.** The first constraint on a requirement becomes its primary constraint, and `anyxof` must be the primary constraint. A secondary constraint such as `minxunits` can't come first: on a new requirement it returns `minxunits cannot be a primary constraint of requirement <name> [<id>].` Before adding children to a non-degree requirement, make sure it has an `anyxof`, `and`, `or`, or `minxcourses` constraint. Free-electives requirements cannot have children.
{% endhint %}

* **`anyxof` takes `x`, or `is_and: true` for all children.** A requirement can have only one.
* **`minxunits` takes `units` and `is_each`.** You can have two only if one is `is_each: true` and the other `false`; a second with the same `is_each` returns `Only one is_each allowed for minxunits in requirement <name> [<id>]`.
* **For other types, copy the `data` shape from an audit that already uses them,** via [`GET /audits/{audit_id}`](/stellic-partner-api/audits/read-an-audit.md). An unknown type returns `['Given type <type> is invalid']`.
* **Use a requirement in the draft audit.** A course node outside an audit returns a 404 with `Requirement not found in an editable audit.` The free-electives requirement accepts only its own course constraint.
* **`is_hidden` hides the constraint from students, but it still applies.** It defaults to `false`.
* **Only drafts can be edited.** A requirement in a published or under-review audit returns a 403 with `Can only add constraints to draft audits.`
* **The token's account needs edit rights on the audit,** or the call returns `Forbidden Access.`
* **Validation errors return 400 with `{"error": "<message>"}`.** A compliance requirement's audit returns a 403.

#### Related APIs

* [`PUT /requirements/{requirement_id}/constraints/{constraint_id}`](/stellic-partner-api/requirements/update-a-requirement-constraint.md) to change the constraint.
* [`DELETE /requirements/{requirement_id}/constraints/{constraint_id}`](/stellic-partner-api/requirements/remove-a-requirement-constraint.md) to remove it.
* [`POST /audits/{audit_id}/requirements/{parent_req_id}/subrequirements`](/stellic-partner-api/audits/add-a-sub-requirement.md) to add children.
