MENU navbar-image

Introduction

Welcome to the Shift Collect API - A RESTful API for managing locker bookings and account access.

This API allows you to manage bookings for lockers at various sites, switch between account contexts, and manage your API tokens.

This API uses Bearer token authentication. Generate API tokens using the POST /v1/tokens/generate endpoint (requires appropriate permissions) and then include the token in the Authorization header as: Bearer {your-token}.

As you scroll, you'll see code examples for working with the API in different programming languages in the dark area to the right (or as part of the content on mobile). You can switch the language used with the tabs at the top right (or from the nav menu at the top left on mobile).

Authenticating requests

To authenticate requests, include an Authorization header with the value "Bearer {YOUR_API_TOKEN}".

All authenticated endpoints are marked with a requires authentication badge in the documentation below.

Generate API tokens using the POST /v1/auth/token endpoint. See the Authentication section below for more information.

Accounts

List the accounts the authenticated user belongs to.

requires authentication

Returns every account that the authenticated user is a member of, including the membership status, join date, and their role assignments scoped to each account.

Example request:

curl --request GET \
    --get "https://api.shiftcollect.com/v1/accounts" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://api.shiftcollect.com/v1/accounts"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://api.shiftcollect.com/v1/accounts';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://api.shiftcollect.com/v1/accounts'
headers = {
  'Authorization': 'Bearer {YOUR_API_TOKEN}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()

Example response (HTTP 200):


{
    "data": [
        {
            "id": "01ARZ3NDEKTSV4RRFFQ69G5FAW",
            "name": "Acme Corp",
            "slug": "acme-corp",
            "role": "owner"
        }
    ]
}
 

Example response (HTTP 401):


{
    "message": "Unauthenticated."
}
 

Request      

GET v1/accounts

Headers

Authorization        

Example: Bearer {YOUR_API_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

Authentication

Generate API token from credentials.

requires authentication

Authenticates a user with email and password and returns an API token. This is useful for programmatic access without needing to login via the SPA first. Requires Admin or Owner role in the specified account.

Example request:

curl --request POST \
    "https://api.shiftcollect.com/v1/auth/token" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"email\": \"[email protected]\",
    \"password\": \"password123\",
    \"account_id\": \"01ARZ3NDEKTSV4RRFFQ69G5FAW\",
    \"token_name\": \"Production API Token\",
    \"expires_at\": \"2025-12-31T23:59:59Z\"
}"
const url = new URL(
    "https://api.shiftcollect.com/v1/auth/token"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "email": "[email protected]",
    "password": "password123",
    "account_id": "01ARZ3NDEKTSV4RRFFQ69G5FAW",
    "token_name": "Production API Token",
    "expires_at": "2025-12-31T23:59:59Z"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://api.shiftcollect.com/v1/auth/token';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'email' => '[email protected]',
            'password' => 'password123',
            'account_id' => '01ARZ3NDEKTSV4RRFFQ69G5FAW',
            'token_name' => 'Production API Token',
            'expires_at' => '2025-12-31T23:59:59Z',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://api.shiftcollect.com/v1/auth/token'
payload = {
    "email": "[email protected]",
    "password": "password123",
    "account_id": "01ARZ3NDEKTSV4RRFFQ69G5FAW",
    "token_name": "Production API Token",
    "expires_at": "2025-12-31T23:59:59Z"
}
headers = {
  'Authorization': 'Bearer {YOUR_API_TOKEN}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers, json=payload)
response.json()

Example response (HTTP 200):


{
    "token": "1|abcdefghijklmnopqrstuvwxyz1234567890",
    "token_name": "Production API Token",
    "account_id": "01ARZ3NDEKTSV4RRFFQ69G5FAW",
    "user": {
        "id": "01ARZ3NDEKTSV4RRFFQ69G5FAW",
        "name": "John Doe",
        "email": "[email protected]"
    },
    "abilities": [
        "*"
    ],
    "expires_at": "2025-12-31T23:59:59.000000Z",
    "created_at": "2025-01-01T00:00:00.000000Z",
    "message": "API token generated successfully"
}
 

Example response (HTTP 403):


{
    "message": "This action is unauthorized. Only admins and owners can generate API tokens."
}
 

Example response (HTTP 403):


{
    "message": "User does not belong to the specified account."
}
 

Example response (HTTP 422):


{
    "message": "The given data was invalid.",
    "errors": {
        "email": [
            "The email field is required."
        ],
        "password": [
            "The password field is required."
        ],
        "account_id": [
            "The account id field is required."
        ],
        "expires_at": [
            "The expires at must be a date after now."
        ]
    }
}
 

Example response (HTTP 422):


{
    "message": "The given data was invalid.",
    "errors": {
        "email": [
            "These credentials do not match our records."
        ]
    }
}
 

Request      

POST v1/auth/token

Headers

Authorization        

Example: Bearer {YOUR_API_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

email   string     

User email address Example: [email protected]

password   string     

User password Example: password123

account_id   string     

Account ID (ULID) for which to generate the token Example: 01ARZ3NDEKTSV4RRFFQ69G5FAW

token_name   string  optional    

Name for the token (optional, defaults to "API Token") Example: Production API Token

expires_at   string  optional    

Expiration date and time (ISO 8601). Must be in the future Example: 2025-12-31T23:59:59Z

Availability

Get site availability for a date range.

requires authentication

Returns sites with available lockers for the entire requested time window. Sites are returned if they have at least one available locker AND have an active timeslot configured for the current account (or a global timeslot if no account-specific timeslot exists). Each site includes an array of available lockers with their dimensions and status. Note: Booking details are never included in the response to prevent data leakage between accounts.

Example request:

curl --request GET \
    --get "https://api.shiftcollect.com/v1/availability?from=2025-01-15T09%3A00%3A00Z&to=2025-01-20T17%3A00%3A00Z&site_id=01ARZ3NDEKTSV4RRFFQ69G5FAA&per_page=20&latitude=50.376289&longitude=-4.143841" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://api.shiftcollect.com/v1/availability"
);

const params = {
    "from": "2025-01-15T09:00:00Z",
    "to": "2025-01-20T17:00:00Z",
    "site_id": "01ARZ3NDEKTSV4RRFFQ69G5FAA",
    "per_page": "20",
    "latitude": "50.376289",
    "longitude": "-4.143841",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_API_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://api.shiftcollect.com/v1/availability';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'from' => '2025-01-15T09:00:00Z',
            'to' => '2025-01-20T17:00:00Z',
            'site_id' => '01ARZ3NDEKTSV4RRFFQ69G5FAA',
            'per_page' => '20',
            'latitude' => '50.376289',
            'longitude' => '-4.143841',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://api.shiftcollect.com/v1/availability'
params = {
  'from': '2025-01-15T09:00:00Z',
  'to': '2025-01-20T17:00:00Z',
  'site_id': '01ARZ3NDEKTSV4RRFFQ69G5FAA',
  'per_page': '20',
  'latitude': '50.376289',
  'longitude': '-4.143841',
}
headers = {
  'Authorization': 'Bearer {YOUR_API_TOKEN}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()

Example response (HTTP 200):


{
    "data": [
        {
            "id": "01kbqqhc6nrfnmxdcydsr1scnr",
            "name": "Bailey Inc Site",
            "address_line_1": "764 Ernser Parkways Suite 841",
            "address_line_2": null,
            "city": "Myaport",
            "postcode": "02042",
            "county": null,
            "country": "United Kingdom",
            "latitude": -25.59289,
            "longitude": -175.353288,
            "access_instructions": null,
            "special_notes": "Qui commodi incidunt iure odit. Et modi ipsum nostrum omnis autem et consequatur. Dolores enim non facere tempora.",
            "height_restriction": null,
            "current_bookings": 0,
            "available_lockers": 0,
            "distance": null,
            "lockers": [
                {
                    "name": "T98",
                    "cabinet": "Train Station",
                    "status": "active",
                    "dimensions": {
                        "height": 36.98,
                        "width": 76.4,
                        "depth": 22.11,
                        "volume": 62466.76392
                    }
                }
            ]
        },
        {
            "id": "01kbqqhc7nvymfs0x5vzeh71mj",
            "name": "Dibbert Inc Site",
            "address_line_1": "12438 Mariela Forest Suite 382",
            "address_line_2": null,
            "city": "Margarettaside",
            "postcode": "57468",
            "county": "Kendraburgh",
            "country": "United Kingdom",
            "latitude": -38.654828,
            "longitude": 95.151071,
            "access_instructions": "Rem est esse sint aut. Sunt suscipit doloribus fugiat ut aut deserunt et. Neque recusandae et ipsam dolorem et ut dicta.",
            "special_notes": null,
            "height_restriction": null,
            "current_bookings": 0,
            "available_lockers": 0,
            "distance": null,
            "lockers": [
                {
                    "name": "E15",
                    "cabinet": "Residential Complex",
                    "status": "unavailable",
                    "dimensions": {
                        "height": 37.89,
                        "width": 40.72,
                        "depth": 25.26,
                        "volume": 38973.169008
                    }
                }
            ]
        }
    ],
    "links": {
        "first": "/?page=1",
        "last": "/?page=1",
        "prev": null,
        "next": null
    },
    "meta": {
        "current_page": 1,
        "from": 1,
        "last_page": 1,
        "links": [
            {
                "url": null,
                "label": "« Previous",
                "page": null,
                "active": false
            },
            {
                "url": "/?page=1",
                "label": "1",
                "page": 1,
                "active": true
            },
            {
                "url": null,
                "label": "Next »",
                "page": null,
                "active": false
            }
        ],
        "path": "/",
        "per_page": 10,
        "to": 2,
        "total": 2
    }
}
 

Example response (HTTP 401):


{
    "message": "Unauthenticated."
}
 

Example response (HTTP 422):


{
    "message": "The given data was invalid.",
    "errors": {
        "from": [
            "The from field is required."
        ],
        "to": [
            "The to must be a date after from."
        ]
    }
}
 

Request      

GET v1/availability

Headers

Authorization        

Example: Bearer {YOUR_API_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

from   string     

Start date and time (ISO 8601). Must be a valid date. Example: 2025-01-15T09:00:00Z

to   string     

End date and time (ISO 8601). Must be after from. Must be a valid date. Must be a date after from. Example: 2025-01-20T17:00:00Z

site_id   string  optional    

Filter by specific site ID. Returns only the selected site with available lockers. Example: 01ARZ3NDEKTSV4RRFFQ69G5FAA

per_page   integer  optional    

Number of sites per page (max 100). Must be at least 1. Must not be greater than 100. Example: 20

latitude   number  optional    

Latitude for sorting results by distance (must include longitude). Results will be sorted by distance ascending (closest first). This field is required when longitude is present. Must be between -90 and 90. Example: 50.376289

longitude   number  optional    

Longitude for sorting results by distance (must include latitude). Results will be sorted by distance ascending (closest first). This field is required when latitude is present. Must be between -180 and 180. Example: -4.143841

Booking Tracking

Track a booking by reference ID (public endpoint).

requires authentication

Allows public users to track their booking using reference ID and email or phone verification. At least one of email or phone must be provided.

Example request:

curl --request POST \
    "https://api.shiftcollect.com/v1/tracking/booking" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"reference_id\": \"BK691B2516D28B2\",
    \"email\": \"[email protected]\",
    \"phone\": \"+447700900123\"
}"
const url = new URL(
    "https://api.shiftcollect.com/v1/tracking/booking"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "reference_id": "BK691B2516D28B2",
    "email": "[email protected]",
    "phone": "+447700900123"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://api.shiftcollect.com/v1/tracking/booking';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'reference_id' => 'BK691B2516D28B2',
            'email' => '[email protected]',
            'phone' => '+447700900123',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://api.shiftcollect.com/v1/tracking/booking'
payload = {
    "reference_id": "BK691B2516D28B2",
    "email": "[email protected]",
    "phone": "+447700900123"
}
headers = {
  'Authorization': 'Bearer {YOUR_API_TOKEN}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers, json=payload)
response.json()

Example response (HTTP 200):


{
    "data": {
        "reference_id": "BK65A3F2E1",
        "status": "confirmed",
        "locker_assignments": [
            {
                "locker_id": "01ARZ3NDEKTSV4RRFFQ69G5FAV",
                "locker_name": "A1-01",
                "cabinet": {
                    "id": "01ARZ3NDEKTSV4RRFFQ69G5FAU",
                    "name": "Cabinet A1",
                    "status": "active"
                },
                "starts_at": "2025-01-15T09:00:00.000000Z",
                "ends_at": "2025-01-20T17:00:00.000000Z"
            }
        ],
        "items_count": 3,
        "items": [
            {
                "name": "Item 1",
                "quantity": 1
            }
        ]
    }
}
 

Example response (HTTP 404):


{
    "message": "Booking not found"
}
 

Example response (HTTP 422):


{
    "message": "The given data was invalid."
}
 

Request      

POST v1/tracking/booking

Headers

Authorization        

Example: Bearer {YOUR_API_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

reference_id   string     

The booking reference ID Example: BK691B2516D28B2

email   string  optional    

Customer email address for verification (required if phone is not provided) Example: [email protected]

phone   string  optional    

Customer phone number for verification (required if email is not provided) Example: +447700900123

Track a booking by ID (authenticated endpoint).

requires authentication

Allows authenticated accounts to track their bookings.

Example request:

curl --request POST \
    "https://api.shiftcollect.com/v1/tracking/01kbqqg3fc5m2ww91r8s6642mp/tracking" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://api.shiftcollect.com/v1/tracking/01kbqqg3fc5m2ww91r8s6642mp/tracking"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "POST",
    headers,
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://api.shiftcollect.com/v1/tracking/01kbqqg3fc5m2ww91r8s6642mp/tracking';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://api.shiftcollect.com/v1/tracking/01kbqqg3fc5m2ww91r8s6642mp/tracking'
headers = {
  'Authorization': 'Bearer {YOUR_API_TOKEN}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers)
response.json()

Example response (HTTP 200):


{
    "data": {
        "reference_id": "BK65A3F2E1",
        "status": "confirmed",
        "locker_assignments": [
            {
                "locker_id": "01ARZ3NDEKTSV4RRFFQ69G5FAV",
                "locker_name": "A1-01",
                "cabinet": {
                    "id": "01ARZ3NDEKTSV4RRFFQ69G5FAU",
                    "name": "Cabinet A1",
                    "status": "active"
                },
                "starts_at": "2025-01-15T09:00:00.000000Z",
                "ends_at": "2025-01-20T17:00:00.000000Z"
            }
        ],
        "items_count": 3,
        "items": [
            {
                "name": "Item 1",
                "quantity": 1
            }
        ]
    }
}
 

Example response (HTTP 401):


{
    "message": "Unauthenticated."
}
 

Example response (HTTP 404):


{
    "message": "Booking not found"
}
 

Request      

POST v1/tracking/{booking_id}/tracking

Headers

Authorization        

Example: Bearer {YOUR_API_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

booking_id   string     

The ID of the booking. Example: 01kbqqg3fc5m2ww91r8s6642mp

Bookings

Display a listing of bookings.

requires authentication

Returns a paginated list of bookings for the current account context. Bookings can be filtered by status.

Example request:

curl --request GET \
    --get "https://api.shiftcollect.com/v1/bookings?status=confirmed&per_page=20&page=1" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://api.shiftcollect.com/v1/bookings"
);

const params = {
    "status": "confirmed",
    "per_page": "20",
    "page": "1",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_API_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://api.shiftcollect.com/v1/bookings';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'status' => 'confirmed',
            'per_page' => '20',
            'page' => '1',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://api.shiftcollect.com/v1/bookings'
params = {
  'status': 'confirmed',
  'per_page': '20',
  'page': '1',
}
headers = {
  'Authorization': 'Bearer {YOUR_API_TOKEN}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()

Example response (HTTP 200):


{
    "data": [
        {
            "id": "01ARZ3NDEKTSV4RRFFQ69G5FAV",
            "reference_id": "BK-2025-001",
            "created_at": "2025-01-01T00:00:00.000000Z",
            "updated_at": "2025-01-01T00:00:00.000000Z",
            "status": {
                "id": "01ARZ3NDEKTSV4RRFFQ69G5FAX",
                "name": "confirmed"
            },
            "user": {
                "id": "01ARZ3NDEKTSV4RRFFQ69G5FAY",
                "name": "John Doe"
            },
            "account": {
                "id": "01ARZ3NDEKTSV4RRFFQ69G5FAZ",
                "name": "Acme Corp"
            },
            "service_product": {
                "id": "01ARZ3NDEKTSV4RRFFQ69G5FAX",
                "name": "DC to Locker"
            },
            "items": [],
            "status_history": []
        }
    ],
    "pagination": {
        "current_page": 1,
        "per_page": 15,
        "total": 100,
        "last_page": 7,
        "from": 1,
        "to": 15,
        "has_more_pages": true
    },
    "links": {
        "first": "http://example.com/api/v1/bookings?page=1",
        "last": "http://example.com/api/v1/bookings?page=7",
        "prev": null,
        "next": "http://example.com/api/v1/bookings?page=2"
    }
}
 

Example response (HTTP 400):


{
    "message": "No account context set"
}
 

Example response (HTTP 401):


{
    "message": "Unauthenticated."
}
 

Example response (HTTP 403):


{
    "message": "This action is unauthorized."
}
 

Request      

GET v1/bookings

Headers

Authorization        

Example: Bearer {YOUR_API_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

status   string  optional    

Filter bookings by status Example: confirmed

per_page   integer  optional    

Number of items per page (max 100) Example: 20

page   integer  optional    

Page number Example: 1

Store a newly created booking.

requires authentication

Creates a new booking associated with the current account context and the authenticated user. The booking will be processed according to the specified service product.

Example request:

curl --request POST \
    "https://api.shiftcollect.com/v1/bookings" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"service_product_id\": \"01ARZ3NDEKTSV4RRFFQ69G5FAX\",
    \"status_id\": \"01ARZ3NDEKTSV4RRFFQ69G5FAX\",
    \"items\": [
        \"architecto\"
    ],
    \"authorisation_group_ids\": [
        \"01ARZ3NDEKTSV4RRFFQ69G5FAY\"
    ],
    \"locker_user_ids\": [
        \"01ARZ3NDEKTSV4RRFFQ69G5FAZ\"
    ]
}"
const url = new URL(
    "https://api.shiftcollect.com/v1/bookings"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "service_product_id": "01ARZ3NDEKTSV4RRFFQ69G5FAX",
    "status_id": "01ARZ3NDEKTSV4RRFFQ69G5FAX",
    "items": [
        "architecto"
    ],
    "authorisation_group_ids": [
        "01ARZ3NDEKTSV4RRFFQ69G5FAY"
    ],
    "locker_user_ids": [
        "01ARZ3NDEKTSV4RRFFQ69G5FAZ"
    ]
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://api.shiftcollect.com/v1/bookings';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'service_product_id' => '01ARZ3NDEKTSV4RRFFQ69G5FAX',
            'status_id' => '01ARZ3NDEKTSV4RRFFQ69G5FAX',
            'items' => [
                'architecto',
            ],
            'authorisation_group_ids' => [
                '01ARZ3NDEKTSV4RRFFQ69G5FAY',
            ],
            'locker_user_ids' => [
                '01ARZ3NDEKTSV4RRFFQ69G5FAZ',
            ],
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://api.shiftcollect.com/v1/bookings'
payload = {
    "service_product_id": "01ARZ3NDEKTSV4RRFFQ69G5FAX",
    "status_id": "01ARZ3NDEKTSV4RRFFQ69G5FAX",
    "items": [
        "architecto"
    ],
    "authorisation_group_ids": [
        "01ARZ3NDEKTSV4RRFFQ69G5FAY"
    ],
    "locker_user_ids": [
        "01ARZ3NDEKTSV4RRFFQ69G5FAZ"
    ]
}
headers = {
  'Authorization': 'Bearer {YOUR_API_TOKEN}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers, json=payload)
response.json()

Example response (HTTP 201):


{
    "message": "Booking created successfully",
    "data": {
        "id": "01ARZ3NDEKTSV4RRFFQ69G5FAV",
        "reference_id": "BK-2025-001",
        "created_at": "2025-01-01T00:00:00.000000Z",
        "updated_at": "2025-01-01T00:00:00.000000Z",
        "status": {
            "id": "01ARZ3NDEKTSV4RRFFQ69G5FAX",
            "name": "confirmed"
        },
        "user": {
            "id": "01ARZ3NDEKTSV4RRFFQ69G5FAY",
            "name": "John Doe"
        },
        "account": {
            "id": "01ARZ3NDEKTSV4RRFFQ69G5FAZ",
            "name": "Acme Corp"
        },
        "service_product": {
            "id": "01ARZ3NDEKTSV4RRFFQ69G5FAX",
            "name": "DC to Locker",
            "description": "Transport from Dispatch Centre to Locker"
        },
        "items": [],
        "status_history": []
    }
}
 

Example response (HTTP 400):


{
    "message": "No account context set"
}
 

Example response (HTTP 401):


{
    "message": "Unauthenticated."
}
 

Example response (HTTP 403):


{
    "message": "This action is unauthorized."
}
 

Example response (HTTP 422):


{
    "message": "The given data was invalid.",
    "errors": {
        "service_product_id": [
            "The selected service product id is invalid."
        ],
        "items.0.name": [
            "The items.0.name field is required when items is present."
        ]
    }
}
 

Request      

POST v1/bookings

Headers

Authorization        

Example: Bearer {YOUR_API_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

service_product_id   string  optional    

The ID of the service product that defines how the booking should be processed Example: 01ARZ3NDEKTSV4RRFFQ69G5FAX

status_id   string  optional    

The ID of the booking status Example: 01ARZ3NDEKTSV4RRFFQ69G5FAX

items   string[]  optional    

Array of items to be stored in the booking

name   string  optional    

Name of the item Example: Box of documents

description   string  optional    

Description of the item. Max 1000 characters Example: Important business documents

quantity   integer  optional    

Must be at least 1. Example: 26

weight   number  optional    

Weight in kilograms. Must be >= 0 Example: 5.5

height   number  optional    

Height in centimeters. Must be >= 0 Example: 30

width   number  optional    

Width in centimeters. Must be >= 0 Example: 40

depth   number  optional    

Depth in centimeters. Must be >= 0 Example: 50

authorisation_group_ids   string[]  optional    

Array of authorisation group IDs

locker_user_ids   string[]  optional    

Array of locker user IDs

Display the specified booking.

requires authentication

Returns detailed information about a specific booking. The booking must belong to the current account context.

Example request:

curl --request GET \
    --get "https://api.shiftcollect.com/v1/bookings/01kbqqg3fc5m2ww91r8s6642mp" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://api.shiftcollect.com/v1/bookings/01kbqqg3fc5m2ww91r8s6642mp"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://api.shiftcollect.com/v1/bookings/01kbqqg3fc5m2ww91r8s6642mp';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://api.shiftcollect.com/v1/bookings/01kbqqg3fc5m2ww91r8s6642mp'
headers = {
  'Authorization': 'Bearer {YOUR_API_TOKEN}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()

Example response (HTTP 200):


{
    "data": {
        "id": "01ARZ3NDEKTSV4RRFFQ69G5FAV",
        "reference_id": "BK-2025-001",
        "created_at": "2025-01-01T00:00:00.000000Z",
        "updated_at": "2025-01-01T00:00:00.000000Z",
        "status": {
            "id": "01ARZ3NDEKTSV4RRFFQ69G5FAX",
            "name": "confirmed"
        },
        "user": {
            "id": "01ARZ3NDEKTSV4RRFFQ69G5FAY",
            "name": "John Doe"
        },
        "account": {
            "id": "01ARZ3NDEKTSV4RRFFQ69G5FAZ",
            "name": "Acme Corp"
        },
        "service_product": {
            "id": "01ARZ3NDEKTSV4RRFFQ69G5FAX",
            "name": "DC to Locker",
            "description": "Transport from Dispatch Centre to Locker"
        },
        "items": [
            {
                "id": "01ARZ3NDEKTSV4RRFFQ69G5FAB",
                "name": "Box of documents",
                "description": "Important business documents",
                "weight": 5.5,
                "height": 30,
                "width": 40,
                "depth": 50,
                "volume": 60000,
                "created_at": "2025-01-01T00:00:00.000000Z",
                "updated_at": "2025-01-01T00:00:00.000000Z"
            }
        ],
        "status_history": []
    }
}
 

Example response (HTTP 400):


{
    "message": "No account context set"
}
 

Example response (HTTP 401):


{
    "message": "Unauthenticated."
}
 

Example response (HTTP 404):


{
    "message": "Booking not found"
}
 

Request      

GET v1/bookings/{booking_id}

Headers

Authorization        

Example: Bearer {YOUR_API_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

booking_id   string     

The ID of the booking. Example: 01kbqqg3fc5m2ww91r8s6642mp

booking   string     

The ID of the booking Example: 01ARZ3NDEKTSV4RRFFQ69G5FAV

Cancel the specified booking.

requires authentication

Cancels a booking, removing it from active status. The booking must belong to the current account context.

Example request:

curl --request DELETE \
    "https://api.shiftcollect.com/v1/bookings/01kbqqg3fc5m2ww91r8s6642mp" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://api.shiftcollect.com/v1/bookings/01kbqqg3fc5m2ww91r8s6642mp"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://api.shiftcollect.com/v1/bookings/01kbqqg3fc5m2ww91r8s6642mp';
$response = $client->delete(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://api.shiftcollect.com/v1/bookings/01kbqqg3fc5m2ww91r8s6642mp'
headers = {
  'Authorization': 'Bearer {YOUR_API_TOKEN}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('DELETE', url, headers=headers)
response.json()

Example response (HTTP 200):


{
    "message": "Booking cancelled",
    "booking": {
        "id": "01ARZ3NDEKTSV4RRFFQ69G5FAV",
        "reference_id": "BK-2025-001",
        "created_at": "2025-01-01T00:00:00.000000Z",
        "updated_at": "2025-01-01T00:00:00.000000Z",
        "status": {
            "id": "01ARZ3NDEKTSV4RRFFQ69G5FAX",
            "name": "cancelled"
        },
        "user": null,
        "account": null,
        "items": [],
        "status_history": []
    }
}
 

Example response (HTTP 400):


{
    "message": "No account context set"
}
 

Example response (HTTP 401):


{
    "message": "Unauthenticated."
}
 

Example response (HTTP 404):


{
    "message": "Booking not found"
}
 

Request      

DELETE v1/bookings/{booking_id}

Headers

Authorization        

Example: Bearer {YOUR_API_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

booking_id   string     

The ID of the booking. Example: 01kbqqg3fc5m2ww91r8s6642mp

id   string     

The ID of the booking to cancel Example: 01ARZ3NDEKTSV4RRFFQ69G5FAV

Add or update booking authorisations.

requires authentication

Adds or extends authorisation groups and locker users for an existing booking. The booking must belong to the current account context.

Example request:

curl --request POST \
    "https://api.shiftcollect.com/v1/bookings/01kbqqg3fc5m2ww91r8s6642mp/authorisation" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"authorisation_group_ids\": [
        \"01ARZ3NDEKTSV4RRFFQ69G5FAY\"
    ],
    \"locker_user_ids\": [
        \"01ARZ3NDEKTSV4RRFFQ69G5FAZ\"
    ]
}"
const url = new URL(
    "https://api.shiftcollect.com/v1/bookings/01kbqqg3fc5m2ww91r8s6642mp/authorisation"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "authorisation_group_ids": [
        "01ARZ3NDEKTSV4RRFFQ69G5FAY"
    ],
    "locker_user_ids": [
        "01ARZ3NDEKTSV4RRFFQ69G5FAZ"
    ]
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://api.shiftcollect.com/v1/bookings/01kbqqg3fc5m2ww91r8s6642mp/authorisation';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'authorisation_group_ids' => [
                '01ARZ3NDEKTSV4RRFFQ69G5FAY',
            ],
            'locker_user_ids' => [
                '01ARZ3NDEKTSV4RRFFQ69G5FAZ',
            ],
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://api.shiftcollect.com/v1/bookings/01kbqqg3fc5m2ww91r8s6642mp/authorisation'
payload = {
    "authorisation_group_ids": [
        "01ARZ3NDEKTSV4RRFFQ69G5FAY"
    ],
    "locker_user_ids": [
        "01ARZ3NDEKTSV4RRFFQ69G5FAZ"
    ]
}
headers = {
  'Authorization': 'Bearer {YOUR_API_TOKEN}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers, json=payload)
response.json()

Example response (HTTP 200):


{
    "message": "Authorisations updated"
}
 

Example response (HTTP 400):


{
    "message": "No account context set"
}
 

Example response (HTTP 401):


{
    "message": "Unauthenticated."
}
 

Example response (HTTP 404):


{
    "message": "Booking not found"
}
 

Example response (HTTP 422):


{
    "message": "The given data was invalid.",
    "errors": {
        "authorisation_group_ids.0": [
            "The selected authorisation group ids.0 is invalid."
        ]
    }
}
 

Request      

POST v1/bookings/{booking_id}/authorisation

Headers

Authorization        

Example: Bearer {YOUR_API_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

booking_id   string     

The ID of the booking. Example: 01kbqqg3fc5m2ww91r8s6642mp

booking   string     

The ID of the booking Example: 01ARZ3NDEKTSV4RRFFQ69G5FAV

Body Parameters

authorisation_group_ids   string[]  optional    

Array of authorisation group IDs to add

locker_user_ids   string[]  optional    

Array of locker user IDs to add

Generate lock codes for booking lockers.

requires authentication

Generates access codes for all lockers associated with a booking. The booking must belong to the current account context.

Example request:

curl --request POST \
    "https://api.shiftcollect.com/v1/bookings/01kbqqg3fc5m2ww91r8s6642mp/generate-codes" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://api.shiftcollect.com/v1/bookings/01kbqqg3fc5m2ww91r8s6642mp/generate-codes"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "POST",
    headers,
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://api.shiftcollect.com/v1/bookings/01kbqqg3fc5m2ww91r8s6642mp/generate-codes';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://api.shiftcollect.com/v1/bookings/01kbqqg3fc5m2ww91r8s6642mp/generate-codes'
headers = {
  'Authorization': 'Bearer {YOUR_API_TOKEN}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers)
response.json()

Example response (HTTP 200):


{
    "message": "Lock codes generated",
    "codes": [
        {
            "locker_id": "01ARZ3NDEKTSV4RRFFQ69G5FAC",
            "code": "1234"
        }
    ]
}
 

Example response (HTTP 400):


{
    "message": "No account context set"
}
 

Example response (HTTP 401):


{
    "message": "Unauthenticated."
}
 

Example response (HTTP 403):


{
    "message": "This action is unauthorized."
}
 

Example response (HTTP 404):


{
    "message": "Booking not found"
}
 

Request      

POST v1/bookings/{booking_id}/generate-codes

Headers

Authorization        

Example: Bearer {YOUR_API_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

booking_id   string     

The ID of the booking. Example: 01kbqqg3fc5m2ww91r8s6642mp

booking   string     

The ID of the booking Example: 01ARZ3NDEKTSV4RRFFQ69G5FAV

Cabinets

Display a listing of cabinets.

requires authentication

Returns a list of cabinets with optional filtering by status, version, layout, maintenance needs, or location. Cabinets include their lockers and arrangements.

Example request:

curl --request GET \
    --get "https://api.shiftcollect.com/v1/cabinets?status=active&version=v2.0&layout=standard&needs_maintenance=1&latitude=51.5074&longitude=-0.1278&radius=10" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://api.shiftcollect.com/v1/cabinets"
);

const params = {
    "status": "active",
    "version": "v2.0",
    "layout": "standard",
    "needs_maintenance": "1",
    "latitude": "51.5074",
    "longitude": "-0.1278",
    "radius": "10",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_API_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://api.shiftcollect.com/v1/cabinets';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'status' => 'active',
            'version' => 'v2.0',
            'layout' => 'standard',
            'needs_maintenance' => '1',
            'latitude' => '51.5074',
            'longitude' => '-0.1278',
            'radius' => '10',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://api.shiftcollect.com/v1/cabinets'
params = {
  'status': 'active',
  'version': 'v2.0',
  'layout': 'standard',
  'needs_maintenance': '1',
  'latitude': '51.5074',
  'longitude': '-0.1278',
  'radius': '10',
}
headers = {
  'Authorization': 'Bearer {YOUR_API_TOKEN}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()

Example response (HTTP 200):


{
    "data": [
        {
            "id": "01ARZ3NDEKTSV4RRFFQ69G5FAA",
            "name": "Cabinet A1",
            "site_id": "01ARZ3NDEKTSV4RRFFQ69G5FAW",
            "status": {
                "id": "01ARZ3NDEKTSV4RRFFQ69G5FAB",
                "name": "active"
            },
            "version": {
                "id": "01ARZ3NDEKTSV4RRFFQ69G5FAC",
                "version": "v2.0",
                "layout": "standard"
            },
            "lockers": []
        }
    ]
}
 

Example response (HTTP 401):


{
    "message": "Unauthenticated."
}
 

Example response (HTTP 403):


{
    "message": "This action is unauthorized."
}
 

Request      

GET v1/cabinets

Headers

Authorization        

Example: Bearer {YOUR_API_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

status   string  optional    

Filter by cabinet status name Example: active

version   string  optional    

Filter by cabinet version Example: v2.0

layout   string  optional    

Filter by cabinet layout Example: standard

needs_maintenance   boolean  optional    

Filter cabinets that need maintenance Example: true

latitude   number  optional    

Latitude for location-based search (must include longitude and radius) Example: 51.5074

longitude   number  optional    

Longitude for location-based search (must include latitude and radius) Example: -0.1278

radius   number  optional    

Radius in kilometers for location-based search (must include latitude and longitude) Example: 10

Display the specified cabinet.

requires authentication

Returns detailed information about a specific cabinet, including its lockers and arrangements.

Example request:

curl --request GET \
    --get "https://api.shiftcollect.com/v1/cabinets/01ARZ3NDEKTSV4RRFFQ69G5FAA" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://api.shiftcollect.com/v1/cabinets/01ARZ3NDEKTSV4RRFFQ69G5FAA"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://api.shiftcollect.com/v1/cabinets/01ARZ3NDEKTSV4RRFFQ69G5FAA';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://api.shiftcollect.com/v1/cabinets/01ARZ3NDEKTSV4RRFFQ69G5FAA'
headers = {
  'Authorization': 'Bearer {YOUR_API_TOKEN}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()

Example response (HTTP 200):


{
    "data": {
        "id": "01ARZ3NDEKTSV4RRFFQ69G5FAA",
        "name": "Cabinet A1",
        "status": "active",
        "total_active_lockers": 10,
        "total_available_lockers": 5,
        "site": {
            "site_id": "01ARZ3NDEKTSV4RRFFQ69G5FAW",
            "name": "Downtown Location"
        },
        "lockers": []
    }
}
 

Example response (HTTP 401):


{
    "message": "Unauthenticated."
}
 

Example response (HTTP 403):


{
    "message": "This action is unauthorized."
}
 

Example response (HTTP 404):


{
    "message": "Cabinet not found"
}
 

Request      

GET v1/cabinets/{id}

Headers

Authorization        

Example: Bearer {YOUR_API_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

id   string     

The ID of the cabinet Example: 01ARZ3NDEKTSV4RRFFQ69G5FAA

Collection Schedules

Store a newly created collection schedule.

requires authentication

Example request:

curl --request POST \
    "https://api.shiftcollect.com/v1/collection-schedules" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"despatch_centre_id\": \"01ARZ3NDEKTSV4RRFFQ69G5FAW\",
    \"name\": \"Weekday Morning Collection\",
    \"description\": \"Eius et animi quos velit et.\",
    \"collection_start_time\": \"08:00:00\",
    \"collection_end_time\": \"10:00:00\",
    \"days_of_week\": [
        0,
        1,
        2,
        3,
        4
    ],
    \"effective_from\": \"2025-01-01T00:00:00Z\",
    \"effective_until\": \"2025-12-31T23:59:59Z\",
    \"is_active\": true
}"
const url = new URL(
    "https://api.shiftcollect.com/v1/collection-schedules"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "despatch_centre_id": "01ARZ3NDEKTSV4RRFFQ69G5FAW",
    "name": "Weekday Morning Collection",
    "description": "Eius et animi quos velit et.",
    "collection_start_time": "08:00:00",
    "collection_end_time": "10:00:00",
    "days_of_week": [
        0,
        1,
        2,
        3,
        4
    ],
    "effective_from": "2025-01-01T00:00:00Z",
    "effective_until": "2025-12-31T23:59:59Z",
    "is_active": true
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://api.shiftcollect.com/v1/collection-schedules';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'despatch_centre_id' => '01ARZ3NDEKTSV4RRFFQ69G5FAW',
            'name' => 'Weekday Morning Collection',
            'description' => 'Eius et animi quos velit et.',
            'collection_start_time' => '08:00:00',
            'collection_end_time' => '10:00:00',
            'days_of_week' => [
                0,
                1,
                2,
                3,
                4,
            ],
            'effective_from' => '2025-01-01T00:00:00Z',
            'effective_until' => '2025-12-31T23:59:59Z',
            'is_active' => true,
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://api.shiftcollect.com/v1/collection-schedules'
payload = {
    "despatch_centre_id": "01ARZ3NDEKTSV4RRFFQ69G5FAW",
    "name": "Weekday Morning Collection",
    "description": "Eius et animi quos velit et.",
    "collection_start_time": "08:00:00",
    "collection_end_time": "10:00:00",
    "days_of_week": [
        0,
        1,
        2,
        3,
        4
    ],
    "effective_from": "2025-01-01T00:00:00Z",
    "effective_until": "2025-12-31T23:59:59Z",
    "is_active": true
}
headers = {
  'Authorization': 'Bearer {YOUR_API_TOKEN}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers, json=payload)
response.json()

Example response (HTTP 201):


{
    "message": "Collection schedule created successfully",
    "data": {
        "id": "01ARZ3NDEKTSV4RRFFQ69G5FAW",
        "despatch_centre_id": "01ARZ3NDEKTSV4RRFFQ69G5FAX",
        "name": "Weekday Morning Collection",
        "collection_start_time": "08:00:00",
        "collection_end_time": "10:00:00",
        "days_of_week": [
            0,
            1,
            2,
            3,
            4
        ],
        "is_active": true
    }
}
 

Example response (HTTP 400):


{
    "message": "No account context set"
}
 

Example response (HTTP 401):


{
    "message": "Unauthenticated."
}
 

Example response (HTTP 403):


{
    "message": "This action is unauthorized."
}
 

Request      

POST v1/collection-schedules

Headers

Authorization        

Example: Bearer {YOUR_API_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

despatch_centre_id   string     

The ID of the despatch centre Example: 01ARZ3NDEKTSV4RRFFQ69G5FAW

name   string     

Name of the collection schedule Example: Weekday Morning Collection

description   string  optional    

Description of the collection schedule Example: Eius et animi quos velit et.

collection_start_time   string     

Collection start time (HH:mm:ss) Example: 08:00:00

collection_end_time   string     

Collection end time (HH:mm:ss) Example: 10:00:00

days_of_week   string[]     

Array of day numbers (0=Monday, 6=Sunday)

*   integer     

Day number (0-6) Example: 16

effective_from   string  optional    

Effective from date (ISO 8601) Example: 2025-01-01T00:00:00Z

effective_until   string  optional    

Effective until date (ISO 8601) Example: 2025-12-31T23:59:59Z

is_active   boolean  optional    

Whether the schedule is active Example: true

Despatch Centres

Display a listing of despatch centres.

requires authentication

Returns a paginated list of despatch centres for the current account.

Example request:

curl --request GET \
    --get "https://api.shiftcollect.com/v1/despatch-centres?per_page=20&page=1" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://api.shiftcollect.com/v1/despatch-centres"
);

const params = {
    "per_page": "20",
    "page": "1",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_API_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://api.shiftcollect.com/v1/despatch-centres';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'per_page' => '20',
            'page' => '1',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://api.shiftcollect.com/v1/despatch-centres'
params = {
  'per_page': '20',
  'page': '1',
}
headers = {
  'Authorization': 'Bearer {YOUR_API_TOKEN}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()

Example response (HTTP 200):


{
    "data": [
        {
            "id": "01ARZ3NDEKTSV4RRFFQ69G5FAW",
            "account_id": "01ARZ3NDEKTSV4RRFFQ69G5FAX",
            "name": "Main Warehouse",
            "description": "Primary despatch centre",
            "address_id": "01ARZ3NDEKTSV4RRFFQ69G5FAY",
            "address": {
                "id": "01ARZ3NDEKTSV4RRFFQ69G5FAY",
                "line_1": "123 Industrial Way",
                "line_2": null,
                "city": "London",
                "postcode": "SW1A 1AA",
                "latitude": 51.5074,
                "longitude": -0.1278
            },
            "access_instructions": "Enter through main gate",
            "special_notes": null,
            "contact_phone": "+44 20 1234 5678",
            "contact_email": "[email protected]",
            "is_active": true
        }
    ],
    "pagination": {
        "current_page": 1,
        "per_page": 50,
        "total": 10,
        "last_page": 1
    }
}
 

Example response (HTTP 400):


{
    "message": "No account context set"
}
 

Example response (HTTP 401):


{
    "message": "Unauthenticated."
}
 

Example response (HTTP 403):


{
    "message": "This action is unauthorized."
}
 

Request      

GET v1/despatch-centres

Headers

Authorization        

Example: Bearer {YOUR_API_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

per_page   integer  optional    

Number of items per page (max 100) Example: 20

page   integer  optional    

Page number Example: 1

Display the specified despatch centre.

requires authentication

Example request:

curl --request GET \
    --get "https://api.shiftcollect.com/v1/despatch-centres/01ARZ3NDEKTSV4RRFFQ69G5FAW" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://api.shiftcollect.com/v1/despatch-centres/01ARZ3NDEKTSV4RRFFQ69G5FAW"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://api.shiftcollect.com/v1/despatch-centres/01ARZ3NDEKTSV4RRFFQ69G5FAW';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://api.shiftcollect.com/v1/despatch-centres/01ARZ3NDEKTSV4RRFFQ69G5FAW'
headers = {
  'Authorization': 'Bearer {YOUR_API_TOKEN}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()

Example response (HTTP 200):


{
    "data": {
        "id": "01ARZ3NDEKTSV4RRFFQ69G5FAW",
        "account_id": "01ARZ3NDEKTSV4RRFFQ69G5FAX",
        "name": "Main Warehouse",
        "description": "Primary despatch centre",
        "address_id": "01ARZ3NDEKTSV4RRFFQ69G5FAY",
        "address": {
            "id": "01ARZ3NDEKTSV4RRFFQ69G5FAY",
            "line_1": "123 Industrial Way",
            "line_2": null,
            "city": "London",
            "postcode": "SW1A 1AA",
            "latitude": 51.5074,
            "longitude": -0.1278
        },
        "access_instructions": "Enter through main gate",
        "special_notes": null,
        "contact_phone": "+44 20 1234 5678",
        "contact_email": "[email protected]",
        "is_active": true
    }
}
 

Example response (HTTP 401):


{
    "message": "Unauthenticated."
}
 

Example response (HTTP 403):


{
    "message": "This action is unauthorized."
}
 

Example response (HTTP 404):


{
    "message": "Despatch centre not found"
}
 

Request      

GET v1/despatch-centres/{id}

Headers

Authorization        

Example: Bearer {YOUR_API_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

id   string     

The ID of the despatch centre Example: 01ARZ3NDEKTSV4RRFFQ69G5FAW

Store a newly created despatch centre.

requires authentication

Example request:

curl --request POST \
    "https://api.shiftcollect.com/v1/despatch-centres" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"name\": \"Main Warehouse\",
    \"description\": \"Primary despatch centre\",
    \"address_line_1\": \"123 Industrial Way\",
    \"address_line_2\": \"architecto\",
    \"city\": \"London\",
    \"postcode\": \"SW1A 1AA\",
    \"county\": \"Greater London\",
    \"country\": \"United Kingdom\",
    \"latitude\": 51.5074,
    \"longitude\": -0.1278,
    \"access_instructions\": \"architecto\",
    \"special_notes\": \"architecto\",
    \"contact_phone\": \"architecto\",
    \"contact_email\": \"[email protected]\",
    \"is_active\": true
}"
const url = new URL(
    "https://api.shiftcollect.com/v1/despatch-centres"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "name": "Main Warehouse",
    "description": "Primary despatch centre",
    "address_line_1": "123 Industrial Way",
    "address_line_2": "architecto",
    "city": "London",
    "postcode": "SW1A 1AA",
    "county": "Greater London",
    "country": "United Kingdom",
    "latitude": 51.5074,
    "longitude": -0.1278,
    "access_instructions": "architecto",
    "special_notes": "architecto",
    "contact_phone": "architecto",
    "contact_email": "[email protected]",
    "is_active": true
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://api.shiftcollect.com/v1/despatch-centres';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'name' => 'Main Warehouse',
            'description' => 'Primary despatch centre',
            'address_line_1' => '123 Industrial Way',
            'address_line_2' => 'architecto',
            'city' => 'London',
            'postcode' => 'SW1A 1AA',
            'county' => 'Greater London',
            'country' => 'United Kingdom',
            'latitude' => 51.5074,
            'longitude' => -0.1278,
            'access_instructions' => 'architecto',
            'special_notes' => 'architecto',
            'contact_phone' => 'architecto',
            'contact_email' => '[email protected]',
            'is_active' => true,
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://api.shiftcollect.com/v1/despatch-centres'
payload = {
    "name": "Main Warehouse",
    "description": "Primary despatch centre",
    "address_line_1": "123 Industrial Way",
    "address_line_2": "architecto",
    "city": "London",
    "postcode": "SW1A 1AA",
    "county": "Greater London",
    "country": "United Kingdom",
    "latitude": 51.5074,
    "longitude": -0.1278,
    "access_instructions": "architecto",
    "special_notes": "architecto",
    "contact_phone": "architecto",
    "contact_email": "[email protected]",
    "is_active": true
}
headers = {
  'Authorization': 'Bearer {YOUR_API_TOKEN}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers, json=payload)
response.json()

Example response (HTTP 201):


{
    "message": "Despatch centre created successfully",
    "data": {
        "id": "01ARZ3NDEKTSV4RRFFQ69G5FAW",
        "name": "Main Warehouse"
    }
}
 

Example response (HTTP 400):


{
    "message": "No account context set"
}
 

Example response (HTTP 401):


{
    "message": "Unauthenticated."
}
 

Example response (HTTP 403):


{
    "message": "This action is unauthorized."
}
 

Request      

POST v1/despatch-centres

Headers

Authorization        

Example: Bearer {YOUR_API_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

name   string     

Name of the despatch centre Example: Main Warehouse

description   string  optional    

Description of the despatch centre Example: Primary despatch centre

address_line_1   string     

First line of address Example: 123 Industrial Way

address_line_2   string  optional    

Second line of address Example: architecto

city   string  optional    

City Example: London

postcode   string     

Postcode Example: SW1A 1AA

county   string  optional    

County Example: Greater London

country   string  optional    

Country Example: United Kingdom

latitude   number  optional    

Latitude Example: 51.5074

longitude   number  optional    

Longitude Example: -0.1278

access_instructions   string  optional    

Access instructions Example: architecto

special_notes   string  optional    

Special notes Example: architecto

contact_phone   string  optional    

Contact phone number Example: architecto

contact_email   string  optional    

Contact email address Example: [email protected]

is_active   boolean  optional    

Whether the despatch centre is active Example: true

Update the specified despatch centre.

requires authentication

Example request:

curl --request PUT \
    "https://api.shiftcollect.com/v1/despatch-centres/01ARZ3NDEKTSV4RRFFQ69G5FAW" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"name\": \"b\",
    \"description\": \"Et animi quos velit et fugiat.\",
    \"address_line_1\": \"d\",
    \"address_line_2\": \"l\",
    \"city\": \"j\",
    \"postcode\": \"nikhwaykcmyuwpwl\",
    \"county\": \"v\",
    \"country\": \"q\",
    \"latitude\": -90,
    \"longitude\": -179,
    \"access_instructions\": \"s\",
    \"special_notes\": \"i\",
    \"contact_phone\": \"t\",
    \"contact_email\": \"[email protected]\",
    \"is_active\": true
}"
const url = new URL(
    "https://api.shiftcollect.com/v1/despatch-centres/01ARZ3NDEKTSV4RRFFQ69G5FAW"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "name": "b",
    "description": "Et animi quos velit et fugiat.",
    "address_line_1": "d",
    "address_line_2": "l",
    "city": "j",
    "postcode": "nikhwaykcmyuwpwl",
    "county": "v",
    "country": "q",
    "latitude": -90,
    "longitude": -179,
    "access_instructions": "s",
    "special_notes": "i",
    "contact_phone": "t",
    "contact_email": "[email protected]",
    "is_active": true
};

fetch(url, {
    method: "PUT",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://api.shiftcollect.com/v1/despatch-centres/01ARZ3NDEKTSV4RRFFQ69G5FAW';
$response = $client->put(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'name' => 'b',
            'description' => 'Et animi quos velit et fugiat.',
            'address_line_1' => 'd',
            'address_line_2' => 'l',
            'city' => 'j',
            'postcode' => 'nikhwaykcmyuwpwl',
            'county' => 'v',
            'country' => 'q',
            'latitude' => -90,
            'longitude' => -179,
            'access_instructions' => 's',
            'special_notes' => 'i',
            'contact_phone' => 't',
            'contact_email' => '[email protected]',
            'is_active' => true,
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://api.shiftcollect.com/v1/despatch-centres/01ARZ3NDEKTSV4RRFFQ69G5FAW'
payload = {
    "name": "b",
    "description": "Et animi quos velit et fugiat.",
    "address_line_1": "d",
    "address_line_2": "l",
    "city": "j",
    "postcode": "nikhwaykcmyuwpwl",
    "county": "v",
    "country": "q",
    "latitude": -90,
    "longitude": -179,
    "access_instructions": "s",
    "special_notes": "i",
    "contact_phone": "t",
    "contact_email": "[email protected]",
    "is_active": true
}
headers = {
  'Authorization': 'Bearer {YOUR_API_TOKEN}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('PUT', url, headers=headers, json=payload)
response.json()

Example response (HTTP 200):


{
    "message": "Despatch centre updated successfully",
    "data": {
        "id": "01ARZ3NDEKTSV4RRFFQ69G5FAW",
        "name": "Main Warehouse"
    }
}
 

Example response (HTTP 401):


{
    "message": "Unauthenticated."
}
 

Example response (HTTP 403):


{
    "message": "This action is unauthorized."
}
 

Example response (HTTP 404):


{
    "message": "Despatch centre not found"
}
 

Request      

PUT v1/despatch-centres/{id}

Headers

Authorization        

Example: Bearer {YOUR_API_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

id   string     

The ID of the despatch centre Example: 01ARZ3NDEKTSV4RRFFQ69G5FAW

Body Parameters

name   string  optional    

Must not be greater than 255 characters. Example: b

description   string  optional    

Must not be greater than 1000 characters. Example: Et animi quos velit et fugiat.

address_line_1   string  optional    

Must not be greater than 255 characters. Example: d

address_line_2   string  optional    

Must not be greater than 255 characters. Example: l

city   string  optional    

Must not be greater than 255 characters. Example: j

postcode   string  optional    

Must not be greater than 20 characters. Example: nikhwaykcmyuwpwl

county   string  optional    

Must not be greater than 255 characters. Example: v

country   string  optional    

Must not be greater than 255 characters. Example: q

latitude   number  optional    

Must be between -90 and 90. Example: -90

longitude   number  optional    

Must be between -180 and 180. Example: -179

access_instructions   string  optional    

Must not be greater than 1000 characters. Example: s

special_notes   string  optional    

Must not be greater than 1000 characters. Example: i

contact_phone   string  optional    

Must not be greater than 50 characters. Example: t

contact_email   string  optional    

Must be a valid email address. Must not be greater than 255 characters. Example: [email protected]

is_active   boolean  optional    

Example: true

Remove the specified despatch centre.

requires authentication

Example request:

curl --request DELETE \
    "https://api.shiftcollect.com/v1/despatch-centres/01ARZ3NDEKTSV4RRFFQ69G5FAW" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://api.shiftcollect.com/v1/despatch-centres/01ARZ3NDEKTSV4RRFFQ69G5FAW"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://api.shiftcollect.com/v1/despatch-centres/01ARZ3NDEKTSV4RRFFQ69G5FAW';
$response = $client->delete(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://api.shiftcollect.com/v1/despatch-centres/01ARZ3NDEKTSV4RRFFQ69G5FAW'
headers = {
  'Authorization': 'Bearer {YOUR_API_TOKEN}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('DELETE', url, headers=headers)
response.json()

Example response (HTTP 200):


{
    "message": "Despatch centre deleted successfully"
}
 

Example response (HTTP 401):


{
    "message": "Unauthenticated."
}
 

Example response (HTTP 403):


{
    "message": "This action is unauthorized."
}
 

Example response (HTTP 404):


{
    "message": "Despatch centre not found"
}
 

Request      

DELETE v1/despatch-centres/{id}

Headers

Authorization        

Example: Bearer {YOUR_API_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

id   string     

The ID of the despatch centre Example: 01ARZ3NDEKTSV4RRFFQ69G5FAW

Sites

Display a listing of sites with search and pagination.

requires authentication

Returns a paginated list of active sites. Supports location-based filtering to find sites within a specified radius of coordinates.

Example request:

curl --request GET \
    --get "https://api.shiftcollect.com/v1/sites?latitude=51.5074&longitude=-0.1278&radius=10&per_page=20&page=1" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://api.shiftcollect.com/v1/sites"
);

const params = {
    "latitude": "51.5074",
    "longitude": "-0.1278",
    "radius": "10",
    "per_page": "20",
    "page": "1",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_API_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://api.shiftcollect.com/v1/sites';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'latitude' => '51.5074',
            'longitude' => '-0.1278',
            'radius' => '10',
            'per_page' => '20',
            'page' => '1',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://api.shiftcollect.com/v1/sites'
params = {
  'latitude': '51.5074',
  'longitude': '-0.1278',
  'radius': '10',
  'per_page': '20',
  'page': '1',
}
headers = {
  'Authorization': 'Bearer {YOUR_API_TOKEN}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()

Example response (HTTP 200):


{
    "data": [
        {
            "id": "01ARZ3NDEKTSV4RRFFQ69G5FAW",
            "name": "Downtown Location",
            "address_line_1": "123 Main St",
            "address_line_2": null,
            "city": "London",
            "postcode": "SW1A 1AA",
            "county": "Greater London",
            "country": "United Kingdom",
            "latitude": 51.5074,
            "longitude": -0.1278,
            "access_instructions": "Enter through main entrance",
            "special_notes": null,
            "height_restriction": 2.5,
            "contact_phone": "+44 20 1234 5678",
            "contact_email": "[email protected]",
            "is_active": true,
            "distance": {
                "km": 2.5,
                "mi": 1.55
            },
            "site_access_codes": [
                {
                    "name": "Customer access code 1",
                    "code": "AB12CD34"
                }
            ]
        }
    ],
    "pagination": {
        "current_page": 1,
        "per_page": 50,
        "total": 25,
        "last_page": 1,
        "from": 1,
        "to": 25,
        "has_more_pages": false
    },
    "links": {
        "first": "http://example.com/api/v1/sites?page=1",
        "last": "http://example.com/api/v1/sites?page=1",
        "prev": null,
        "next": null
    }
}
 

Example response (HTTP 401):


{
    "message": "Unauthenticated."
}
 

Example response (HTTP 403):


{
    "message": "This action is unauthorized."
}
 

Request      

GET v1/sites

Headers

Authorization        

Example: Bearer {YOUR_API_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

latitude   number  optional    

Latitude for location-based search (must include longitude and radius) Example: 51.5074

longitude   number  optional    

Longitude for location-based search (must include latitude and radius) Example: -0.1278

radius   number  optional    

Radius in kilometers for location-based search (must include latitude and longitude) Example: 10

per_page   integer  optional    

Number of items per page (max 100) Example: 20

page   integer  optional    

Page number Example: 1

Display the specified site.

requires authentication

Returns detailed information about a specific site.

Example request:

curl --request GET \
    --get "https://api.shiftcollect.com/v1/sites/01ARZ3NDEKTSV4RRFFQ69G5FAW" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://api.shiftcollect.com/v1/sites/01ARZ3NDEKTSV4RRFFQ69G5FAW"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://api.shiftcollect.com/v1/sites/01ARZ3NDEKTSV4RRFFQ69G5FAW';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://api.shiftcollect.com/v1/sites/01ARZ3NDEKTSV4RRFFQ69G5FAW'
headers = {
  'Authorization': 'Bearer {YOUR_API_TOKEN}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()

Example response (HTTP 200):


{
    "data": {
        "id": "01ARZ3NDEKTSV4RRFFQ69G5FAW",
        "name": "Downtown Location",
        "address_line_1": "123 Main St",
        "address_line_2": null,
        "city": "London",
        "postcode": "SW1A 1AA",
        "county": "Greater London",
        "country": "United Kingdom",
        "latitude": 51.5074,
        "longitude": -0.1278,
        "access_instructions": "Enter through main entrance",
        "special_notes": null,
        "height_restriction": 2.5,
        "contact_phone": "+44 20 1234 5678",
        "contact_email": "[email protected]",
        "is_active": true,
        "site_access_codes": [
            {
                "id": "01ARZ3NDEKTSV4RRFFQ69G5FBA",
                "name": "Customer access code 1",
                "code": "AB12CD34",
                "type": {
                    "id": "01ARZ3NDEKTSV4RRFFQ69G5FBB",
                    "name": "customer"
                }
            }
        ]
    }
}
 

Example response (HTTP 401):


{
    "message": "Unauthenticated."
}
 

Example response (HTTP 403):


{
    "message": "This action is unauthorized."
}
 

Example response (HTTP 404):


{
    "message": "Site not found"
}
 

Request      

GET v1/sites/{id}

Headers

Authorization        

Example: Bearer {YOUR_API_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

id   string     

The ID of the site Example: 01ARZ3NDEKTSV4RRFFQ69G5FAW

Token Management

Generate API token for account.

requires authentication

Creates a new API token for the authenticated user in the current account context. Requires Admin or Owner role in the current account.

Example request:

curl --request POST \
    "https://api.shiftcollect.com/v1/tokens/generate" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"token_name\": \"Production API Token\",
    \"expires_at\": \"2025-12-31T23:59:59Z\"
}"
const url = new URL(
    "https://api.shiftcollect.com/v1/tokens/generate"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "token_name": "Production API Token",
    "expires_at": "2025-12-31T23:59:59Z"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://api.shiftcollect.com/v1/tokens/generate';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'token_name' => 'Production API Token',
            'expires_at' => '2025-12-31T23:59:59Z',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://api.shiftcollect.com/v1/tokens/generate'
payload = {
    "token_name": "Production API Token",
    "expires_at": "2025-12-31T23:59:59Z"
}
headers = {
  'Authorization': 'Bearer {YOUR_API_TOKEN}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers, json=payload)
response.json()

Example response (HTTP 201):


{
    "token": "1|abcdefghijklmnopqrstuvwxyz1234567890",
    "token_name": "Production API Token",
    "account_id": "01ARZ3NDEKTSV4RRFFQ69G5FAW",
    "abilities": [
        "*"
    ],
    "expires_at": "2025-12-31T23:59:59.000000Z",
    "created_at": "2025-01-01T00:00:00.000000Z",
    "message": "API token generated successfully"
}
 

Example response (HTTP 400):


{
    "message": "No account context set"
}
 

Example response (HTTP 401):


{
    "message": "Unauthenticated."
}
 

Example response (HTTP 403):


{
    "message": "This action is unauthorized."
}
 

Example response (HTTP 422):


{
    "message": "The given data was invalid.",
    "errors": {
        "token_name": [
            "The token name field is required."
        ],
        "expires_at": [
            "The expires at must be a date after now."
        ]
    }
}
 

Request      

POST v1/tokens/generate

Headers

Authorization        

Example: Bearer {YOUR_API_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

token_name   string     

Name for the token Example: Production API Token

expires_at   string  optional    

Expiration date and time (ISO 8601). Must be in the future Example: 2025-12-31T23:59:59Z

List API tokens for account.

requires authentication

Returns all API tokens for the authenticated user in the current account context. Requires Admin or Owner role in the current account.

Example request:

curl --request GET \
    --get "https://api.shiftcollect.com/v1/tokens?search=Production" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://api.shiftcollect.com/v1/tokens"
);

const params = {
    "search": "Production",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_API_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://api.shiftcollect.com/v1/tokens';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'search' => 'Production',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://api.shiftcollect.com/v1/tokens'
params = {
  'search': 'Production',
}
headers = {
  'Authorization': 'Bearer {YOUR_API_TOKEN}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()

Example response (HTTP 200):


{
    "tokens": [
        {
            "id": 1,
            "name": "Production API Token",
            "abilities": [
                "*"
            ],
            "last_used_at": "2025-01-15T10:30:00.000000Z",
            "created_at": "2025-01-01T00:00:00.000000Z",
            "expires_at": "2025-12-31T23:59:59.000000Z"
        }
    ],
    "account_id": "01ARZ3NDEKTSV4RRFFQ69G5FAW",
    "total": 1
}
 

Example response (HTTP 400):


{
    "message": "No account context set"
}
 

Example response (HTTP 401):


{
    "message": "Unauthenticated."
}
 

Example response (HTTP 403):


{
    "message": "This action is unauthorized."
}
 

Request      

GET v1/tokens

Headers

Authorization        

Example: Bearer {YOUR_API_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

search   string  optional    

Search tokens by name Example: Production

Revoke a specific API token.

requires authentication

Revokes a single API token by ID. Requires Admin or Owner role in the current account.

Example request:

curl --request DELETE \
    "https://api.shiftcollect.com/v1/tokens/1" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://api.shiftcollect.com/v1/tokens/1"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://api.shiftcollect.com/v1/tokens/1';
$response = $client->delete(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://api.shiftcollect.com/v1/tokens/1'
headers = {
  'Authorization': 'Bearer {YOUR_API_TOKEN}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('DELETE', url, headers=headers)
response.json()

Example response (HTTP 200):


{
    "message": "API token revoked successfully"
}
 

Example response (HTTP 400):


{
    "message": "No account context set"
}
 

Example response (HTTP 401):


{
    "message": "Unauthenticated."
}
 

Example response (HTTP 403):


{
    "message": "This action is unauthorized."
}
 

Example response (HTTP 404):


{
    "message": "Token not found"
}
 

Request      

DELETE v1/tokens/{tokenId}

Headers

Authorization        

Example: Bearer {YOUR_API_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

tokenId   string     

The ID of the token to revoke Example: 1

Revoke all API tokens for account.

requires authentication

Revokes all API tokens for the authenticated user in the current account context. Requires Admin or Owner role in the current account.

Example request:

curl --request DELETE \
    "https://api.shiftcollect.com/v1/tokens" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://api.shiftcollect.com/v1/tokens"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://api.shiftcollect.com/v1/tokens';
$response = $client->delete(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://api.shiftcollect.com/v1/tokens'
headers = {
  'Authorization': 'Bearer {YOUR_API_TOKEN}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('DELETE', url, headers=headers)
response.json()

Example response (HTTP 200):


{
    "message": "All API tokens revoked successfully",
    "deleted_count": 5
}
 

Example response (HTTP 400):


{
    "message": "No account context set"
}
 

Example response (HTTP 401):


{
    "message": "Unauthenticated."
}
 

Example response (HTTP 403):


{
    "message": "This action is unauthorized."
}
 

Request      

DELETE v1/tokens

Headers

Authorization        

Example: Bearer {YOUR_API_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

User Management

Get the current authenticated user

requires authentication

Returns information about the currently authenticated user, including all accounts they belong to, their roles in each account, and the current account context.

Example request:

curl --request GET \
    --get "https://api.shiftcollect.com/v1/user" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://api.shiftcollect.com/v1/user"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://api.shiftcollect.com/v1/user';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://api.shiftcollect.com/v1/user'
headers = {
  'Authorization': 'Bearer {YOUR_API_TOKEN}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()

Example response (HTTP 200):


{
    "data": {
        "id": "01ARZ3NDEKTSV4RRFFQ69G5FAV",
        "name": "John Doe",
        "email": "[email protected]",
        "created_at": "2025-01-01T00:00:00.000000Z",
        "is_active": true,
        "accounts": [
            {
                "id": "01ARZ3NDEKTSV4RRFFQ69G5FAW",
                "name": "Acme Corp",
                "slug": "acme-corp",
                "is_active": true,
                "joined_at": "2025-01-01T00:00:00.000000Z",
                "role": "owner"
            }
        ],
        "current_account": {
            "id": "01ARZ3NDEKTSV4RRFFQ69G5FAW",
            "name": "Acme Corp",
            "slug": "acme-corp",
            "role": "owner"
        },
        "role": "owner",
        "permissions": [
            "bookings.view",
            "account.manage_users"
        ]
    }
}
 

Example response (HTTP 401):


{
    "message": "User not authenticated"
}
 

Request      

GET v1/user

Headers

Authorization        

Example: Bearer {YOUR_API_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

Response

Response Fields

id   string     

The user's unique identifier (ID)

name   string     

The user's full name

email   string     

The user's email address

created_at   string     

When the user account was created

is_active   boolean     

Whether the user account is active

accounts   string[][]     

Array of all accounts the user belongs to, with their roles

id        

Account identifier (ID)

name        

Account name

slug        

Account URL slug

is_active        

Whether the user is active in this account

joined_at        

When the user joined this account

role        

Role name for this account

current_account   object     

The currently active account context

id        

Account identifier (ID)

name        

Account name

slug        

Account URL slug

role        

Role name for current account

role   string     

Role name for the current account context

permissions   string[]     

Array of permission names for the current account context