Categories
Categories label the events of a day plan and the Inbox. Reassign has two types of category: areas and activity types. Projects group events and Inbox blocks. Use these endpoints to read and change all three.
The machine-readable spec of all public endpoints: openapi.json.
Areas and activity types
| Category | What it is | How Reassign shows it |
|---|---|---|
| Area | A category or group, for example "Work" or "Health". | A color |
| Activity type | A tag, for example "Focus". | A fill pattern |
- An event links to a maximum of one area and a maximum of one activity type.
- Some areas and activity types are shared defaults. For these,
isGlobalistrue.isGlobalis always present. - You can delete a shared default. The delete hides it for your account only. Refer to Delete a shared default.
- When you update a shared default, Reassign makes your own copy (a fork). The fork gets a new ID. Its
overridesIdis the ID of the shared default. - If you already have a fork of that default, Reassign updates the fork. It does not make a second fork.
- A fork takes the links of your events, Inbox items, trackers, and projects from the shared default. A calendar default stays on the shared default, and reads show the fork.
- A write that names a shared default that you forked uses your fork. This applies to
areaIdandactivityTypeIdon events, the backlog, and scheduling, and toreassignToon a delete. The result gives the fork id. - Names are unique for each type of category, among the categories that you can see. To compare names, Reassign ignores uppercase and lowercase, accents, and extra spaces. A create or a rename to a name that is already in use fails with
conflict(409).
Use the IDs from this page in the areaId and activityTypeId fields of events and of the backlog. Use a project ID in the projectId field of events and of the backlog.
The area model
coloris a hex color with 6 lowercase digits,#rrggbb, for example#3b82f6.overridesIdis always present. It isnullwhen the area is not a fork.orderis the display order, always a whole number. Refer to Display order.
- Name
id- Type
- string, required
- Description
- Name
name- Type
- string, required
- Description
- Name
order- Type
- integer, required
- Description
- Name
isGlobal- Type
- boolean, required
- Description
- Name
overridesId- Type
- string | null, required
- Description
- Name
color- Type
- string, required
- Description
The activity type model
patternis the fill pattern. The values use snake_case, for examplehatch_randhatch_l.overridesIdis always present. It isnullwhen the activity type is not a fork.orderis the display order, always a whole number. Refer to Display order.
- Name
id- Type
- string, required
- Description
- Name
name- Type
- string, required
- Description
- Name
order- Type
- integer, required
- Description
- Name
isGlobal- Type
- boolean, required
- Description
- Name
overridesId- Type
- string | null, required
- Description
- Name
pattern- Type
- "solid" | "hatch_r" | "hatch_l" | "cross" | "horizontal" | "vertical" | "grid" | "dots" | "waves" | "chevron", required
- Description
Projects
A project is a named goal, for example "Launch". It can be in one area, or in no area. Events and Inbox blocks link to a project with projectId.
- A project is your own. Reassign has no shared default project, and a project has no fork.
- A project links to a maximum of one area. It takes its color from that area.
- A synced task list or a Linear project can feed a project. Its Inbox items link to that project.
- A sync links a list or a Linear project to the live project with the same name, in any area. Thus one project can take lists from two or more task apps or accounts.
- When no live project has the name of a task list, the sync makes a new project in the default area of the list. A task list always feeds a project.
- To give a list or a Linear project its own project, use the
splitop. To move a Linear project to a different project, use therelinkop. - An archived project stays in the list, with
archived: true. It takes no new links, but its links stay.
The project model
areaIdis the parent area. It isnullwhen the project has no area.archivedistruefor an archived project.publishCalendarIdis the task list that gets a new Inbox block of the project. It isnullwhen there is no such list. Refer to Source of a new block.orderis the display order. It can be any number, not only a whole number.
- Name
id- Type
- string, required
- Description
- Name
name- Type
- string, required
- Description
- Name
areaId- Type
- string | null, required
- Description
- Name
order- Type
- number, required
- Description
- Name
archived- Type
- boolean, required
- Description
- Name
publishCalendarId- Type
- string | null, required
- Description
The task list that a new Inbox item of the project is created in; null is off.
Display order
order is a whole number that sets the position of an area or an activity type in the lists of the app. Areas and activity types each have their own order.
| Rule | Details |
|---|---|
| Sort | Reassign sorts the list from the lowest order to the highest. GET /api/v1/categories returns each list in this sequence. |
| Value on a create | A create op does not take order. Reassign sets order to the number of categories of that type that you can see before the create. When no other category has this order or a higher one, the new category goes to the end of the list. |
| Value on an update | An update op can set order to a whole number. Reassign writes only that category. It does not change the order of the other categories. Two categories can have the same order. |
| Shared default | An update with order on a shared default makes a fork, as for a change of name. The fork gets the new order. |
To move a category, send an update op with a new order for each category that must move.
Projects have their own order, with these differences:
- A project
createputs the project at the end: itsorderis 1 more than the highestorderof your projects. - A project
updatecan setorderto any number, for example1.5. - The
projectslist is inorder. Two projects with the sameorderare in the sequence that you made them.
List the categories
Get all the areas and activity types that the account can see, and all the projects of the account. When the account has a fork of a shared default, the list shows only the fork.
- The token must have the
events:reador theevents:writescope. - The account needs Reassign Pro. The 7-day free trial includes it.
- This endpoint takes no query parameter. An unknown query parameter returns
422with the codevalidation. areasholds area objects.activityTypesholds activity type objects.projectsholds project objects.projectsincludes the archived projects.- Each list is in display order: the lowest
orderfirst.
Response fields
- Name
areas- Type
- object[], required
- Description
6 fields
- Name
id- Type
- string, required
- Description
- Name
name- Type
- string, required
- Description
- Name
order- Type
- integer, required
- Description
- Name
isGlobal- Type
- boolean, required
- Description
- Name
overridesId- Type
- string | null, required
- Description
- Name
color- Type
- string, required
- Description
- Name
activityTypes- Type
- object[], required
- Description
6 fields
- Name
id- Type
- string, required
- Description
- Name
name- Type
- string, required
- Description
- Name
order- Type
- integer, required
- Description
- Name
isGlobal- Type
- boolean, required
- Description
- Name
overridesId- Type
- string | null, required
- Description
- Name
pattern- Type
- "solid" | "hatch_r" | "hatch_l" | "cross" | "horizontal" | "vertical" | "grid" | "dots" | "waves" | "chevron", required
- Description
- Name
projects- Type
- object[], required
- Description
6 fields
- Name
id- Type
- string, required
- Description
- Name
name- Type
- string, required
- Description
- Name
areaId- Type
- string | null, required
- Description
- Name
order- Type
- number, required
- Description
- Name
archived- Type
- boolean, required
- Description
- Name
publishCalendarId- Type
- string | null, required
- Description
The task list that a new Inbox item of the project is created in; null is off.
Responses
| Status | Codes | Meaning |
|---|---|---|
200 | — | Success. |
401 | unauthorized | No Bearer token and no session cookie, or the token is invalid, expired, or revoked. The response carries a WWW-Authenticate challenge that points at the protected-resource metadata. |
403 | permissionscope | A token without events:read or events:write gets scope "This token is not authorized to read events (requires events:read or events:write scope)." An account without Reassign Pro access gets permission "Reassign needs an active subscription." The 7-day free trial includes Reassign Pro. A cookie session from another site gets permission "Cross-origin request." |
422 | validation | The request has a query parameter; this operation takes none. |
429 | rate_limited | Too many requests. The edge firewall limits each IP to 2000 requests per minute across /api/v1; that 429 comes from the edge and can have a body that is not this JSON and no Retry-After header. When an edge 429 has no Retry-After, retry after 60 seconds. The app also limits each Bearer credential to 600 requests per minute, and some routes limit each user. These limits return this body. This app 429 always has Retry-After: retry after that number of seconds. |
503 | internal | A fault on our side. The request is safe to retry. |
Request
curl "https://reassign.app/api/v1/categories" \
-H "Authorization: Bearer rsk_live_YOUR_TOKEN"Response
{
"areas": [
{
"id": "3c9d2a41-6b7e-4f80-9a1b-2c3d4e5f6071",
"name": "Work",
"color": "#3b82f6",
"order": 0,
"isGlobal": false,
"overridesId": null
}
],
"activityTypes": [
{
"id": "5e6f7081-92a3-4b4c-8d5e-6f708192a3b4",
"name": "Focus",
"pattern": "solid",
"order": 0,
"isGlobal": false,
"overridesId": null
}
],
"projects": [
{
"id": "f3a4b5c6-d7e8-4f90-a1b2-c3d4e5f60718",
"name": "Launch",
"areaId": "3c9d2a41-6b7e-4f80-9a1b-2c3d4e5f6071",
"order": 0,
"archived": false,
"publishCalendarId": null
}
]
}Change the categories
Create, update, or delete areas, activity types, and projects in one request. Each item in areas, activityTypes, and projects is one operation (op). The op field of the item gives the action.
- The token must have the
events:writescope. - The account needs Reassign Pro. The 7-day free trial includes it.
- Send one or more ops in
areas,activityTypes,projects, or in a combination of them. A body with no op returns422with the messageProvide at least one area, activity-type or project op. - Reassign runs the project ops after the area and activity type ops.
- By default, the request is atomic. If one op fails, Reassign writes no change. Set
partialtotrueto apply the valid ops and to skip the ops that fail.
Validation
Reassign checks the body before it runs an op.
- A body that is not valid as a whole returns
422with the codevalidationand no rows. For example,areasis not an array, an array has more than 50 ops, or the body has an unknown key. - An op that is not valid becomes an
errorrow with the codevalidation. The request then follows the rules in "Status of a failed request" below. - An atomic request with an op that is not valid writes nothing. When each failed op is not valid, the status is
422, and the body has the rows. - In
areasandactivityTypes,opmust becreate,update, ordelete. An unknownopgets the messageUnknown op "<op>". Use one of: create, update, delete. - In
projects,opmust becreate,update,delete,split, orrelink. An unknownopgets the messageUnknown op "<op>". Use one of: create, update, delete, split, relink. namehas 1 to 60 characters. This also applies to a project.colormust be a hex color with 6 lowercase digits, for example#22c55e. Reassign does not convert other color formats.patternmust be one of the values in the activity type model.- Reassign rejects a field that it does not know. An area op with
patternor an activity type op withcoloris not valid. - The message of a bad op names the op and the first bad field, for example
Invalid "create" op. `name`: Too small: expected string to have >=1 characters. An op that is not an object gets the messageEach op must be an object.
Ops
| Op | What it does |
|---|---|
create | Makes an area or an activity type. The name must not be blank, and it must not be the same as the name of a category of the same type. With no color, Reassign selects a color that no area uses, if possible. With no pattern, Reassign selects a pattern that no activity type uses, if possible. The op can carry its own id. With no id, Reassign makes a UUID. |
update | Changes name, color (areas), pattern (activity types), or order. Send one or more of them. With none of them, the op fails with Provide a new name, color and/or order to update. (or … pattern and/or order … for an activity type). When you update a shared default, the result has a new id and a forkedFrom field. Use the new id after this. |
delete | Deletes an area or an activity type. For a shared default or your fork of it, the delete hides the default for your account only. When events, Inbox items, trackers, or calendar defaults use the category, send reassignTo. An ID of a different category of the same type moves the links to it. null clears the links. Refer to Delete a category that items use. |
Project ops
| Op | What it does |
|---|---|
create | Makes a project with name and an optional areaId. With no areaId, the project has no area. The op can carry its own id. You cannot set publishCalendarId on a create. |
update | Changes name, areaId, order, archived, or publishCalendarId, by the id of the project. Send one or more of them. With none of them, the op fails with Provide a new name, areaId, order, archived and/or publishCalendarId to update. |
delete | Deletes a project by its id. Its Inbox blocks and events keep their area and lose the project link. |
split | Moves one task list or Linear project (linkId) that feeds the project id to a new project of its own. |
relink | Moves one Linear project (linkId) to the live project id. |
Project names
- A project name is unique among all your live projects, in all areas. An archived project does not block a name.
- To compare names, Reassign ignores uppercase and lowercase and extra spaces. Unlike areas and activity types, it does not ignore accents.
- A create or a rename to a name in use fails with
conflict. The message names the other project and its area, for exampleA project named Launch exists in Work.For a project with no area, the area isNo area.
Update a project
areaIdtakes the ID of an area that you can see, ornullfor no area. A shared default that you forked gives your fork.archived: truearchives the project. An archived project takes no new links, but its links stay.archived: falserestores it.publishCalendarIdtakes a task list that feeds the project and can take a new item, ornullto turn it off. A new Inbox block of the project goes to this list, unless the block names its own list.- A change of
areaIddoes not change the area of the Inbox blocks that the project has now.
Delete a project
- A project that a task list or a Linear project feeds fails the delete with
conflict. A sync would make the project again. - For a task list, the message is
Link the task list to a different project first. - For a Linear project, the message is
Link the Linear project to a different project first, or archive this project.Userelink, or archive the project.
Split a project
linkIdis theidof a task list or of a Linear project that feeds the projectidnow.- The new project gets the name
<list name> (<Provider>), for exampleLaunch (Todoist). Reassign cuts a long name to fit in 60 characters. - When a live project has that name, the new project gets
2,3, and so on at the end. - The new project goes in the area of the old project.
- The Inbox blocks of the list or the Linear project move to the new project. A later sync keeps the list or the Linear project in the new project.
- When the old project used the list as its
publishCalendarId, the split sets that field tonull. For a Linear project, the split does the same when that field is a team of the Linear project, and no other Linear project of the old project holds that team. - A
linkIdthat does not feed the project fails withnot_found:Task list or Linear project not found, or it does not feed this project.
Relink a Linear project
linkIdis theidof a Linear project.idis a live project, not an archived one.- The Inbox blocks of the Linear project move to the project
id. The tasks in Linear do not change. - When the Linear project fed no project before, only its Inbox blocks with no project move.
- When the
publishCalendarIdof the old project is a team of the Linear project, and no other Linear project of the old project holds that team, the relink sets that field tonull. - A task list changes its project in its list settings, not with
relink. AlinkIdthat is not a Linear project fails withnot_found:Linear project not found or not accessible. A task list changes its project in its list settings. - When the Linear project feeds
idalready, the op changes nothing. Its result hasnoop: true, and the op records no undo. - No public endpoint gives the
linkIdof a Linear project now. Only the Reassign app can read it.
Results
Each op gets one row in the array of its type: areas, activityTypes, or projects. index is the position of the op in its own array, from 0. The response has projects only when the request has project ops.
| Op | result of an ok row |
|---|---|
create | { "created": { id, name, color } } for an area, or { "created": { id, name, pattern } } for an activity type. |
update | { "updated": { id, name, color or pattern } }. When the op forked a shared default, updated also has forkedFrom. The result does not show order. Read GET /api/v1/categories to see the new order. |
delete | { "deletedIds": [id] }. For a shared default or your fork of it, deletedIds also has the other ID of the pair when a fork existed. When reassignTo is an ID, the result also has movedEvents, the number of events that moved. movedEvents does not count Inbox items, trackers, calendar defaults, or projects. |
For a project op:
| Op | result of an ok row |
|---|---|
create | { "created": { id, name, areaId, publishCalendarId } } |
update | { "updated": { id, name, areaId, archived, publishCalendarId } } |
delete | { "deletedIds": [id] } |
split | { "split": { id, name, areaId, fromId, linkId, movedItems } }. id and name are of the new project. fromId is the old project. movedItems is the number of Inbox blocks that moved. |
relink | { "relinked": { id, fromId, linkId, movedItems, noop? } }. fromId is the project that the Linear project fed before, or null. |
- An
errorrow has anerrorobject withcode,message, and optional detail fields. Refer to Error format. Askippedrow has areason. - When one or more ops apply and the server records an undo receipt, the response has
undoTokenandexpiresAt. Send the token toPOST /api/v1/actions/undobeforeexpiresAt(30 minutes) to reverse all the ops of the request. - A request that applies no op has no
undoToken. If the server cannot record the undo, the response also has noundoToken, and the changes stay. - The undo of a delete puts back each link that the delete moved or cleared. The undo of a delete of a shared default fails with
stalewhen a category of the same type now has its name. Refer to Stale tokens. - The undo of a project delete makes the project again with its ID, and puts back its links.
- The undo of a
splitlinks the list or the Linear project back to the old project, and deletes the new project. The undo of arelinkmoves the Linear project and its Inbox blocks back. - A project undo fails with
stalein these cases:- An Inbox block, an event, a calendar, or a Linear project now links to a project that the request made.
- The undo gives a live project the name of a different live project.
- The list or the Linear project of a
splitor arelinknow feeds a different project, or the old project is deleted or archived.
Op errors
| Cause | error.code |
|---|---|
No area or activity type has the id of an update or a delete op. The message is Area "<id>" not found or not accessible. (or Activity type …). For a project, the message is Project "<id>" not found or not accessible. | not_found |
The areaId of a project op is not an area that you can see: Area not found. The publishCalendarId is not a writable task list of the project that can take a new item: Task list not found, not writable, or not a list of this project. A publishCalendarId that is not a UUID gets Task list not found or not writable. The linkId of a split or a relink is not valid. | not_found |
An op that is not valid (refer to "Validation" above), a blank name, an update with no field to change, a delete with no reassignTo of a category that items use, or a reassignTo that does not exist or is the same category. | validation |
A create or a rename to the name of a different category of the same type. The message is An area named "<name>" already exists (id <id>). Reuse it instead of creating a duplicate, or pick a different name. A rename says renaming into a duplicate. For a type, the message starts with An activity type named. | conflict |
| A project name that a different live project has, or a delete of a project that a task list or a Linear project feeds. Refer to Project ops. | conflict |
| A server fault in the op | internal |
Delete a category that items use
When live items use a category, a delete with no reassignTo, or with "", fails with validation. The message is:
Items use this area. Pass `reassignTo` with another area's id to move them, or `reassignTo: null` to clear their link.
For an activity type, the message says activity type. The error of the row also has these fields:
| Field | Value |
|---|---|
usage | { events, inboxItems, trackers, calendars, projects? }: the number of items that use the category. calendars counts the calendars that use it as their default. projects is for an area only: the number of live projects under the area. Deleted events, archived trackers, and archived projects are not in the counts. For a shared default, the counts include your fork. |
reassignTargets | [{ id, name }]: the categories of the same type that can take the links. The list never has the category that you delete, or its fork. |
Do these steps:
- Show
usageto the user, and ask where the items go. - Send the delete again with
reassignTo. Use anidfromreassignTargetsto move the links, ornullto clear them.
A category that no live item uses deletes with no reassignTo. A live project under an area counts as a use. An area delete with reassignTo moves each project of the area to that area. With reassignTo: null, the projects have no area. The move does not rename a project.
Delete a shared default
- The delete hides the shared default, and your fork of it, for your account only. Other accounts still see the default.
- After the delete,
GET /api/v1/categoriesdoes not show either ID. deletedIdshas the ID that you sent. When you had a fork, it also has the other ID of the pair.- The undo shows the default again and puts back each link.
Status of a failed request
- In an atomic request with a failed op, only the failed op is an
errorrow. The other ops areskippedrows, with the reasonNot applied — another op in this batch failed; fix the errors and resend. - An atomic request with one or more ops that are not valid runs no op. Each bad op is an
errorrow, and the valid ops areskipped. - For a server fault outside an op in an atomic request, all ops get the same message and the code of the error, usually
internal. - When no op applies, Reassign rejects the request. The body is
{ "error": { code, message }, areas, activityTypes, projects? }.projectsis there only when the request sent project ops. The status followserror.code, as the Responses table shows. - A request where one or more ops apply returns
200.
Refer to Errors for the error format.
Request body
- Name
areas- Type
- object[]
- Description
3 forms
One form:
op: "create"- Name
id- Type
- string
- Description
- Name
name- Type
- string, required
- Description
- Name
color- Type
- string
- Description
Lowercase "#rrggbb"; omit to auto-pick.
One form:
op: "update"- Name
id- Type
- string, required
- Description
- Name
name- Type
- string
- Description
- Name
color- Type
- string
- Description
Lowercase "#rrggbb"; omit to auto-pick.
- Name
order- Type
- integer
- Description
One form:
op: "delete"- Name
id- Type
- string, required
- Description
- Name
reassignTo- Type
- string | null
- Description
Another area's id to move the linked items onto, or null to clear their link. Required when items use it.
- Name
activityTypes- Type
- object[]
- Description
3 forms
One form:
op: "create"- Name
id- Type
- string
- Description
- Name
name- Type
- string, required
- Description
- Name
pattern- Type
- "solid" | "hatch_r" | "hatch_l" | "cross" | "horizontal" | "vertical" | "grid" | "dots" | "waves" | "chevron"
- Description
A fill pattern; omit to auto-pick.
One form:
op: "update"- Name
id- Type
- string, required
- Description
- Name
name- Type
- string
- Description
- Name
pattern- Type
- "solid" | "hatch_r" | "hatch_l" | "cross" | "horizontal" | "vertical" | "grid" | "dots" | "waves" | "chevron"
- Description
A fill pattern; omit to auto-pick.
- Name
order- Type
- integer
- Description
One form:
op: "delete"- Name
id- Type
- string, required
- Description
- Name
reassignTo- Type
- string | null
- Description
Another activity type's id to move the linked items onto, or null to clear their link. Required when items use it.
- Name
projects- Type
- object[]
- Description
5 forms
One form:
op: "create"- Name
id- Type
- string
- Description
- Name
name- Type
- string, required
- Description
The project name; unique among all live projects of the user, in any area.
- Name
areaId- Type
- string | null
- Description
The parent area id, or null for no area. When a write moves an Inbox item to the project and sets no area, the item takes this area.
One form:
op: "update"- Name
id- Type
- string, required
- Description
- Name
name- Type
- string
- Description
The project name; unique among all live projects of the user, in any area.
- Name
areaId- Type
- string | null
- Description
The parent area id, or null for no area. When a write moves an Inbox item to the project and sets no area, the item takes this area.
- Name
publishCalendarId- Type
- string | null
- Description
The task list that a new Inbox item of this project is created in, unless the item names its own list. null turns it off.
- Name
order- Type
- number
- Description
The sort position.
- Name
archived- Type
- boolean
- Description
true archives the project: it leaves the lookups and takes no new links, but its links stay. false restores it.
One form:
op: "delete"- Name
id- Type
- string, required
- Description
The project to delete; its items and events keep their area and lose the project link.
One form:
op: "split"- Name
id- Type
- string, required
- Description
The shared project to split a link from.
- Name
linkId- Type
- string, required
- Description
The task list (
source_calendarsid) or Linear project (source_projectsid) that feedsidand moves to a new project of its own, "{name} ({Provider})".
One form:
op: "relink"- Name
id- Type
- string, required
- Description
The live project that the Linear project feeds next.
- Name
linkId- Type
- string, required
- Description
The Linear project (
source_projectsid) to point atid. Its Inbox items move along. A task list changes its project in its list settings.
- Name
partial- Type
- boolean
- Description
Best-effort mode instead of the default all-or-nothing.
Response fields
- Name
undoToken- Type
- string
- Description
- Name
expiresAt- Type
- string
- Description
- Name
areas- Type
- object[], required
- Description
3 forms
One form:
status: "ok"- Name
index- Type
- integer, required
- Description
- Name
result- Type
- object, required
- Description
3 forms
One form: With
created- Name
created- Type
- object, required
- Description
3 fields
- Name
id- Type
- string, required
- Description
- Name
name- Type
- string, required
- Description
- Name
color- Type
- string, required
- Description
One form: With
updated- Name
updated- Type
- object, required
- Description
4 fields
- Name
id- Type
- string, required
- Description
- Name
forkedFrom- Type
- string
- Description
- Name
name- Type
- string, required
- Description
- Name
color- Type
- string, required
- Description
One form: With
deletedIds- Name
deletedIds- Type
- string[], required
- Description
- Name
movedEvents- Type
- integer
- Description
- Name
warnings- Type
- "classification_pending"[]
- Description
One form:
status: "error"- Name
index- Type
- integer, required
- Description
- Name
error- Type
- object, required
- Description
11 fields
- Name
code- Type
- "conflict" | "not_found" | "validation" | "permission" | "scope" | "stale" | "read_only" | "rate_limited" | "internal", required
- Description
- Name
message- Type
- string, required
- Description
- Name
issues- Type
- object[]
- Description
3 fields
- Name
path- Type
- string | integer[], required
- Description
- Name
message- Type
- string, required
- Description
- Name
expected- Type
- string
- Description
- Name
feature- Type
- string
- Description
- Name
conflictingRows- Type
- object[]
- Description
3 fields
- Name
entity- Type
- string, required
- Description
- Name
id- Type
- string, required
- Description
- Name
reason- Type
- "changed" | "deleted" | "newly_present", required
- Description
- Name
conflictingRowsTruncated- Type
- true
- Description
- Name
usage- Type
- object
- Description
5 fields
- Name
events- Type
- integer, required
- Description
- Name
inboxItems- Type
- integer, required
- Description
- Name
trackers- Type
- integer, required
- Description
- Name
calendars- Type
- integer, required
- Description
- Name
projects- Type
- integer
- Description
- Name
reassignTargets- Type
- object[]
- Description
2 fields
- Name
id- Type
- string, required
- Description
- Name
name- Type
- string, required
- Description
- Name
unlinkedCheckout- Type
- object
- Description
3 fields
- Name
sessionId- Type
- string, required
- Description
- Name
paymentReceived- Type
- boolean, required
- Description
- Name
supportUrl- Type
- string, required
- Description
- Name
conflicts- Type
- object[]
- Description
2 forms
One form: With
id- Name
start- Type
- string, required
- Description
- Name
end- Type
- string, required
- Description
- Name
id- Type
- string, required
- Description
- Name
name- Type
- string, required
- Description
One form: With
batchIndex- Name
start- Type
- string, required
- Description
- Name
end- Type
- string, required
- Description
- Name
batchIndex- Type
- integer, required
- Description
- Name
name- Type
- string, required
- Description
- Name
nearestSlots- Type
- object[]
- Description
4 fields
- Name
start- Type
- string, required
- Description
- Name
end- Type
- string, required
- Description
- Name
score- Type
- number
- Description
- Name
reason- Type
- string
- Description
One form:
status: "skipped"- Name
index- Type
- integer, required
- Description
- Name
reason- Type
- string, required
- Description
- Name
activityTypes- Type
- object[], required
- Description
3 forms
One form:
status: "ok"- Name
index- Type
- integer, required
- Description
- Name
result- Type
- object, required
- Description
3 forms
One form: With
created- Name
created- Type
- object, required
- Description
3 fields
- Name
id- Type
- string, required
- Description
- Name
name- Type
- string, required
- Description
- Name
pattern- Type
- "solid" | "hatch_r" | "hatch_l" | "cross" | "horizontal" | "vertical" | "grid" | "dots" | "waves" | "chevron", required
- Description
One form: With
updated- Name
updated- Type
- object, required
- Description
4 fields
- Name
id- Type
- string, required
- Description
- Name
forkedFrom- Type
- string
- Description
- Name
name- Type
- string, required
- Description
- Name
pattern- Type
- "solid" | "hatch_r" | "hatch_l" | "cross" | "horizontal" | "vertical" | "grid" | "dots" | "waves" | "chevron", required
- Description
One form: With
deletedIds- Name
deletedIds- Type
- string[], required
- Description
- Name
movedEvents- Type
- integer
- Description
- Name
warnings- Type
- "classification_pending"[]
- Description
One form:
status: "error"- Name
index- Type
- integer, required
- Description
- Name
error- Type
- object, required
- Description
11 fields
- Name
code- Type
- "conflict" | "not_found" | "validation" | "permission" | "scope" | "stale" | "read_only" | "rate_limited" | "internal", required
- Description
- Name
message- Type
- string, required
- Description
- Name
issues- Type
- object[]
- Description
3 fields
- Name
path- Type
- string | integer[], required
- Description
- Name
message- Type
- string, required
- Description
- Name
expected- Type
- string
- Description
- Name
feature- Type
- string
- Description
- Name
conflictingRows- Type
- object[]
- Description
3 fields
- Name
entity- Type
- string, required
- Description
- Name
id- Type
- string, required
- Description
- Name
reason- Type
- "changed" | "deleted" | "newly_present", required
- Description
- Name
conflictingRowsTruncated- Type
- true
- Description
- Name
usage- Type
- object
- Description
5 fields
- Name
events- Type
- integer, required
- Description
- Name
inboxItems- Type
- integer, required
- Description
- Name
trackers- Type
- integer, required
- Description
- Name
calendars- Type
- integer, required
- Description
- Name
projects- Type
- integer
- Description
- Name
reassignTargets- Type
- object[]
- Description
2 fields
- Name
id- Type
- string, required
- Description
- Name
name- Type
- string, required
- Description
- Name
unlinkedCheckout- Type
- object
- Description
3 fields
- Name
sessionId- Type
- string, required
- Description
- Name
paymentReceived- Type
- boolean, required
- Description
- Name
supportUrl- Type
- string, required
- Description
- Name
conflicts- Type
- object[]
- Description
2 forms
One form: With
id- Name
start- Type
- string, required
- Description
- Name
end- Type
- string, required
- Description
- Name
id- Type
- string, required
- Description
- Name
name- Type
- string, required
- Description
One form: With
batchIndex- Name
start- Type
- string, required
- Description
- Name
end- Type
- string, required
- Description
- Name
batchIndex- Type
- integer, required
- Description
- Name
name- Type
- string, required
- Description
- Name
nearestSlots- Type
- object[]
- Description
4 fields
- Name
start- Type
- string, required
- Description
- Name
end- Type
- string, required
- Description
- Name
score- Type
- number
- Description
- Name
reason- Type
- string
- Description
One form:
status: "skipped"- Name
index- Type
- integer, required
- Description
- Name
reason- Type
- string, required
- Description
- Name
projects- Type
- object[]
- Description
3 forms
One form:
status: "ok"- Name
index- Type
- integer, required
- Description
- Name
result- Type
- object, required
- Description
5 forms
One form: With
created- Name
created- Type
- object, required
- Description
4 fields
- Name
id- Type
- string, required
- Description
- Name
name- Type
- string, required
- Description
- Name
areaId- Type
- string | null, required
- Description
- Name
publishCalendarId- Type
- string | null, required
- Description
One form: With
updated- Name
updated- Type
- object, required
- Description
5 fields
- Name
id- Type
- string, required
- Description
- Name
name- Type
- string, required
- Description
- Name
areaId- Type
- string | null, required
- Description
- Name
archived- Type
- boolean, required
- Description
- Name
publishCalendarId- Type
- string | null, required
- Description
One form: With
deletedIds- Name
deletedIds- Type
- string[], required
- Description
One form: With
split- Name
split- Type
- object, required
- Description
A split: the link feeds a new project "{name} ({Provider})" now.
6 fields
- Name
id- Type
- string, required
- Description
The new project of the link.
- Name
name- Type
- string, required
- Description
- Name
areaId- Type
- string | null, required
- Description
- Name
fromId- Type
- string, required
- Description
The shared project that the link left.
- Name
linkId- Type
- string, required
- Description
The task list or Linear project that moved.
- Name
movedItems- Type
- integer, required
- Description
The Inbox items that moved with the link.
One form: With
relinked- Name
relinked- Type
- object, required
- Description
A relink: the Linear project feeds
idnow.5 fields
- Name
id- Type
- string, required
- Description
The project that the Linear project feeds now.
- Name
fromId- Type
- string | null, required
- Description
The project that it fed before; null for none.
- Name
linkId- Type
- string, required
- Description
The Linear project that moved.
- Name
movedItems- Type
- integer, required
- Description
The Inbox items that moved with the link.
- Name
noop- Type
- true
- Description
The Linear project feeds
idalready: nothing changed and no undo receipt.
- Name
warnings- Type
- "classification_pending"[]
- Description
One form:
status: "error"- Name
index- Type
- integer, required
- Description
- Name
error- Type
- object, required
- Description
11 fields
- Name
code- Type
- "conflict" | "not_found" | "validation" | "permission" | "scope" | "stale" | "read_only" | "rate_limited" | "internal", required
- Description
- Name
message- Type
- string, required
- Description
- Name
issues- Type
- object[]
- Description
3 fields
- Name
path- Type
- string | integer[], required
- Description
- Name
message- Type
- string, required
- Description
- Name
expected- Type
- string
- Description
- Name
feature- Type
- string
- Description
- Name
conflictingRows- Type
- object[]
- Description
3 fields
- Name
entity- Type
- string, required
- Description
- Name
id- Type
- string, required
- Description
- Name
reason- Type
- "changed" | "deleted" | "newly_present", required
- Description
- Name
conflictingRowsTruncated- Type
- true
- Description
- Name
usage- Type
- object
- Description
5 fields
- Name
events- Type
- integer, required
- Description
- Name
inboxItems- Type
- integer, required
- Description
- Name
trackers- Type
- integer, required
- Description
- Name
calendars- Type
- integer, required
- Description
- Name
projects- Type
- integer
- Description
- Name
reassignTargets- Type
- object[]
- Description
2 fields
- Name
id- Type
- string, required
- Description
- Name
name- Type
- string, required
- Description
- Name
unlinkedCheckout- Type
- object
- Description
3 fields
- Name
sessionId- Type
- string, required
- Description
- Name
paymentReceived- Type
- boolean, required
- Description
- Name
supportUrl- Type
- string, required
- Description
- Name
conflicts- Type
- object[]
- Description
2 forms
One form: With
id- Name
start- Type
- string, required
- Description
- Name
end- Type
- string, required
- Description
- Name
id- Type
- string, required
- Description
- Name
name- Type
- string, required
- Description
One form: With
batchIndex- Name
start- Type
- string, required
- Description
- Name
end- Type
- string, required
- Description
- Name
batchIndex- Type
- integer, required
- Description
- Name
name- Type
- string, required
- Description
- Name
nearestSlots- Type
- object[]
- Description
4 fields
- Name
start- Type
- string, required
- Description
- Name
end- Type
- string, required
- Description
- Name
score- Type
- number
- Description
- Name
reason- Type
- string
- Description
One form:
status: "skipped"- Name
index- Type
- integer, required
- Description
- Name
reason- Type
- string, required
- Description
Responses
| Status | Codes | Meaning |
|---|---|---|
200 | — | Success. |
400 | batch_rejected | Every op failed, and the failed ops have different codes. The code is batch_rejected. |
401 | unauthorized | No Bearer token and no session cookie, or the token is invalid, expired, or revoked. The response carries a WWW-Authenticate challenge that points at the protected-resource metadata. |
403 | permissionscope | A token without events:write gets scope "This token is not authorized to modify events (missing events:write scope)." An account without Reassign Pro access gets permission "Reassign needs an active subscription." The 7-day free trial includes Reassign Pro. A cookie session from another site gets permission "Cross-origin request." |
404 | not_found | An op names an item that does not exist. |
409 | conflict | The request conflicts with the current state: conflict "A project named Launch exists in Work." or conflict "Link the task list to a different project first." |
422 | validation | The request body is not valid. The message names the first bad field by its path. A repeated or unknown query parameter is also a 422. |
429 | rate_limited | Too many requests. The edge firewall limits each IP to 2000 requests per minute across /api/v1; that 429 comes from the edge and can have a body that is not this JSON and no Retry-After header. When an edge 429 has no Retry-After, retry after 60 seconds. The app also limits each Bearer credential to 600 requests per minute, and some routes limit each user. These limits return this body. This app 429 always has Retry-After: retry after that number of seconds. |
503 | internal | A fault on our side. The request is safe to retry. |
Most error responses: When no op of the batch applied, the body also has the areas, activityTypes and projects rows, so the caller sees which op failed.
Request
curl -X POST "https://reassign.app/api/v1/categories" \
-H "Authorization: Bearer rsk_live_YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"areas": [
{
"op": "create",
"name": "Health",
"color": "#22c55e"
}
],
"activityTypes": [
{
"op": "update",
"id": "5e6f7081-92a3-4b4c-8d5e-6f708192a3b4",
"name": "Deep focus"
}
],
"projects": [
{
"op": "split",
"id": "f3a4b5c6-d7e8-4f90-a1b2-c3d4e5f60718",
"linkId": "a4b5c6d7-e8f9-4a01-b2c3-d4e5f6071829"
}
]
}'Response
{
"undoToken": "00000000-0000-4000-8000-000000000001",
"expiresAt": "2026-08-13T09:12:00.000Z",
"areas": [
{
"index": 0,
"status": "ok",
"result": {
"created": {
"id": "6f7a8b9c-0d1e-4f2a-8b3c-4d5e6f7a8b9c",
"name": "Health",
"color": "#22c55e"
}
}
}
],
"activityTypes": [
{
"index": 0,
"status": "ok",
"result": {
"updated": {
"id": "5e6f7081-92a3-4b4c-8d5e-6f708192a3b4",
"name": "Deep focus",
"pattern": "solid"
}
}
}
],
"projects": [
{
"index": 0,
"status": "ok",
"result": {
"split": {
"id": "b5c6d7e8-f9a0-4b12-83d4-e5f60718293a",
"name": "Launch (Todoist)",
"areaId": "3c9d2a41-6b7e-4f80-9a1b-2c3d4e5f6071",
"fromId": "f3a4b5c6-d7e8-4f90-a1b2-c3d4e5f60718",
"linkId": "a4b5c6d7-e8f9-4a01-b2c3-d4e5f6071829",
"movedItems": 3
}
}
}
]
}