Assign an SOP
Reference for POST /assignments, which assigns an SOP to a member by sign-in email, refuses duplicates and sends no email.
On this page
Shell
POST https://app.sopcompass.com/api/v1/assignmentsScope: read and write. Content-Type: application/json.
Assigns an SOP to a member of the workspace, by their sign-in email. Returns 201 Created with the new assignment, shaped as in List assignments.
Important: The API does not send the assignment email the app sends. The assignment appears in the person’s Assignments in the app, but nobody is notified. If people should hear about it, notify them your own way, for example from the same Zap or script.
Body parameters
| Name | Type | Required | Description |
|---|---|---|---|
sop_id |
UUID | Yes | An SOP the workspace can see (its own or in a shared-in library) that isn’t archived. |
email |
string | Yes | The member’s sign-in email. Not case sensitive; surrounding spaces are ignored. |
due_on |
string or null | No | Due date as YYYY-MM-DD. Must be a real calendar date. A date in the past is accepted, and the assignment is then overdue straight away. |
note |
string or null | No | A note for the assignee, up to 1,000 characters. A blank note is stored as null. |
Behavior
- Recorded as assigned by the key’s creator.
assigned_byis the owner or admin who created the API key. - No duplicates. If the person already has this SOP assigned and not yet completed (from the app or the API), the request is refused with
422 already_assigned. A retried request therefore never assigns twice. Once they complete it, it can be assigned again. - Members only. Someone who hasn’t joined the workspace yet gets
422 not_a_member. Invite them in the app first; useGET /peopleto check. - No email. See the note above.
Request
Shell
curl https://app.sopcompass.com/api/v1/assignments \
-H "Authorization: Bearer $SOPCOMPASS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"sop_id": "5b7e9d1a-2c4f-4e6b-8a1d-3c5e7f9a0b03",
"email": "new.cleaner@example.com",
"due_on": "2026-10-01",
"note": "Please finish before your first shift."
}'JavaScript
const res = await fetch("https://app.sopcompass.com/api/v1/assignments", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.SOPCOMPASS_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
sop_id: "5b7e9d1a-2c4f-4e6b-8a1d-3c5e7f9a0b03",
email: "new.cleaner@example.com",
due_on: "2026-10-01",
note: "Please finish before your first shift.",
}),
});
const body = await res.json();
if (res.status === 201) {
console.log("Assigned", body.data.id);
} else if (body.error.code === "already_assigned") {
console.log("Already assigned, nothing to do");
} else {
throw new Error(`${res.status} ${body.error.code}: ${body.error.message}`);
}Python
import os
import requests
res = requests.post(
"https://app.sopcompass.com/api/v1/assignments",
headers={"Authorization": f"Bearer {os.environ['SOPCOMPASS_API_KEY']}"},
json={
"sop_id": "5b7e9d1a-2c4f-4e6b-8a1d-3c5e7f9a0b03",
"email": "new.cleaner@example.com",
"due_on": "2026-10-01",
"note": "Please finish before your first shift.",
},
timeout=30,
)
body = res.json()
if res.status_code == 201:
print("Assigned", body["data"]["id"])
elif body["error"]["code"] == "already_assigned":
print("Already assigned, nothing to do")
else:
raise RuntimeError(f"{res.status_code} {body['error']['code']}: {body['error']['message']}")Response
201 Created
JSON
{
"data": {
"id": "d5f7b9c1-3e5a-4f7b-9d1e-3f5a7c9e1b23",
"sop": {
"id": "5b7e9d1a-2c4f-4e6b-8a1d-3c5e7f9a0b03",
"title": "New hire onboarding"
},
"assignee": {
"id": "2c4e6a8b-0d2f-4e4a-8b6c-8d0f2a4c6e22",
"name": null,
"email": "new.cleaner@example.com"
},
"assigned_by": {
"id": "8e0a2c4d-6f8b-4a0c-8e2d-4f6a8c0e2a09",
"name": "Dana Whitfield",
"email": "dana.whitfield@example.com"
},
"note": "Please finish before your first shift.",
"due_on": "2026-10-01",
"requires_quiz": false,
"status": "open",
"viewed_at": null,
"completed_at": null,
"created_at": "2026-09-19T16:20:41.873506Z"
}
}Errors
| Status | Code | When |
|---|---|---|
| 400 | invalid_json |
The body isn’t a JSON object. |
| 403 | read_only_key |
The key is read only. |
| 403 | workspace_read_only |
The workspace’s subscription has ended. |
| 404 | not_found |
No SOP with that id is visible to this workspace. |
| 415 | unsupported_media_type |
The request has no Content-Type: application/json header. |
| 422 | invalid_parameter |
sop_id is missing or not a UUID, email is missing or doesn’t look like an email address, or due_on isn’t a real YYYY-MM-DD date. |
| 422 | invalid_note |
note isn’t a string, or is longer than 1,000 characters. |
| 422 | sop_archived |
The SOP is archived. Restore it in the app first. |
| 422 | not_a_member |
Nobody in the workspace signs in with that email. |
| 422 | already_assigned |
The person already has this SOP assigned and not yet completed. |
Authentication, plan and rate limit errors apply to every endpoint; see Errors.