Quickstart
This guide shows how to make your first requests to the Reassign REST API. You create a token, read a day, add an event, and then undo the change.
This guide needs a trial or Pro plan. The 7-day free trial includes Reassign Pro.
1. Create a token
Create a personal access token (a "key") in the Reassign app.
- Sign in to the Reassign app.
- Go to Settings › Integrations › API.
- In New key, type a name, for example "My app".
- Choose Read only or Read and write. For this guide, choose Read and write, because step 4 writes an event.
- Click Create key.
- Copy the key from Your new key, and keep it in a safe place.
- Click I saved it.
| Choice | Scopes | Permits |
|---|---|---|
| Read only | events:read | Read calls only |
| Read and write | events:read events:write | Read and write calls |
- The key starts with
rsk_live_. - The app shows the key one time only. If you lose it, revoke it and create a new key.
- Keep the key on your server. Do not put it in browser code.
Refer to Authentication for OAuth 2.0 and for the revoke steps.
2. Test the token
Call GET /me. This call shows who owns the token, the plan, and the scopes. It works on all plans.
Request
curl "https://reassign.app/api/v1/me" \
-H "Authorization: Bearer rsk_live_YOUR_TOKEN"Response
{
"id": "00000000-0000-4000-8000-000000000042",
"email": "user@example.com",
"plan": "pro",
"trialEndsAt": null,
"offer": {
"kind": "entitled"
},
"subscription": {
"provider": "web",
"status": "active",
"currentPeriodEndsAt": "2026-09-13T08:00:00.000Z",
"cancelAtPeriodEnd": false
},
"emailSubscribed": true,
"scopes": [
"events:read",
"events:write"
],
"auth": {
"via": "oauth",
"clientId": "reassign-ios"
}
}planis"trial","pro", or"none".trialEndsAtis an instant, for example"2026-09-30T08:00:00.000Z", on a trial. It isnullon all other plans.emailisnullwhen the account has no email address.- The example shows an OAuth 2.0 token. For a personal access token,
authis{ "via": "pat" }. - If the token is not valid, the API returns HTTP 401. Refer to Errors.
3. Read a day
Call GET /schedule with from and to. For one day, send the same date in the two parameters.
Request
curl "https://reassign.app/api/v1/schedule?from=2026-08-14&to=2026-08-14" \
-H "Authorization: Bearer rsk_live_YOUR_TOKEN"Response
{
"timezone": "Europe/Ljubljana",
"now": "2026-08-14T10:42",
"days": [
{
"date": "2026-08-14",
"events": [
{
"id": "b7f1c2a0-1d2e-4f3a-9b8c-5d6e7f801234",
"start": "2026-08-14T09:00",
"end": "2026-08-14T10:30",
"kind": "blocking",
"name": "Team sync",
"source": "google",
"meeting": {
"url": "https://us02web.zoom.us/j/1234567890",
"label": "Zoom"
},
"location": {
"text": "Room 4, 2nd floor",
"url": "https://www.google.com/maps/search/?api=1&query=Room%204%2C%202nd%20floor"
},
"areaId": "3c9d2a41-6b7e-4f80-9a1b-2c3d4e5f6071",
"activityTypeId": "5e6f7081-92a3-4b4c-8d5e-6f708192a3b4",
"projectId": null,
"priority": 0,
"calendarId": "8a1f0c2e-3b4d-4e5f-9a0b-1c2d3e4f5061",
"mirrorCalendarIds": [
"a1b2c3d4-5e6f-4071-8293-a4b5c6d7e8f9"
]
}
],
"freeSlots": [
{
"start": "2026-08-14T10:45",
"end": "2026-08-15T00:00"
}
],
"loadByArea": [
{
"areaId": "3c9d2a41-6b7e-4f80-9a1b-2c3d4e5f6071",
"minutes": 90,
"eventCount": 1
}
],
"loadByActivityType": [
{
"activityTypeId": "5e6f7081-92a3-4b4c-8d5e-6f708192a3b4",
"minutes": 90,
"eventCount": 1
}
],
"loadByProject": [
{
"projectId": null,
"minutes": 90,
"eventCount": 1
}
]
}
],
"areas": [
{
"id": "3c9d2a41-6b7e-4f80-9a1b-2c3d4e5f6071",
"name": "Work",
"color": "#3b82f6"
}
],
"activityTypes": [
{
"id": "5e6f7081-92a3-4b4c-8d5e-6f708192a3b4",
"name": "Focus",
"pattern": "solid"
}
],
"projects": [],
"userPreferences": {
"conflictPolicy": "propose"
},
"integrations": {
"aiClassify": true,
"defaultCalendarId": "8a1f0c2e-3b4d-4e5f-9a0b-1c2d3e4f5061",
"sources": [
{
"provider": "google",
"account": "user@example.com",
"status": "connected",
"calendars": [
{
"id": "8a1f0c2e-3b4d-4e5f-9a0b-1c2d3e4f5061",
"name": "Work",
"writable": true,
"area": {
"mode": "automatic"
},
"activityType": {
"mode": "automatic"
},
"kind": {
"mode": "automatic"
}
},
{
"id": "a1b2c3d4-5e6f-4071-8293-a4b5c6d7e8f9",
"name": "Team",
"writable": true,
"area": {
"mode": "automatic"
},
"activityType": {
"mode": "automatic"
},
"kind": {
"mode": "automatic"
}
}
]
}
]
},
"backlogCount": 1
}fromandtoare required. Send each as"YYYY-MM-DD". The range can be 366 days or less.dayshas one item for each date. Each day has itseventsand its free time (freeSlots).startandendare local datetimes ("YYYY-MM-DDTHH:MM") in the time zone of the account. The response gives the zone one time, intimezone.- An event ends on a later date when it goes past midnight. Refer to Core concepts.
areaId,activityTypeId, andprojectIdare ids. Find their names in theareas,activityTypes, andprojectslists. The value isnullwhen the event has none.priorityis a whole number from0(none) to4(urgent).nowis the current local datetime of the account.- A query parameter that the route does not know gets HTTP 422 with the error code
validation. - Refer to Scheduling for all fields.
GET /events does not read a day. It is a change poll: it returns the events
that changed after your last poll. Refer to Events.
4. Add an event
Call POST /events with an ops array. Each op is one change. This call needs the events:write scope.
The example has three ops: a create, an update of one occurrence, and a delete of one occurrence. For your first call, send only the create op. Use an areaId and an activityTypeId from step 3, or remove them. Remove calendarId if you have no connected calendar.
Request
curl -X POST "https://reassign.app/api/v1/events" \
-H "Authorization: Bearer rsk_live_YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"ops": [
{
"op": "create",
"name": "Deep work",
"start": "2026-08-14T09:00",
"end": "2026-08-14T10:30",
"areaId": "3c9d2a41-6b7e-4f80-9a1b-2c3d4e5f6071",
"activityTypeId": "5e6f7081-92a3-4b4c-8d5e-6f708192a3b4",
"notes": "Draft the launch post.",
"calendarId": "8a1f0c2e-3b4d-4e5f-9a0b-1c2d3e4f5061"
},
{
"op": "update",
"id": "c4d5e6f7-0819-4a2b-8c3d-4e5f60718293@2026-08-15",
"start": "2026-08-15T16:00"
},
{
"op": "delete",
"id": "c4d5e6f7-0819-4a2b-8c3d-4e5f60718293@2026-08-16"
}
]
}'Response
{
"timezone": "Europe/Ljubljana",
"undoToken": "00000000-0000-4000-8000-000000000001",
"expiresAt": "2026-08-13T09:12:00.000Z",
"results": [
{
"index": 0,
"status": "ok",
"result": {
"created": {
"id": "b7f1c2a0-1d2e-4f3a-9b8c-5d6e7f801234",
"start": "2026-08-14T09:00",
"end": "2026-08-14T10:30",
"kind": "blocking",
"name": "Deep work",
"notes": "Draft the launch post.",
"source": "reassign",
"areaId": "3c9d2a41-6b7e-4f80-9a1b-2c3d4e5f6071",
"activityTypeId": "5e6f7081-92a3-4b4c-8d5e-6f708192a3b4",
"projectId": null,
"priority": 0,
"calendarId": "8a1f0c2e-3b4d-4e5f-9a0b-1c2d3e4f5061"
}
}
},
{
"index": 1,
"status": "ok",
"result": {
"updated": {
"id": "c4d5e6f7-0819-4a2b-8c3d-4e5f60718293@2026-08-15",
"seriesId": "c4d5e6f7-0819-4a2b-8c3d-4e5f60718293",
"originalDate": "2026-08-15",
"start": "2026-08-15T16:00",
"end": "2026-08-15T17:30",
"kind": "blocking",
"name": "Deep work",
"recurrence": "FREQ=DAILY",
"source": "reassign",
"areaId": "3c9d2a41-6b7e-4f80-9a1b-2c3d4e5f6071",
"activityTypeId": "5e6f7081-92a3-4b4c-8d5e-6f708192a3b4",
"projectId": null,
"priority": 0
}
}
},
{
"index": 2,
"status": "ok",
"result": {
"deletedIds": [
"c4d5e6f7-0819-4a2b-8c3d-4e5f60718293@2026-08-16"
]
}
}
]
}resultshas one row for each op, in the same order.results[0].result.createdis the new event.- Keep the
undoToken. You use it in the next step. It expires atexpiresAt. startandendare local datetimes. An event that you write withPOST /eventsis 5 minutes to 168 hours long. The server keeps the exact minute.- The batch is atomic by default. If one op fails, the server applies none of them.
- If the time overlaps a blocking event, the op fails with the error code
conflict. The error row can give up to threenearestSlots. When all failed ops have the codeconflict, the HTTP status is 409. - A bad op, for example an op with an unknown key, becomes an error row with the code
validation. - A token with only
events:readgets HTTP 403 with the error codescope, also when the body is not correct.
Refer to Errors for the rejected batch.
5. Undo the change
Send the undoToken to POST /actions/undo. The API removes the event that you added.
Request
curl -X POST "https://reassign.app/api/v1/actions/undo" \
-H "Authorization: Bearer rsk_live_YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"tokens": [
"00000000-0000-4000-8000-000000000001"
]
}'Response
{
"results": [
{
"index": 0,
"status": "ok",
"result": {
"reverted": 1,
"restored": 1,
"removed": 0,
"voided": 0
}
}
]
}- The example response restores one event (
restoredis 1), for example after a delete. For the undo of a create,removedis 1 andrestoredis 0.revertedis the total of the counts. - An undo token is valid for 30 minutes from the write.
- You can use each token one time only.
- To remove an event after the 30 minutes, send
POST /eventswith{ "op": "delete", "id": "<event id>" }. Refer to Events.
What's next
- Core concepts: the day plan, spans, recurring events, and undo.
- Events: all event fields and calls.
- Connect an AI assistant: use Reassign from an AI assistant through MCP.