Skip to main content

POST /api/schedule

Run the scheduling engine on a set of volunteers and shifts. The engine assigns volunteers to open shift slots respecting group requirements, max hours, and time-overlap constraints, then returns a fairness score and any conflicts. Authentication required: Yes — Authorization: Bearer [user_id].[signature]

Request body

volunteers
object[]
required
List of volunteers to schedule.
unassigned_shifts
object[]
required
Shifts that need to be filled by the engine.
current_assignments
object[]
Optional. Existing assignments to lock in before the engine runs. The engine will preserve these and fill remaining slots around them.

Response body

assigned_shifts
object
A map of shift_id to an array of volunteer_id strings. Shifts with no assignable volunteers will not appear here — check unfilled_shifts for those.
{
  "shift_101": ["vol_7", "vol_12"],
  "shift_102": ["vol_3"]
}
unfilled_shifts
string[]
List of shift_id values for shifts that could not be fully filled. Cross-reference with conflicts to understand why.
fairness_score
number
A float representing how evenly the workload is distributed across all volunteers. Lower values indicate a more balanced schedule. A score of 0.12 is well-distributed; values closer to 1.0 indicate significant imbalance.
conflicts
object[]
Detailed reasons for each unfilled shift.
volunteers
object
A map of volunteer_id to a summary of their resulting schedule.

Example

curl -X POST https://shift-scheduler-api-3nxm.vercel.app/api/schedule \
     -H "Authorization: Bearer YOUR_KEY" \
     -H "Content-Type: application/json" \
     -d '{
       "volunteers": [
         {"id": "v1", "name": "Alice", "group": "Adults", "max_hours": 12},
         {"id": "v2", "name": "Delegate 1", "group": "Delegates", "max_hours": 10}
       ],
       "unassigned_shifts": [
         {
           "id": "s1",
           "start": "2026-05-01T09:00:00Z",
           "end": "2026-05-01T17:00:00Z",
           "required_groups": {"Delegates": 2, "Adults": 2}
         }
       ],
       "current_assignments": []
     }'
Example response:
{
  "assigned_shifts": {
    "shift_101": ["vol_7", "vol_12"],
    "shift_102": ["vol_3"]
  },
  "unfilled_shifts": ["shift_103"],
  "fairness_score": 0.12,
  "conflicts": [
    {
      "shift_id": "shift_103",
      "group": "Lifeguards",
      "reasons": ["Volunteer vol_7 already reached max_hours (40.0)"]
    }
  ],
  "volunteers": {
    "vol_7": {
      "assigned_hours": 40.0,
      "assigned_shifts": ["shift_100", "shift_101"]
    },
    "vol_12": {
      "assigned_hours": 8.0,
      "assigned_shifts": ["shift_101"]
    }
  }
}

POST /api/schedule/csv

Same scheduling engine as POST /api/schedule, but accepts CSV files via multipart/form-data instead of a JSON body. Useful for bulk imports from spreadsheet tools. Authentication required: Yes — Authorization: Bearer [user_id].[signature]

Form fields

volunteers
file
required
A CSV file with volunteer data. Use the same column structure as sample_volunteers.csv: Name, Group, Max Hours, Email, Phone. The Email and Phone columns are metadata and are not used by the scheduling engine.
Name,Group,Max Hours,Email,Phone
Delegate 1,Delegates,10,delegate1@example.com,(555) 101-0001
Adult 66,Adults,12,adult66@example.com,(555) 201-0066
shifts
file
required
A CSV file with shift data. Use the same column structure as sample_shifts.csv: Name, Start, End, Groups.The Groups column accepts a comma-separated list of Group:Count pairs (e.g., "Delegates:2, Adults:2").
Name,Start,End,Groups
Shift 1,12/01/2025 08:00 AM,12/01/2025 10:00 AM,"Delegates:2, Adults:2"
Shift 2,12/01/2025 10:00 AM,12/01/2025 12:00 PM,"Delegates:2, Adults:2"

Example

curl -X POST https://shift-scheduler-api-3nxm.vercel.app/api/schedule/csv \
     -H "Authorization: Bearer YOUR_KEY" \
     -F "volunteers=@sample_volunteers.csv" \
     -F "shifts=@sample_shifts.csv"
The response schema is identical to POST /api/schedule.

POST /api/validate

Validate a request payload without running the scheduler. The API checks the structure and types of your volunteers, unassigned_shifts, and current_assignments fields and returns any validation errors. Authentication required: Yes — Authorization: Bearer [user_id].[signature]
Call this endpoint first when debugging a 400 Bad Request from /api/schedule. It returns specific field-level errors that identify exactly what is malformed in your payload.

Request body

Same schema as POST /api/schedulevolunteers, unassigned_shifts, and optionally current_assignments.

Example

curl -X POST https://shift-scheduler-api-3nxm.vercel.app/api/validate \
     -H "Authorization: Bearer YOUR_KEY" \
     -H "Content-Type: application/json" \
     -d '{
       "volunteers": [{"id": "v1", "name": "Alice", "group": "Adults", "max_hours": 12}],
       "unassigned_shifts": [{"id": "s1", "start": "2026-05-01T09:00:00Z", "end": "2026-05-01T17:00:00Z", "required_groups": {"Adults": 1}}]
     }'

GET /api/usage

Retrieve your current API quota and usage history for your API key. Authentication required: Yes — Authorization: Bearer [user_id].[signature]

Response body

quota
number
Your total daily request quota.
usage_count
number
Number of requests made in the current billing period.
history
object[]
A list of recent API calls with timestamps and endpoint details.

Example

curl https://shift-scheduler-api-3nxm.vercel.app/api/usage \
     -H "Authorization: Bearer YOUR_KEY"

Build docs developers (and LLMs) love