Authentication

All API requests require authentication using an API key. Include your API key in the request header (recommended) or as a query parameter.

Header Method (Recommended)

JavaScript
const response = await fetch('https://rosterly.quickstopsolution.com/api/events?start=2026-01-01&end=2026-01-31', { headers: { 'X-API-Key': 'your-api-key-here' } });
PHP
$ch = curl_init('https://rosterly.quickstopsolution.com/api/events?start=2026-01-01&end=2026-01-31'); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'X-API-Key: your-api-key-here' ]); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch);

Query Parameter Method

Example
GET https://rosterly.quickstopsolution.com/api/events?start=2026-01-01&end=2026-01-31&api_key=your-api-key-here

Rate Limits

API requests are limited to 10 requests per minute per API key. Rate limit information is included in response headers:

  • X-RateLimit-Limit - Maximum requests allowed
  • X-RateLimit-Remaining - Remaining requests in current window
  • X-RateLimit-Reset - When the rate limit resets

If you exceed the rate limit, you'll receive a 429 Too Many Requests response.

Caching

All GET requests are cached using ETag and Last-Modified headers. To validate your cache, include these headers in your request:

  • If-None-Match - ETag from previous response
  • If-Modified-Since - Last-Modified date from previous response

If the data hasn't changed, you'll receive a 304 Not Modified response with no body, saving bandwidth.

Date & Time

Event timestamps are stored in the database as UTC (YYYY-MM-DD HH:MM:SS with no offset). API responses return those same UTC values in start_datetime and end_datetime.

Sending dates (create / update)

When you POST or PUT an event, the server accepts ISO 8601 strings. How a value is interpreted depends on whether you include a timezone:

Format Example Interpretation
With timezone offset 2024-01-15T09:00:00+08:00, 2024-01-15T01:00:00Z Converted to UTC for storage
Without timezone (naive) 2024-01-15 09:00:00, 2024-01-15T09:00:00 Treated as wall-clock time in the server APP_TIMEZONE (default: Asia/Kuala_Lumpur, UTC+8)

For example, 2024-01-15T09:00:00 without an offset means 9:00 AM Malaysia time and is stored as 2024-01-15 01:00:00 UTC.

Recommended: always include an explicit offset (Z or +08:00) so there is no ambiguity.

Events Endpoints

GET /api/events

List calendar events. Requires start and end date parameters.

Required Parameters:

  • start - Start date (YYYY-MM-DD or YYYY-MM-DD HH:MM:SS)
  • end - End date (YYYY-MM-DD or YYYY-MM-DD HH:MM:SS)

Optional Parameters:

  • event_type_id - Filter by event type
  • staff_id - Filter events where this staff member is an attendee
JavaScript
const response = await fetch('https://rosterly.quickstopsolution.com/api/events?start=2026-01-01&end=2026-01-31&event_type_id=1&staff_id=5', { headers: { 'X-API-Key': 'your-api-key-here' } }); const data = await response.json();
Node.js (Backend)
// .env // API_BASE_URL=https://rosterly.quickstopsolution.com/api // API_KEY=your-api-key-here const baseUrl = process.env.API_BASE_URL; const apiKey = process.env.API_KEY; async function main() { const response = await fetch(`${baseUrl}/events?start=2026-01-01&end=2026-01-31&event_type_id=1&staff_id=5`, { headers: { 'X-API-Key': apiKey } }); const data = await response.json(); console.log('status', response.status); console.log(data); } main().catch(console.error);
PHP
$ch = curl_init('https://rosterly.quickstopsolution.com/api/events?start=2026-01-01&end=2026-01-31&event_type_id=1&staff_id=5'); curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-API-Key: your-api-key-here']); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); $data = json_decode($response, true);
POST /api/events

Create a new calendar event. Descriptions support Markdown and the API returns a sanitized description_html field for rendering.

Required Body Fields:

  • title - Event title
  • start_datetime - Start date/time. ISO 8601 with offset recommended; naive values use APP_TIMEZONE (see Date & Time)
  • end_datetime - End date/time. Same format rules as start_datetime

Optional Body Fields:

  • description - Markdown description source. Raw HTML is escaped; pasted <pre> blocks are normalized into code blocks.
  • location - Event location
  • event_type_id - Event type ID
  • is_all_day - Boolean (true/false)
  • attendees - Array of staff/user IDs
JavaScript
const response = await fetch('https://rosterly.quickstopsolution.com/api/events', { method: 'POST', headers: { 'X-API-Key': 'your-api-key-here', 'Content-Type': 'application/json' }, body: JSON.stringify({ title: 'Team Meeting', description: '
REPORTING FOR CASE/VISIT/MEETING BY STAFF

DATE/TIME: 20/05/2026 (21:00 - 22:00)
', start_datetime: '2026-01-15 10:00:00', end_datetime: '2026-01-15 11:00:00', event_type_id: 1, attendees: [1, 2, 3] }) }); const data = await response.json();
Node.js (Backend)
// .env // API_BASE_URL=https://rosterly.quickstopsolution.com/api // API_KEY=your-api-key-here const baseUrl = process.env.API_BASE_URL; const apiKey = process.env.API_KEY; async function main() { const response = await fetch(`${baseUrl}/events`, { method: 'POST', headers: { 'X-API-Key': apiKey, 'Content-Type': 'application/json' }, body: JSON.stringify({ title: 'Team Meeting', description: '
REPORTING FOR CASE/VISIT/MEETING BY STAFF

DATE/TIME: 20/05/2026 (21:00 - 22:00)
', start_datetime: '2026-01-15 10:00:00', end_datetime: '2026-01-15 11:00:00', event_type_id: 1, attendees: [1, 2, 3] }) }); const data = await response.json(); console.log('status', response.status); console.log(data); } main().catch(console.error);
PHP
$data = [ 'title' => 'Team Meeting', 'description' => "
REPORTING FOR CASE/VISIT/MEETING BY STAFF

DATE/TIME: 20/05/2026 (21:00 - 22:00)
", 'start_datetime' => '2026-01-15 10:00:00', 'end_datetime' => '2026-01-15 11:00:00', 'event_type_id' => 1, 'attendees' => [1, 2, 3] ]; $ch = curl_init('https://rosterly.quickstopsolution.com/api/events'); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'X-API-Key: your-api-key-here', 'Content-Type: application/json' ]); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch);
GET /api/events/:id

Get a single event by ID.

JavaScript
const response = await fetch('https://rosterly.quickstopsolution.com/api/events/123', { headers: { 'X-API-Key': 'your-api-key-here' } }); const data = await response.json();
Node.js (Backend)
// .env // API_BASE_URL=https://rosterly.quickstopsolution.com/api // API_KEY=your-api-key-here const baseUrl = process.env.API_BASE_URL; const apiKey = process.env.API_KEY; async function main() { const response = await fetch(`${baseUrl}/events/123`, { headers: { 'X-API-Key': apiKey } }); const data = await response.json(); console.log('status', response.status); console.log(data); } main().catch(console.error);
PHP
$ch = curl_init('https://rosterly.quickstopsolution.com/api/events/123'); curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-API-Key: your-api-key-here']); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); $data = json_decode($response, true);
PUT /api/events/:id

Update an existing event. Only include fields you want to update.

JavaScript
const response = await fetch('https://rosterly.quickstopsolution.com/api/events/123', { method: 'PUT', headers: { 'X-API-Key': 'your-api-key-here', 'Content-Type': 'application/json' }, body: JSON.stringify({ title: 'Updated Team Meeting', description: '
UPDATED HANDOVER

VENUE: Confirmed
STAFF: Assigned
' }) }); const data = await response.json();
Node.js (Backend)
// .env // API_BASE_URL=https://rosterly.quickstopsolution.com/api // API_KEY=your-api-key-here const baseUrl = process.env.API_BASE_URL; const apiKey = process.env.API_KEY; async function main() { const response = await fetch(`${baseUrl}/events/123`, { method: 'PUT', headers: { 'X-API-Key': apiKey, 'Content-Type': 'application/json' }, body: JSON.stringify({ title: 'Updated Team Meeting', description: '
UPDATED HANDOVER

VENUE: Confirmed
STAFF: Assigned
' }) }); const data = await response.json(); console.log('status', response.status); console.log(data); } main().catch(console.error);
PHP
$data = [ 'title' => 'Updated Team Meeting', 'description' => "
UPDATED HANDOVER

VENUE: Confirmed
STAFF: Assigned
" ]; $ch = curl_init('https://rosterly.quickstopsolution.com/api/events/123'); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT'); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'X-API-Key: your-api-key-here', 'Content-Type: application/json' ]); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); $result = json_decode($response, true);
DELETE /api/events/:id

Delete an event.

JavaScript
const response = await fetch('https://rosterly.quickstopsolution.com/api/events/123', { method: 'DELETE', headers: { 'X-API-Key': 'your-api-key-here' } }); const data = await response.json();
Node.js (Backend)
// .env // API_BASE_URL=https://rosterly.quickstopsolution.com/api // API_KEY=your-api-key-here const baseUrl = process.env.API_BASE_URL; const apiKey = process.env.API_KEY; async function main() { const response = await fetch(`${baseUrl}/events/123`, { method: 'DELETE', headers: { 'X-API-Key': apiKey } }); const data = await response.json(); console.log('status', response.status); console.log(data); } main().catch(console.error);
PHP
$ch = curl_init('https://rosterly.quickstopsolution.com/api/events/123'); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE'); curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-API-Key: your-api-key-here']); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); $result = json_decode($response, true);

Public Holidays Endpoints

GET /api/public-holidays?year=YYYY

List all public holidays. You can optionally filter by year.

Optional Parameters:

  • year - Filter holidays by year (e.g., 2026)
JavaScript
const response = await fetch('https://rosterly.quickstopsolution.com/api/public-holidays?year=2026', { headers: { 'X-API-Key': 'your-api-key-here' } }); const data = await response.json();
Node.js (Backend)
// .env // API_BASE_URL=https://rosterly.quickstopsolution.com/api // API_KEY=your-api-key-here const baseUrl = process.env.API_BASE_URL; const apiKey = process.env.API_KEY; async function main() { const response = await fetch(`${baseUrl}/public-holidays?year=2026`, { headers: { 'X-API-Key': apiKey } }); const data = await response.json(); console.log('status', response.status); console.log(data); } main().catch(console.error);
PHP
$ch = curl_init('https://rosterly.quickstopsolution.com/api/public-holidays?year=2026'); curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-API-Key: your-api-key-here']); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); $data = json_decode($response, true);
GET /api/public-holidays/:id

Get a single public holiday by ID.

JavaScript
const response = await fetch('https://rosterly.quickstopsolution.com/api/public-holidays/10', { headers: { 'X-API-Key': 'your-api-key-here' } }); const data = await response.json();
Node.js (Backend)
// .env // API_BASE_URL=https://rosterly.quickstopsolution.com/api // API_KEY=your-api-key-here const baseUrl = process.env.API_BASE_URL; const apiKey = process.env.API_KEY; async function main() { const response = await fetch(`${baseUrl}/public-holidays/10`, { headers: { 'X-API-Key': apiKey } }); const data = await response.json(); console.log('status', response.status); console.log(data); } main().catch(console.error);
PHP
$ch = curl_init('https://rosterly.quickstopsolution.com/api/public-holidays/10'); curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-API-Key: your-api-key-here']); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); $data = json_decode($response, true);
POST /api/public-holidays

Create a new public holiday.

Required Body Fields:

  • title - Holiday name
  • start_date - Start date (YYYY-MM-DD)
  • end_date - End date (YYYY-MM-DD)

Optional Body Fields:

  • is_custom - Boolean (true/false), default false
JavaScript
const response = await fetch('https://rosterly.quickstopsolution.com/api/public-holidays', { method: 'POST', headers: { 'X-API-Key': 'your-api-key-here', 'Content-Type': 'application/json' }, body: JSON.stringify({ title: 'Company Day', start_date: '2026-11-15', end_date: '2026-11-15', is_custom: true }) }); const data = await response.json();
Node.js (Backend)
// .env // API_BASE_URL=https://rosterly.quickstopsolution.com/api // API_KEY=your-api-key-here const baseUrl = process.env.API_BASE_URL; const apiKey = process.env.API_KEY; async function main() { const response = await fetch(`${baseUrl}/public-holidays`, { method: 'POST', headers: { 'X-API-Key': apiKey, 'Content-Type': 'application/json' }, body: JSON.stringify({ title: 'Company Day', start_date: '2026-11-15', end_date: '2026-11-15', is_custom: true }) }); const data = await response.json(); console.log('status', response.status); console.log(data); } main().catch(console.error);
PHP
$data = [ 'title' => 'Company Day', 'start_date' => '2026-11-15', 'end_date' => '2026-11-15', 'is_custom' => true ]; $ch = curl_init('https://rosterly.quickstopsolution.com/api/public-holidays'); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'X-API-Key: your-api-key-here', 'Content-Type: application/json' ]); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); $result = json_decode($response, true);
PUT /api/public-holidays/:id

Update an existing public holiday. Send one or more updatable fields.

Updatable Body Fields:

  • title - Holiday name
  • start_date - Start date (YYYY-MM-DD)
  • end_date - End date (YYYY-MM-DD)
  • is_custom - Boolean (true/false)
JavaScript
const response = await fetch('https://rosterly.quickstopsolution.com/api/public-holidays/10', { method: 'PUT', headers: { 'X-API-Key': 'your-api-key-here', 'Content-Type': 'application/json' }, body: JSON.stringify({ title: 'Updated Company Day', end_date: '2026-11-16' }) }); const data = await response.json();
Node.js (Backend)
// .env // API_BASE_URL=https://rosterly.quickstopsolution.com/api // API_KEY=your-api-key-here const baseUrl = process.env.API_BASE_URL; const apiKey = process.env.API_KEY; async function main() { const response = await fetch(`${baseUrl}/public-holidays/10`, { method: 'PUT', headers: { 'X-API-Key': apiKey, 'Content-Type': 'application/json' }, body: JSON.stringify({ title: 'Updated Company Day', end_date: '2026-11-16' }) }); const data = await response.json(); console.log('status', response.status); console.log(data); } main().catch(console.error);
PHP
$data = [ 'title' => 'Updated Company Day', 'end_date' => '2026-11-16' ]; $ch = curl_init('https://rosterly.quickstopsolution.com/api/public-holidays/10'); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT'); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'X-API-Key: your-api-key-here', 'Content-Type: application/json' ]); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); $result = json_decode($response, true);
DELETE /api/public-holidays/:id

Delete a public holiday.

JavaScript
const response = await fetch('https://rosterly.quickstopsolution.com/api/public-holidays/10', { method: 'DELETE', headers: { 'X-API-Key': 'your-api-key-here' } }); const data = await response.json();
Node.js (Backend)
// .env // API_BASE_URL=https://rosterly.quickstopsolution.com/api // API_KEY=your-api-key-here const baseUrl = process.env.API_BASE_URL; const apiKey = process.env.API_KEY; async function main() { const response = await fetch(`${baseUrl}/public-holidays/10`, { method: 'DELETE', headers: { 'X-API-Key': apiKey } }); const data = await response.json(); console.log('status', response.status); console.log(data); } main().catch(console.error);
PHP
$ch = curl_init('https://rosterly.quickstopsolution.com/api/public-holidays/10'); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE'); curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-API-Key: your-api-key-here']); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); $result = json_decode($response, true);

Rosters Endpoints

GET /api/rosters?start=YYYY-MM-DD&end=YYYY-MM-DD

List rosters. Requires start and end date parameters.

Required Parameters:

  • start - Start date (YYYY-MM-DD)
  • end - End date (YYYY-MM-DD)

Optional Parameters:

  • roster_type_id - Filter by roster type
  • staff_id - Filter rosters where this staff member has entries
JavaScript
const response = await fetch('https://rosterly.quickstopsolution.com/api/rosters?start=2026-01-01&end=2026-12-31&roster_type_id=1&staff_id=5', { headers: { 'X-API-Key': 'your-api-key-here' } }); const data = await response.json();
Node.js (Backend)
// .env // API_BASE_URL=https://rosterly.quickstopsolution.com/api // API_KEY=your-api-key-here const baseUrl = process.env.API_BASE_URL; const apiKey = process.env.API_KEY; async function main() { const response = await fetch(`${baseUrl}/rosters?start=2026-01-01&end=2026-12-31&roster_type_id=1&staff_id=5`, { headers: { 'X-API-Key': apiKey } }); const data = await response.json(); console.log('status', response.status); console.log(data); } main().catch(console.error);
PHP
$ch = curl_init('https://rosterly.quickstopsolution.com/api/rosters?start=2026-01-01&end=2026-12-31&roster_type_id=1&staff_id=5'); curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-API-Key: your-api-key-here']); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); $data = json_decode($response, true);
POST /api/rosters

Create a new roster.

Required Body Fields:

  • name - Roster name
  • roster_type_id - Roster type ID
  • year - Year (e.g., 2026)
  • month - Month (1-12)
JavaScript
const response = await fetch('https://rosterly.quickstopsolution.com/api/rosters', { method: 'POST', headers: { 'X-API-Key': 'your-api-key-here', 'Content-Type': 'application/json' }, body: JSON.stringify({ name: 'January 2026 Roster', roster_type_id: 1, year: 2026, month: 1, notes: 'Monthly roster' }) }); const data = await response.json();
Node.js (Backend)
// .env // API_BASE_URL=https://rosterly.quickstopsolution.com/api // API_KEY=your-api-key-here const baseUrl = process.env.API_BASE_URL; const apiKey = process.env.API_KEY; async function main() { const response = await fetch(`${baseUrl}/rosters`, { method: 'POST', headers: { 'X-API-Key': apiKey, 'Content-Type': 'application/json' }, body: JSON.stringify({ name: 'January 2026 Roster', roster_type_id: 1, year: 2026, month: 1, notes: 'Monthly roster' }) }); const data = await response.json(); console.log('status', response.status); console.log(data); } main().catch(console.error);
PHP
$data = [ 'name' => 'January 2026 Roster', 'roster_type_id' => 1, 'year' => 2026, 'month' => 1, 'notes' => 'Monthly roster' ]; $ch = curl_init('https://rosterly.quickstopsolution.com/api/rosters'); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'X-API-Key: your-api-key-here', 'Content-Type: application/json' ]); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); $result = json_decode($response, true);
GET /api/rosters/:id?staff_id=X

Get a roster with entries. If staff_id is provided, returns shifts grouped by date for that staff member.

JavaScript
const response = await fetch('https://rosterly.quickstopsolution.com/api/rosters/123?staff_id=5', { headers: { 'X-API-Key': 'your-api-key-here' } }); const data = await response.json();
Node.js (Backend)
// .env // API_BASE_URL=https://rosterly.quickstopsolution.com/api // API_KEY=your-api-key-here const baseUrl = process.env.API_BASE_URL; const apiKey = process.env.API_KEY; async function main() { const response = await fetch(`${baseUrl}/rosters/123?staff_id=5`, { headers: { 'X-API-Key': apiKey } }); const data = await response.json(); console.log('status', response.status); console.log(data); } main().catch(console.error);
PHP
$ch = curl_init('https://rosterly.quickstopsolution.com/api/rosters/123?staff_id=5'); curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-API-Key: your-api-key-here']); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); $data = json_decode($response, true);
POST /api/rosters/:id/entries

Add or update a roster entry.

Required Body Fields:

  • staff_id - Staff/user ID
  • entry_date - Date (YYYY-MM-DD)

Optional Body Fields:

  • shift_id - Shift ID
  • notes - Notes
JavaScript
const response = await fetch('https://rosterly.quickstopsolution.com/api/rosters/123/entries', { method: 'POST', headers: { 'X-API-Key': 'your-api-key-here', 'Content-Type': 'application/json' }, body: JSON.stringify({ staff_id: 5, entry_date: '2026-01-15', shift_id: 1, notes: 'Morning shift' }) }); const data = await response.json();
Node.js (Backend)
// .env // API_BASE_URL=https://rosterly.quickstopsolution.com/api // API_KEY=your-api-key-here const baseUrl = process.env.API_BASE_URL; const apiKey = process.env.API_KEY; async function main() { const response = await fetch(`${baseUrl}/rosters/123/entries`, { method: 'POST', headers: { 'X-API-Key': apiKey, 'Content-Type': 'application/json' }, body: JSON.stringify({ staff_id: 5, entry_date: '2026-01-15', shift_id: 1, notes: 'Morning shift' }) }); const data = await response.json(); console.log('status', response.status); console.log(data); } main().catch(console.error);
PHP
$data = [ 'staff_id' => 5, 'entry_date' => '2026-01-15', 'shift_id' => 1, 'notes' => 'Morning shift' ]; $ch = curl_init('https://rosterly.quickstopsolution.com/api/rosters/123/entries'); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'X-API-Key: your-api-key-here', 'Content-Type: application/json' ]); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); $result = json_decode($response, true);

Users Endpoints

GET /api/users

List all active users (staff members).

JavaScript
const response = await fetch('https://rosterly.quickstopsolution.com/api/users', { headers: { 'X-API-Key': 'your-api-key-here' } }); const data = await response.json();
Node.js (Backend)
// .env // API_BASE_URL=https://rosterly.quickstopsolution.com/api // API_KEY=your-api-key-here const baseUrl = process.env.API_BASE_URL; const apiKey = process.env.API_KEY; async function main() { const response = await fetch(`${baseUrl}/users`, { headers: { 'X-API-Key': apiKey } }); const data = await response.json(); console.log('status', response.status); console.log(data); } main().catch(console.error);
PHP
$ch = curl_init('https://rosterly.quickstopsolution.com/api/users'); curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-API-Key: your-api-key-here']); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); $data = json_decode($response, true);
POST /api/users

Create a new user (staff member).

Required Body Fields:

  • username - Username (unique)
  • email - Email address (unique)
  • password - Password (will be hashed)
  • full_name - Full name

Optional Body Fields:

  • designation - Job title/designation
  • phone - Phone number
JavaScript
const response = await fetch('https://rosterly.quickstopsolution.com/api/users', { method: 'POST', headers: { 'X-API-Key': 'your-api-key-here', 'Content-Type': 'application/json' }, body: JSON.stringify({ username: 'johndoe', email: 'john@example.com', password: 'securepassword123', full_name: 'John Doe', designation: 'Developer', phone: '+1234567890' }) }); const data = await response.json();
Node.js (Backend)
// .env // API_BASE_URL=https://rosterly.quickstopsolution.com/api // API_KEY=your-api-key-here const baseUrl = process.env.API_BASE_URL; const apiKey = process.env.API_KEY; async function main() { const response = await fetch(`${baseUrl}/users`, { method: 'POST', headers: { 'X-API-Key': apiKey, 'Content-Type': 'application/json' }, body: JSON.stringify({ username: 'johndoe', email: 'john@example.com', password: 'securepassword123', full_name: 'John Doe', designation: 'Developer', phone: '+1234567890' }) }); const data = await response.json(); console.log('status', response.status); console.log(data); } main().catch(console.error);
PHP
$data = [ 'username' => 'johndoe', 'email' => 'john@example.com', 'password' => 'securepassword123', 'full_name' => 'John Doe', 'designation' => 'Developer', 'phone' => '+1234567890' ]; $ch = curl_init('https://rosterly.quickstopsolution.com/api/users'); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'X-API-Key: your-api-key-here', 'Content-Type: application/json' ]); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); $result = json_decode($response, true);

Types Endpoints

GET /api/event-types

List all active event types. Creating and editing event types is only available in Settings to admins.

JavaScript
const response = await fetch('https://rosterly.quickstopsolution.com/api/event-types', { headers: { 'X-API-Key': 'your-api-key-here' } }); const data = await response.json();
Node.js (Backend)
// .env // API_BASE_URL=https://rosterly.quickstopsolution.com/api // API_KEY=your-api-key-here const baseUrl = process.env.API_BASE_URL; const apiKey = process.env.API_KEY; async function main() { const response = await fetch(`${baseUrl}/event-types`, { headers: { 'X-API-Key': apiKey } }); const data = await response.json(); console.log('status', response.status); console.log(data); } main().catch(console.error);
PHP
$ch = curl_init('https://rosterly.quickstopsolution.com/api/event-types'); curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-API-Key: your-api-key-here']); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); $data = json_decode($response, true);
POST /api/event-types

Not available via the API. Admins create event types in Settings.

Required Body Fields:

  • name - Event type name (must be unique)

Optional Body Fields:

  • color - Hex color code (default: #0A9396)
  • icon - Icon name
JavaScript
const response = await fetch('https://rosterly.quickstopsolution.com/api/event-types', { method: 'POST', headers: { 'X-API-Key': 'your-api-key-here', 'Content-Type': 'application/json' }, body: JSON.stringify({ name: 'Workshop', color: '#FF5733', icon: 'calendar' }) }); const data = await response.json();
Node.js (Backend)
// .env // API_BASE_URL=https://rosterly.quickstopsolution.com/api // API_KEY=your-api-key-here const baseUrl = process.env.API_BASE_URL; const apiKey = process.env.API_KEY; async function main() { const response = await fetch(`${baseUrl}/event-types`, { method: 'POST', headers: { 'X-API-Key': apiKey, 'Content-Type': 'application/json' }, body: JSON.stringify({ name: 'Workshop', color: '#FF5733', icon: 'calendar' }) }); const data = await response.json(); console.log('status', response.status); console.log(data); } main().catch(console.error);
PHP
$data = [ 'name' => 'Workshop', 'color' => '#FF5733', 'icon' => 'calendar' ]; $ch = curl_init('https://rosterly.quickstopsolution.com/api/event-types'); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'X-API-Key: your-api-key-here', 'Content-Type: application/json' ]); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); $result = json_decode($response, true);
PUT /api/event-types/:id

Not available via the API. Admins edit event types in Settings.

Optional Body Fields:

  • name - Event type name
  • color - Hex color code
  • icon - Icon name
  • description - Description
  • is_active - Boolean active state
JavaScript
const response = await fetch('https://rosterly.quickstopsolution.com/api/event-types/5', { method: 'PUT', headers: { 'X-API-Key': 'your-api-key-here', 'Content-Type': 'application/json' }, body: JSON.stringify({ name: 'Updated Workshop', color: '#FF5733', icon: 'calendar', description: 'Updated event type description', is_active: true }) }); const data = await response.json();
DELETE /api/event-types/:id

Not available via the API. Admins delete event types in Settings.

JavaScript
const response = await fetch('https://rosterly.quickstopsolution.com/api/event-types/5', { method: 'DELETE', headers: { 'X-API-Key': 'your-api-key-here' } }); const data = await response.json();
GET /api/roster-types

List all active roster types. Creating and editing roster types is only available in Settings to admins.

JavaScript
const response = await fetch('https://rosterly.quickstopsolution.com/api/roster-types', { headers: { 'X-API-Key': 'your-api-key-here' } }); const data = await response.json();
Node.js (Backend)
// .env // API_BASE_URL=https://rosterly.quickstopsolution.com/api // API_KEY=your-api-key-here const baseUrl = process.env.API_BASE_URL; const apiKey = process.env.API_KEY; async function main() { const response = await fetch(`${baseUrl}/roster-types`, { headers: { 'X-API-Key': apiKey } }); const data = await response.json(); console.log('status', response.status); console.log(data); } main().catch(console.error);
PHP
$ch = curl_init('https://rosterly.quickstopsolution.com/api/roster-types'); curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-API-Key: your-api-key-here']); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); $data = json_decode($response, true);
POST /api/roster-types

Not available via the API. Admins create roster types in Settings.

Required Body Fields:

  • name - Roster type name (must be unique)

Optional Body Fields:

  • color - Hex color code (default: #0A9396)
  • description - Description
  • schedule_pattern - Schedule pattern
  • custom_days - Custom days array
JavaScript
const response = await fetch('https://rosterly.quickstopsolution.com/api/roster-types', { method: 'POST', headers: { 'X-API-Key': 'your-api-key-here', 'Content-Type': 'application/json' }, body: JSON.stringify({ name: 'Weekly Roster', color: '#0A9396', description: 'Weekly staff roster', schedule_pattern: 'weekdays', custom_days: ['mon', 'tue', 'wed', 'thu', 'fri'] }) }); const data = await response.json();
Node.js (Backend)
// .env // API_BASE_URL=https://rosterly.quickstopsolution.com/api // API_KEY=your-api-key-here const baseUrl = process.env.API_BASE_URL; const apiKey = process.env.API_KEY; async function main() { const response = await fetch(`${baseUrl}/roster-types`, { method: 'POST', headers: { 'X-API-Key': apiKey, 'Content-Type': 'application/json' }, body: JSON.stringify({ name: 'Weekly Roster', color: '#0A9396', description: 'Weekly staff roster', schedule_pattern: 'weekdays', custom_days: ['mon', 'tue', 'wed', 'thu', 'fri'] }) }); const data = await response.json(); console.log('status', response.status); console.log(data); } main().catch(console.error);
PHP
$data = [ 'name' => 'Weekly Roster', 'color' => '#0A9396', 'description' => 'Weekly staff roster', 'schedule_pattern' => 'weekdays', 'custom_days' => ['mon', 'tue', 'wed', 'thu', 'fri'] ]; $ch = curl_init('https://rosterly.quickstopsolution.com/api/roster-types'); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'X-API-Key: your-api-key-here', 'Content-Type: application/json' ]); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); $result = json_decode($response, true);
PUT /api/roster-types/:id

Not available via the API. Admins edit roster types in Settings.

Optional Body Fields:

  • name - Roster type name
  • color - Hex color code
  • description - Description
  • schedule_pattern - Schedule pattern
  • custom_days - Custom days array
  • is_active - Boolean active state
JavaScript
const response = await fetch('https://rosterly.quickstopsolution.com/api/roster-types/3', { method: 'PUT', headers: { 'X-API-Key': 'your-api-key-here', 'Content-Type': 'application/json' }, body: JSON.stringify({ name: 'Updated Weekly Roster', color: '#0A9396', description: 'Updated weekly staff roster', schedule_pattern: 'custom', custom_days: ['mon', 'wed', 'fri'], is_active: true }) }); const data = await response.json();
DELETE /api/roster-types/:id

Not available via the API. Admins delete roster types in Settings.

JavaScript
const response = await fetch('https://rosterly.quickstopsolution.com/api/roster-types/3', { method: 'DELETE', headers: { 'X-API-Key': 'your-api-key-here' } }); const data = await response.json();
GET /api/shifts

List all active shifts. Creating and editing staff shifts is only available in Settings to admins.

JavaScript
const response = await fetch('https://rosterly.quickstopsolution.com/api/shifts', { headers: { 'X-API-Key': 'your-api-key-here' } }); const data = await response.json();
Node.js (Backend)
// .env // API_BASE_URL=https://rosterly.quickstopsolution.com/api // API_KEY=your-api-key-here const baseUrl = process.env.API_BASE_URL; const apiKey = process.env.API_KEY; async function main() { const response = await fetch(`${baseUrl}/shifts`, { headers: { 'X-API-Key': apiKey } }); const data = await response.json(); console.log('status', response.status); console.log(data); } main().catch(console.error);
PHP
$ch = curl_init('https://rosterly.quickstopsolution.com/api/shifts'); curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-API-Key: your-api-key-here']); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); $data = json_decode($response, true);

Permissions

API keys can have specific permissions to control access. Common permissions include:

  • events:read - Read calendar events
  • events:write - Create/update/delete events
  • rosters:read - Read rosters
  • rosters:write - Create/update rosters
  • users:read - Read users
  • users:write - Create users
  • types:read - Read types
  • types:write - Create/update/delete types and public holidays
  • all - Full access to all endpoints

If an API key doesn't have the required permission, you'll receive a 403 Forbidden response.