> 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/catalog-sections/create-a-section-constraint.md).

# Create a section constraint

Use this endpoint to add a section constraint between data syncs, for example to hold reserved seats for students who satisfy a requirement group. A constraint pairs a section with a requirement group your data sync has already loaded, and an action. Your data sync stays the source of truth: the next sync removes any constraint on a synced section that the sync doesn't carry, whoever created it, so add the same row to your data sync before then.

## POST /catalog/section/constraint/{sis\_id}

>

```json
{"openapi":"3.0.0","info":{"title":"Stellic for Developers","version":"1.0"},"tags":[{"name":"Catalog Sections"}],"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":{"SectionConstraintRequest":{"type":"object","description":"Writable fields of a section constraint. Mirrors a schedule feed constraint row minus `section_constraint_id`, which the URL carries.","required":["section_id"],"properties":{"section_id":{"type":"string","description":"Catalog ID (`uni_id`) of the section the constraint applies to. Must match exactly one section."},"requirement_id":{"type":"string","default":"","description":"Identifier of a requirement group already ingested from your schedule feed's constraint rows. Blank or omitted creates a record with no requirement group; only one record without a group per section and action is allowed. A group the platform has not ingested returns 400."},"action":{"type":"string","default":"show","enum":["add","change_credit","change_grading_option","department_consent","disallow_drop","disallow_register","drop","full_refund","hide","instructor_consent","late_add","late_drop","reserved_seats","show","warn","withdraw"],"description":"Action the constraint applies. Use `reserved_seats`; the feed spelling `reserve_seats` is rejected."},"note":{"type":"string","default":"","description":"Free text stored with the record, kept exactly as sent (whitespace included)."},"start_timestamp":{"type":"string","nullable":true,"description":"`YYYY-MM-DD` (read as midnight UTC) or an ISO-8601 timestamp. `null`, an empty string, or omission stores no start."},"end_timestamp":{"type":"string","nullable":true,"description":"`YYYY-MM-DD` (read as midnight UTC) or an ISO-8601 timestamp. `null`, an empty string, or omission stores no end."}}},"SectionConstraintResponse":{"type":"object","description":"A section constraint record.","properties":{"sis_id":{"type":"string","description":"The record's identifier (the `{sis_id}` in the URL)."},"section_id":{"type":"string","description":"Catalog ID (`uni_id`) of the section the constraint applies to."},"requirement_id":{"type":"string","description":"Requirement group identifier, or an empty string when the record has no requirement group."},"action":{"type":"string","description":"Action the constraint applies."},"note":{"type":"string","description":"Free text stored with the record; an empty string when none was sent."},"start_timestamp":{"type":"string","format":"date-time","nullable":true,"description":"ISO-8601 timestamp in UTC (for example `2025-12-02T00:00:00Z`), or `null`."},"end_timestamp":{"type":"string","format":"date-time","nullable":true,"description":"ISO-8601 timestamp in UTC (for example `2026-01-15T00:00:00Z`), or `null`."}}},"SectionConstraintValidationError":{"type":"object","description":"Error body for 400 responses on the section constraint endpoints. Keys are field names (`section_id`, `requirement_id`, `action`, `note`, `start_timestamp`, `end_timestamp`, or `sis_id`), or `non_field_errors` when the body isn't a JSON object; each value is a list of messages.","additionalProperties":{"type":"array","items":{"type":"string"}}},"SectionConstraintErrorDetail":{"type":"object","description":"Error body for 404 and 409 responses on the section constraint endpoints.","properties":{"detail":{"type":"string","description":"Human-readable reason."}}}}},"paths":{"/catalog/section/constraint/{sis_id}":{"post":{"tags":["Catalog Sections"],"parameters":[{"name":"sis_id","in":"path","required":true,"description":"Partner-chosen identifier for the new record, in the same namespace as your schedule feed's `section_constraint_id` column. At most 64 characters, and not already in use by another record.","schema":{"type":"string","maxLength":64}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SectionConstraintRequest"}}}},"responses":{"201":{"description":"Constraint created. The body is the stored record; omitted optional fields show their defaults (`action` is `show`, `note` is an empty string, timestamps are `null`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SectionConstraintResponse"}}}},"400":{"description":"Validation failure. The body is an object keyed by field name; each value is a list of messages. `section_id` is the only required body field.\n\nCommon causes:\n- `section_id` missing: returns `This field is required.`\n- `section_id` unknown: returns `No course section found for id {section_id}`\n- `section_id` shared by more than one section: returns `Course section id {section_id} matches more than one section`\n- `requirement_id` not yet ingested from your schedule feed: returns `No ingested requirement found for id {requirement_id}`\n- `action` outside the accepted list, including the feed spelling `reserve_seats`\n- `start_timestamp` or `end_timestamp` not `YYYY-MM-DD` or ISO-8601\n- `requirement_id` or `note` sent as `null`: returns `This field may not be null.`\n- Body is not a JSON object: returns `Invalid data. Expected a dictionary, but got {type}.` under the `non_field_errors` key\n- `{sis_id}` longer than 64 characters: returns `sis_id must be at most 64 characters` under the `sis_id` key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SectionConstraintValidationError"}}}},"401":{"description":"Missing or invalid Bearer token."},"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.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"},"client_ip":{"type":"string"}}}}}},"409":{"description":"The record would collide with an existing one. Nothing is written.\n\nCommon causes:\n- `{sis_id}` already in use: returns `A section constraint with sis_id {sis_id} already exists`\n- Another record already pairs this section, action, and requirement group: returns `A section constraint already exists on section {section_id} with action {action} and requirement_id {requirement_id}`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SectionConstraintErrorDetail"}}}}}}}}}
```

#### What happens after the call

* The constraint is created right away under your `{sis_id}` and returned with a 201.
* With a `requirement_id`, the constraint takes a copy of that group's rules from the most recently loaded constraint that uses it. Your data sync's constraints for the group are unchanged.
* At institutions that evaluate reserved seats from section constraints, a `reserved_seats` constraint with a `requirement_id` applies from the next seat-availability check: students who don't satisfy the group don't count that group's reserved seats as available. It applies only when the section's seat data from your SIS includes a reserved-seat group with the same ID. Constraints with other actions are stored but not evaluated.

#### Notes

* **Two different 409s.** Either `{sis_id}` is already in use, or another constraint already pairs the same section, action, and requirement group (a constraint with no requirement group counts as one pairing). Change the existing constraint with `PUT` instead.
* **Use `reserved_seats`, not `reserve_seats`.** Your data sync accepts both spellings; this endpoint accepts only `reserved_seats`.
* **The requirement group must already be loaded by your data sync.** You can't send a group's rules here; an unknown `requirement_id` returns a 400.
* **`start_timestamp` and `end_timestamp` aren't evaluated.** A constraint applies from creation until it's removed, whatever its dates say.
* **Your data sync can change a constraint's `{sis_id}`.** If this constraint matches a row in your data sync (same section, action, and requirement group), the next sync keeps it but gives it the sync's identifier.

#### Related APIs

* [`GET /catalog/section/constraint/{sis_id}`](/stellic-partner-api/catalog-sections/read-a-section-constraint.md) to read a constraint.
* [`PUT /catalog/section/constraint/{sis_id}`](/stellic-partner-api/catalog-sections/replace-a-section-constraint.md) to replace one.
* [`DELETE /catalog/section/constraint/{sis_id}`](/stellic-partner-api/catalog-sections/remove-a-section-constraint.md) to remove one before the next sync.
* [`POST /catalog/section/restriction/{id}`](/stellic-partner-api/catalog-sections/add-a-restriction-to-a-section.md) for rules based on student sets rather than a requirement group.
