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.

1. Create a token

Create a personal access token (a "key") in the Reassign app.

  1. Sign in to the Reassign app.
  2. Go to Settings › Integrations › API.
  3. In New key, type a name, for example "My app".
  4. Choose Read only or Read and write. For this guide, choose Read and write, because step 4 writes an event.
  5. Click Create key.
  6. Copy the key from Your new key, and keep it in a safe place.
  7. Click I saved it.
ChoiceScopesPermits
Read onlyevents:readRead calls only
Read and writeevents:read events:writeRead 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

GET
/api/v1/me
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"
  }
}
  • plan is "trial", "pro", or "none".
  • trialEndsAt is an instant, for example "2026-09-30T08:00:00.000Z", on a trial. It is null on all other plans.
  • email is null when the account has no email address.
  • The example shows an OAuth 2.0 token. For a personal access token, auth is { "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

GET
/api/v1/schedule
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
}
  • from and to are required. Send each as "YYYY-MM-DD". The range can be 366 days or less.
  • days has one item for each date. Each day has its events and its free time (freeSlots).
  • start and end are local datetimes ("YYYY-MM-DDTHH:MM") in the time zone of the account. The response gives the zone one time, in timezone.
  • An event ends on a later date when it goes past midnight. Refer to Core concepts.
  • areaId, activityTypeId, and projectId are ids. Find their names in the areas, activityTypes, and projects lists. The value is null when the event has none.
  • priority is a whole number from 0 (none) to 4 (urgent).
  • now is 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.

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

POST
/api/v1/events
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"
        ]
      }
    }
  ]
}
  • results has one row for each op, in the same order. results[0].result.created is the new event.
  • Keep the undoToken. You use it in the next step. It expires at expiresAt.
  • start and end are local datetimes. An event that you write with POST /events is 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 three nearestSlots. When all failed ops have the code conflict, 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:read gets HTTP 403 with the error code scope, 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

POST
/api/v1/actions/undo
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 (restored is 1), for example after a delete. For the undo of a create, removed is 1 and restored is 0. reverted is 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 /events with { "op": "delete", "id": "<event id>" }. Refer to Events.

What's next