# Upsert user assignments

Source: https://www.supervisible.com/developers/assignments/post-assignments

POST /assignments



## POST /assignments

Creates or replaces whole weekly planned totals from 0–168 hours. Any input date normalizes to Sunday. The stable key is userId, projectId, optional capabilityId, and normalized week: separate writes to the same key replace that total. Within a batch, duplicate keys after normalization reject the entire batch; rows are not summed. A null or omitted capabilityId writes an uncategorized assignment. The write also ensures the person and capability are attached to the project. By default, the response expands `project` and `capability` so callers don't need a second lookup; override with `?expand=` (empty disables expansion). Returns a soft `warnings` array when any item falls within an approved time-off window for that user — the write still succeeds.

Base URL: https://app.supervisible.com/api/v1

Required scope: write:assignments

## Operation contract

The definition below includes parameters, request bodies, response schemas, examples and authentication requirements.

```json
{
  "summary": "Upsert user assignments",
  "description": "Creates or replaces whole weekly planned totals from 0–168 hours. Any input date normalizes to Sunday. The stable key is userId, projectId, optional capabilityId, and normalized week: separate writes to the same key replace that total. Within a batch, duplicate keys after normalization reject the entire batch; rows are not summed. A null or omitted capabilityId writes an uncategorized assignment. The write also ensures the person and capability are attached to the project. By default, the response expands `project` and `capability` so callers don't need a second lookup; override with `?expand=` (empty disables expansion). Returns a soft `warnings` array when any item falls within an approved time-off window for that user — the write still succeeds.",
  "tags": [
    "assignments"
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "x-required-scope": "write:assignments",
  "parameters": [
    {
      "in": "query",
      "name": "expand",
      "required": false,
      "description": "Comma-separated expansions (user, project, capability). Defaults to `project,capability`.",
      "schema": {
        "type": "string"
      }
    }
  ],
  "requestBody": {
    "required": true,
    "content": {
      "application/json": {
        "schema": {
          "type": "object",
          "properties": {
            "items": {
              "minItems": 1,
              "maxItems": 1000,
              "type": "array",
              "items": {
                "type": "object",
                "properties": {
                  "userId": {
                    "type": "string",
                    "format": "uuid",
                    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                  },
                  "projectId": {
                    "type": "string",
                    "format": "uuid",
                    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                  },
                  "capabilityId": {
                    "anyOf": [
                      {
                        "type": "string",
                        "format": "uuid",
                        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "date": {
                    "type": "string",
                    "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
                  },
                  "hours": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 168
                  }
                },
                "required": [
                  "userId",
                  "projectId",
                  "date",
                  "hours"
                ],
                "additionalProperties": false
              }
            }
          },
          "required": [
            "items"
          ],
          "additionalProperties": false,
          "example": {
            "items": [
              {
                "userId": "019cb675-c4df-7f8b-8a83-5f28581f5e7e",
                "projectId": "019cb675-c4d6-7e90-8806-25e5145c3a06",
                "capabilityId": null,
                "date": "2026-01-06",
                "hours": 8
              }
            ]
          }
        }
      }
    }
  },
  "responses": {
    "200": {
      "description": "Successful response",
      "content": {
        "application/json": {
          "example": {
            "data": [
              {
                "id": "019cb675-c4df-7f8b-8a83-5f28581f5e7e",
                "userId": "019cb675-c4df-7f8b-8a83-5f28581f5e7e",
                "projectId": "019cb675-c4d6-7e90-8806-25e5145c3a06",
                "capabilityId": null,
                "date": "2026-01-04",
                "hours": 8,
                "project": {
                  "id": "019cb675-c4d6-7e90-8806-25e5145c3a06",
                  "name": "CRM Sync",
                  "status": "active"
                },
                "capability": null
              }
            ],
            "warnings": [
              {
                "code": "time_off_overlap",
                "message": "User Juan Méndez has approved time off 2026-01-05 → 2026-01-09 overlapping this assignment on 2026-01-04",
                "details": {
                  "userId": "019cb675-c4df-7f8b-8a83-5f28581f5e7e",
                  "timeOffRequestId": "019cb675-c4df-7f8b-8a83-5f28581f5e7f",
                  "itemIndex": 0,
                  "date": "2026-01-04"
                }
              }
            ]
          }
        }
      }
    },
    "400": {
      "description": "Invalid request"
    },
    "401": {
      "description": "Unauthorized"
    },
    "403": {
      "description": "Missing required scope or current member permission"
    },
    "404": {
      "description": "Not found"
    },
    "409": {
      "description": "Conflict; refresh current state and preview again"
    },
    "429": {
      "description": "Rate limited; honor Retry-After"
    }
  }
}
```

## Referenced definitions

```json
{
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "API Key"
      }
    }
  }
}
```

[Complete OpenAPI specification](https://www.supervisible.com/openapi/public-api-v1.json)
