curl --request POST \
--url https://{organization}.rescueconsole.com/api/shifts/schedules/import \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"dry_run": true,
"rows": [
{
"name": "Contoso Adoption Day",
"starts_at": "2026-10-03",
"event_kind": "adoption",
"location": "Main Street store"
},
{
"name": "Volunteer orientation",
"starts_at": "2026-10-07T18:00:00Z",
"ends_at": "2026-10-07T20:00:00Z",
"event_kind": "training"
}
]
}
'const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
dry_run: true,
rows: [
{
name: 'Contoso Adoption Day',
starts_at: '2026-10-03',
event_kind: 'adoption',
location: 'Main Street store'
},
{
name: 'Volunteer orientation',
starts_at: '2026-10-07T18:00:00Z',
ends_at: '2026-10-07T20:00:00Z',
event_kind: 'training'
}
]
})
};
fetch('https://{organization}.rescueconsole.com/api/shifts/schedules/import', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://{organization}.rescueconsole.com/api/shifts/schedules/import"
payload = {
"dry_run": True,
"rows": [
{
"name": "Contoso Adoption Day",
"starts_at": "2026-10-03",
"event_kind": "adoption",
"location": "Main Street store"
},
{
"name": "Volunteer orientation",
"starts_at": "2026-10-07T18:00:00Z",
"ends_at": "2026-10-07T20:00:00Z",
"event_kind": "training"
}
]
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text){
"dry_run": true,
"total_rows": 123,
"would_create": 123,
"created": 123,
"errors": [
{
"line": 123,
"message": "<string>"
}
],
"skipped": [
{}
],
"can_detect_duplicates": true,
"all_day_rows": 123,
"preview": [
{}
]
}{
"error": "<string>"
}{
"error": "house_trained must be 1, 0 or null (not assessed)"
}{
"error": "house_trained must be 1, 0 or null (not assessed)"
}Import schedules
Creates schedules from rows, such as the lines of a spreadsheet. Send dry_run: true first to check the rows without creating anything. Every row is checked before any is created, so one bad row creates nothing. Locations are matched by name. Rows are never matched against the schedules you already have: importing the same rows twice creates every schedule twice. Needs write on Shifts.
A coordinator’s: needs write on Shifts AND read on People. A key without read on People is refused (403) with “Only a coordinator can do this: it needs permission to see People.”
curl --request POST \
--url https://{organization}.rescueconsole.com/api/shifts/schedules/import \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"dry_run": true,
"rows": [
{
"name": "Contoso Adoption Day",
"starts_at": "2026-10-03",
"event_kind": "adoption",
"location": "Main Street store"
},
{
"name": "Volunteer orientation",
"starts_at": "2026-10-07T18:00:00Z",
"ends_at": "2026-10-07T20:00:00Z",
"event_kind": "training"
}
]
}
'const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
dry_run: true,
rows: [
{
name: 'Contoso Adoption Day',
starts_at: '2026-10-03',
event_kind: 'adoption',
location: 'Main Street store'
},
{
name: 'Volunteer orientation',
starts_at: '2026-10-07T18:00:00Z',
ends_at: '2026-10-07T20:00:00Z',
event_kind: 'training'
}
]
})
};
fetch('https://{organization}.rescueconsole.com/api/shifts/schedules/import', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://{organization}.rescueconsole.com/api/shifts/schedules/import"
payload = {
"dry_run": True,
"rows": [
{
"name": "Contoso Adoption Day",
"starts_at": "2026-10-03",
"event_kind": "adoption",
"location": "Main Street store"
},
{
"name": "Volunteer orientation",
"starts_at": "2026-10-07T18:00:00Z",
"ends_at": "2026-10-07T20:00:00Z",
"event_kind": "training"
}
]
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text){
"dry_run": true,
"total_rows": 123,
"would_create": 123,
"created": 123,
"errors": [
{
"line": 123,
"message": "<string>"
}
],
"skipped": [
{}
],
"can_detect_duplicates": true,
"all_day_rows": 123,
"preview": [
{}
]
}{
"error": "<string>"
}{
"error": "house_trained must be 1, 0 or null (not assessed)"
}{
"error": "house_trained must be 1, 0 or null (not assessed)"
}Authorizations
An API key from Settings, API keys. It starts with rc_live_.
Body
Response
What was created, or on a dry run what would be. A dry run answers 200 even when rows were refused: read errors.
How many rows passed their own checks.
How many schedules were created. 0 on a dry run, or when any row was refused.
Show child attributes
Show child attributes
Always empty: no row is ever skipped.
Always false: rows are not matched against the schedules you already have.
How many of the rows are all-day schedules.
The first ten rows as they would be created.