# Upsert actual hours

Source: https://www.supervisible.com/developers/actual-hours/post-actual-hours

POST /actual-hours



## POST /actual-hours

Creates or replaces whole weekly actual totals from 0–168 hours. Any input date normalizes to Sunday. Send one row per user/project/capability/week: duplicate normalized keys reject the entire batch instead of adding or overwriting hours. A null or omitted capabilityId writes an uncategorized allocation. Separate requests for the same key replace the weekly total. If no current line of work exists, Supervisible creates one so the hours can count in financial summaries. Backfilling hours for a removed person preserves the removed state instead of putting them back on the active project roster.

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

Required scope: write:actual_hours

## Operation contract

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

```json
{
  "summary": "Upsert actual hours",
  "description": "Creates or replaces whole weekly actual totals from 0–168 hours. Any input date normalizes to Sunday. Send one row per user/project/capability/week: duplicate normalized keys reject the entire batch instead of adding or overwriting hours. A null or omitted capabilityId writes an uncategorized allocation. Separate requests for the same key replace the weekly total. If no current line of work exists, Supervisible creates one so the hours can count in financial summaries. Backfilling hours for a removed person preserves the removed state instead of putting them back on the active project roster.",
  "tags": [
    "actual-hours"
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "x-required-scope": "write:actual_hours",
  "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": 7
              }
            ]
          }
        }
      }
    }
  },
  "responses": {
    "200": {
      "description": "Successful response",
      "content": {
        "application/json": {
          "example": {
            "data": [
              {
                "id": "019cb675-c4df-7f8b-8a83-5f28581f5e7f",
                "userId": "019cb675-c4df-7f8b-8a83-5f28581f5e7e",
                "projectId": "019cb675-c4d6-7e90-8806-25e5145c3a06",
                "capabilityId": null,
                "date": "2026-01-04",
                "hours": 7,
                "createdAt": "2026-01-06T10:00:00.000Z",
                "updatedAt": "2026-01-06T10:00:00.000Z"
              }
            ]
          }
        }
      }
    },
    "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"
    }
  },
  "parameters": []
}
```

## 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)
