Overview
The Nimble REST API lets you interact with your workspace programmatically — create and update workitems, manage todos, log time, add comments, and more. This guide covers every available endpoint with example requests and responses for use with Postman.
Base URL: https://api.nimblework.com/blox/openapi
Getting a Token
Every API call requires Authorization: Bearer <token>. Register a client once, then request a new token whenever your token expires (~1 hour).
Step 1 — Register an API Client in Nimble
- Log in to your Nimble instance.
- In the left sidebar, click Account Space.
- In the top nav, click Administration → REST API Client.
- Click + REGISTER (top right).
- Enter a Client Name. The Client ID is auto-generated — copy it.
- Expand Workspace Access Permissions and tick the permissions you need (Read Card, Create Card, Update Card, etc.).
- Click REGISTER CLIENT. Copy the Client Secret — it is shown only once. Click DONE.
Step 2 — Get a Token
POST https://api.nimblework.com/rest/v1/oauth/token
| Header | Value |
|---|---|
| Content-Type | application/json |
Body · raw · JSON
{
"grant_type": "client_credentials",
"client_id": "nmb_cli_xxxxxxxxxxxx",
"client_secret": "your_client_secret_here"
}
Response 200 OK
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600
}
Copy the access_token. Use it as Bearer <access_token> in all subsequent requests.
Postman Setup
Create a Postman Environment with these variables so you only set them once:
| Variable | Example value |
|---|---|
| token | eyJhbGciOiJSUzI1NiIs… (paste from Step 2) |
| baseUrl | https://api.nimblework.com/blox/openapi |
| workspaceId | 2110769 |
| correlation | INSTANCE:accountId:userId |
Then in every request use {{baseUrl}}, {{token}}, etc.
Workspaces
GET — List Workspaces
GET {{baseUrl}}/workspaces?limit=10
| Header | Value |
|---|---|
| Authorization | Bearer {{token}} |
| accept | application/json |
| Param | Required | Description |
|---|---|---|
| limit | opt | Number of results per page (default 50) |
| pageToken | opt | Cursor from previous response for next page |
| sort | opt | Field to sort by |
| order | opt | asc or desc |
Response 200 OK
{
"items": [
{
"workspaceId": "2110769",
"name": "My First Project",
"description": "FromProjectCreate",
"createdBy": "353147453",
"modifiedBy": "353147453",
"createdAt": "2026-08-14T17:12:17Z"
}
],
"total": 1,
"pageToken": null
}
GET — Single Workspace
GET {{baseUrl}}/workspaces/:workspaceId
| Header | Value |
|---|---|
| Authorization | Bearer {{token}} |
| accept | application/json |
| Path Variable | Required | Description |
|---|---|---|
| workspaceId | req | e.g. 2110769 |
Response 200 OK
{
"workspaceId": "2110769",
"name": "My First Project",
"description": "FromProjectCreate",
"createdBy": "353147453",
"modifiedBy": "353147453",
"createdAt": "2026-08-14T17:12:17Z",
"updatedAt": "2026-08-14T17:12:17Z"
}
Forms
Forms are the templates that define the fields for instances (workitems). Every instance belongs to a form. The X-WorkspaceId header is required for both form endpoints.
GET — List Forms
GET {{baseUrl}}/forms
| Header | Value |
|---|---|
| Authorization | Bearer {{token}} |
| X-WorkspaceId | {{workspaceId}} |
| accept | application/json |
Response 200 OK
{
"items": [
{
"formId": "523440",
"name": "Issue",
"prefix": "ISS",
"workspaceId": "2110769",
"hexColorCode": "#FF5733",
"custom": true,
"createdAt": "2026-01-10T09:00:00Z",
"fields": [
{ "fieldUniqueName": "Name", "custom": false, "readOnly": false },
{ "fieldUniqueName": "Priority", "custom": true, "readOnly": false },
{ "fieldUniqueName": "Assigned To", "custom": true, "readOnly": false },
{ "fieldUniqueName": "Status", "custom": false, "readOnly": true }
]
}
]
}
GET — Single Form (with full field schema)
GET {{baseUrl}}/forms/:formId
| Header | Value |
|---|---|
| Authorization | Bearer {{token}} |
| X-WorkspaceId | {{workspaceId}} |
| accept | application/json |
| Path Variable | Required | Description |
|---|---|---|
| formId | req | Numeric form ID, e.g. 523440 |
Response 200 OK
{
"formId": "523440",
"name": "Issue",
"prefix": "ISS",
"workspaceId": "2110769",
"fields": [
{
"fieldUniqueName": "Name",
"custom": false,
"readOnly": false,
"type": "TEXT",
"required": true
},
{
"fieldUniqueName": "Priority",
"custom": true,
"readOnly": false,
"type": "LOOKUP",
"required": false
}
]
}
Instances (Workitems)
An instance is a single workitem (card). Custom field values are sent and received at the root level alongside system fields. Always include formId in the request body for writes.
GET — List Instances
GET {{baseUrl}}/instances?workspaceId={{workspaceId}}&formId=523440&limit=20
| Header | Value |
|---|---|
| Authorization | Bearer {{token}} |
| accept | application/json |
| Param | Required | Description |
|---|---|---|
| workspaceId | req | Your workspace ID |
| formId | opt | Filter by form, e.g. 523440 |
| expand | opt | true — inlines lookup field values |
| limit | opt | Max results per page |
| pageToken | opt | Cursor for next page |
| sort | opt | Field name to sort by |
| order | opt | asc or desc |
Response 200 OK
{
"items": [
{
"instanceId": "523440-42",
"id": "ISS-42",
"formId": "523440",
"workspaceId": "2110769",
"Name": "Login page broken",
"Priority": "High",
"Status": "Open",
"createdAt": "2026-08-01T10:00:00Z"
}
],
"total": 1
}
GET — Single Instance
GET {{baseUrl}}/instances/:instanceId?expand=true
| Header | Value |
|---|---|
| Authorization | Bearer {{token}} |
| accept | application/json |
| Path Variable | Required | Description |
|---|---|---|
| instanceId | req | e.g. ISS-42 |
Response 200 OK
{
"instanceId": "523440-42",
"id": "ISS-42",
"formId": "523440",
"workspaceId": "2110769",
"Name": "Login page broken",
"Priority": "High",
"Status": "Open",
"flags": [],
"blocks": [],
"createdAt": "2026-08-01T10:00:00Z"
}
GET — Subblocks (child instances)
GET {{baseUrl}}/instances/:instanceId/subblocks?depth=-1
| Header | Value |
|---|---|
| Authorization | Bearer {{token}} |
| accept | application/json |
| Param | Required | Description |
|---|---|---|
| depth | req | 0 = direct children only · -1 = full tree · n = n levels |
Response 200 OK
{
"items": [
{ "instanceId": "523440-43", "id": "ISS-43", "Name": "Sub-task A", "...": "..." }
]
}
POST — Create Instance
POST {{baseUrl}}/instances
| Header | Value |
|---|---|
| Authorization | Bearer {{token}} |
| Content-Type | application/json |
| accept | application/json |
{
"formId": "523440",
"workspaceId": "2110769",
"Name": "Login page broken",
"Priority": "High",
"Assigned To": "John Smith"
}
Note: formId and workspaceId are required. All other fields are custom fields from the form schema — use the exact field names returned by GET /forms/:formId.
Response 201 CREATED
{
"instanceId": "523440-42",
"id": "ISS-42"
}
The Location response header also contains the URL of the new instance.
PUT — Full Replace
PUT {{baseUrl}}/instances/:instanceId
| Header | Value |
|---|---|
| Authorization | Bearer {{token}} |
| Content-Type | application/json |
| accept | application/json |
{
"formId": "523440",
"Name": "Login page broken — updated",
"Priority": "Critical"
}
Important: This is a full replacement. Any custom field not included in the body (e.g. Assigned To) will be cleared. System fields like Status, flags, and blocks are never cleared by PUT.
Response 200 OK
{
"instanceId": "523440-42",
"id": "ISS-42",
"Name": "Login page broken — updated",
"Priority": "Critical",
"Assigned To": null
}
PATCH — Partial Update
PATCH {{baseUrl}}/instances/:instanceId
| Header | Value |
|---|---|
| Authorization | Bearer {{token}} |
| Content-Type | application/json |
| accept | application/json |
{
"formId": "523440",
"Priority": "Low"
}
Note: Only Priority changes. All other fields remain untouched. formId is required. Do not send flag or block keys here — use the dedicated sub-resource endpoints.
Response 200 OK
{
"instanceId": "523440-42",
"id": "ISS-42",
"Priority": "Low"
}
DELETE — Delete Instance
DELETE {{baseUrl}}/instances/:instanceId
| Header | Value |
|---|---|
| Authorization | Bearer {{token}} |
Response 204 NO CONTENT — Empty body. Returns 404 if the instance has already been deleted.
Flags
Only available on instances of STANDALONE form types. Returns 400 for sub-block instances.
POST — Flag an Instance
POST {{baseUrl}}/instances/:instanceId/flags
| Header | Value |
|---|---|
| Authorization | Bearer {{token}} |
| Content-Type | application/json |
| accept | */* |
{
"comment": "Needs immediate attention"
}
comment is optional. Max 5,000 characters if provided.
Response 200 OK
{
"instanceId": "523440-42",
"flags": [
{
"actionId": "flag_001",
"actor": { "actorId": "353136425", "type": "USER", "name": "John Smith" },
"comment": "Needs immediate attention",
"createdAt": "2026-08-19T10:00:00Z"
}
]
}
DELETE — Unflag an Instance
DELETE {{baseUrl}}/instances/:instanceId/flags/:actionId
| Header | Value |
|---|---|
| Authorization | Bearer {{token}} |
| Content-Type | application/json |
| Path Variable | Required | Description |
|---|---|---|
| actionId | req | The actionId from the flag entry, e.g. flag_001 |
Body · raw · JSON (optional)
{
"comment": "Resolved"
}
Returns 400 (not 409) for error cases: no flag history, actionId mismatch, already unflagged.
Response 200 OK
{ "instanceId": "523440-42", "flags": [] }
Blocks
POST — Block an Instance
POST {{baseUrl}}/instances/:instanceId/blocks
| Header | Value |
|---|---|
| Authorization | Bearer {{token}} |
| Content-Type | application/json |
| accept | */* |
{
"reason": "Waiting for design approval",
"comment": "Blocked until design sign-off is received"
}
Both reason and comment are required. Returns 400 if either is absent or blank. Use GET /forms/:formId to discover valid blocking reasons for the form.
Response 200 OK
{
"instanceId": "523440-42",
"blocks": [
{
"actionId": "block_001",
"reason": "Waiting for design approval",
"comment": "Blocked until design sign-off is received",
"actor": { "actorId": "353136425", "type": "USER", "name": "John Smith" }
}
]
}
DELETE — Unblock an Instance
DELETE {{baseUrl}}/instances/:instanceId/blocks/:actionId
| Header | Value |
|---|---|
| Authorization | Bearer {{token}} |
| Content-Type | application/json |
{
"comment": "Design approved, unblocking"
}
comment is required — returns 400 if absent or blank.
Response 200 OK
{ "instanceId": "523440-42", "blocks": [] }
Votes
POST — Vote on an Instance
POST {{baseUrl}}/instances/:instanceId/votes
| Header | Value |
|---|---|
| Authorization | Bearer {{token}} |
| accept | application/json |
No body required. Returns 409 if you have already voted on this instance.
Response 200 OK
{ "instanceId": "523440-42", "action": "voted", "votes": 1 }
DELETE — Remove Vote
DELETE {{baseUrl}}/instances/:instanceId/votes
| Header | Value |
|---|---|
| Authorization | Bearer {{token}} |
Returns 409 if you have not voted on this instance.
Response 200 OK
{ "instanceId": "523440-42", "action": "unvoted", "votes": 0 }
Links
Creates or removes a typed directional link between two instances. HIERARCHY links also set parentCard on the source instance.
PUT — Create a Link
PUT {{baseUrl}}/instances/:instanceId/link
| Header | Value |
|---|---|
| Authorization | Bearer {{token}} |
| Content-Type | application/json |
{
"to": {
"workItemId": "ISS-50",
"formId": "523440",
"workSpaceId": "2110769"
},
"relationInverse": "fulfills",
"metaType": "DEPENDENCY"
}
metaType values: HIERARCHY (default), DEPENDENCY, TRACEBAILITY, CONTAINMENT, ASSOCIATION.
Response 200 OK
{ "linkId": "lnk_001", "from": "ISS-42", "to": "ISS-50", "metaType": "DEPENDENCY" }
DELETE — Remove a Link
DELETE {{baseUrl}}/instances/:instanceId/link/:targetId?metaType=DEPENDENCY
| Header | Value |
|---|---|
| Authorization | Bearer {{token}} |
| Query Param | Required | Description |
|---|---|---|
| metaType | opt | Must match the value used when the link was created. Defaults to HIERARCHY. |
Response 200 OK
{ "linkId": "lnk_001", "removed": true }
Comments
Limitations: User mentions (@user), emoji, and inline attachments are not supported in comment text. Use POST /attachments to attach files to an instance.
POST — Add a Comment
POST {{baseUrl}}/instances/:instanceId/comments
| Header | Value |
|---|---|
| Authorization | Bearer {{token}} |
| Content-Type | application/json |
{
"content": "Reproduced on Chrome 126. Stack trace attached.",
"type": "COMMENT"
}
content is required (min 1 char). type is optional, defaults to COMMENT.
Response 201 CREATED
{ "commentId": "cmt_abc123" }
GET — List Comments
GET {{baseUrl}}/instances/:instanceId/comments
| Header | Value |
|---|---|
| Authorization | Bearer {{token}} |
| accept | application/json |
Response 200 OK
{
"comments": [
{
"commentId": "cmt_abc123",
"content": "Reproduced on Chrome 126.",
"type": "COMMENT",
"authorId": "353136425",
"createdAt": "2026-08-19T10:05:00Z",
"replies": []
}
]
}
GET — Single Comment (with replies)
GET {{baseUrl}}/instances/:instanceId/comments/:commentId
| Header | Value |
|---|---|
| Authorization | Bearer {{token}} |
| accept | application/json |
Response 200 OK
{
"commentId": "cmt_abc123",
"content": "Reproduced on Chrome 126.",
"authorId": "353136425",
"replies": [
{ "commentId": "cmt_def456", "content": "Also on Firefox.", "authorId": "353147453" }
]
}
PUT — Add a Reply
PUT {{baseUrl}}/instances/:instanceId/comments/:commentId/replies
| Header | Value |
|---|---|
| Authorization | Bearer {{token}} |
| Content-Type | application/json |
{ "content": "Also reproduced on Safari 17." }
Response 200 OK
{ "commentId": "cmt_ghi789" }
PUT — Edit Comment Text
PUT {{baseUrl}}/instances/:instanceId/comments/:commentId/content
| Header | Value |
|---|---|
| Authorization | Bearer {{token}} |
| Content-Type | application/json |
{ "content": "Reproduced on Chrome 126 and Edge 124. Stack trace attached." }
Response 200 OK
{ "commentId": "cmt_abc123", "updated": true }
DELETE — Delete Comment
DELETE {{baseUrl}}/instances/:instanceId/comments/:commentId
| Header | Value |
|---|---|
| Authorization | Bearer {{token}} |
Response 204 NO CONTENT — Empty body on success.
Attachments
POST — Upload a File
POST {{baseUrl}}/instances/:instanceId/attachments
| Header | Value |
|---|---|
| Authorization | Bearer {{token}} |
| Content-Type | Do NOT set manually — Postman sets this automatically for form-data |
Body · form-data
| Key | Type | Value |
|---|---|---|
| file | File | Select file from your computer (max 32 MB) |
In Postman: Body tab → select form-data → set key to file → hover the key and change type from Text to File → click Select Files.
Response 201 CREATED
{ "attachmentId": "att_789012" }
POST — Link an External Resource
POST {{baseUrl}}/instances/:instanceId/attachments/link
| Header | Value |
|---|---|
| Authorization | Bearer {{token}} |
| Content-Type | application/json |
{
"attachmentName": "Design Mockup",
"content": "https://figma.com/file/abc123",
"linkedUsing": "Figma"
}
Response 201 CREATED
{ "attachmentId": "att_link_001" }
GET — List Attachments
GET {{baseUrl}}/instances/:instanceId/attachments
| Header | Value |
|---|---|
| Authorization | Bearer {{token}} |
| accept | application/json |
Response 200 OK
{
"attachments": [
{
"attachmentId": "att_789012",
"name": "screenshot.png",
"mimeType": "image/png",
"fileSize": 204800,
"createdAt": "2026-08-19T11:00:00Z"
}
]
}
DELETE — Delete Attachment
DELETE {{baseUrl}}/instances/:instanceId/attachments/:attachmentId
| Header | Value |
|---|---|
| Authorization | Bearer {{token}} |
Response 204 NO CONTENT — Empty body on success.
Todos
GET — List Todos
GET {{baseUrl}}/instances/:instanceId/todos
| Header | Value |
|---|---|
| Authorization | Bearer {{token}} |
| accept | application/json |
| Param | Required | Description |
|---|---|---|
| assigneeId | opt | Filter by assignee user ID |
| limit | opt | Max results per page |
| pageToken | opt | Cursor for next page |
Response 200 OK
{
"todos": [
{
"todoId": "TODO1",
"name": "Write unit tests",
"status": "open",
"assigneeId": "353136425",
"estimate": 4
}
]
}
POST — Create a Todo
POST {{baseUrl}}/instances/:instanceId/todos
| Header | Value |
|---|---|
| Authorization | Bearer {{token}} |
| Content-Type | application/json |
{
"name": "Write unit tests",
"assigneeId": "353136425",
"estimate": 4,
"formId": "523440"
}
name is required. All other fields are optional.
Response 201 CREATED
{ "todoId": "TODO1" }
PATCH — Update a Todo
PATCH {{baseUrl}}/instances/:instanceId/todos/:todoId
| Header | Value |
|---|---|
| Authorization | Bearer {{token}} |
| Content-Type | application/json |
{
"estimate": 6
}
All fields optional: name, assigneeId, estimate. Only sent fields are updated.
Response 200 OK
{ "todoId": "TODO1", "estimate": 6 }
POST — Close a Todo
POST {{baseUrl}}/instances/:instanceId/todos/:todoId/close
| Header | Value |
|---|---|
| Authorization | Bearer {{token}} |
No body required.
Response 200 OK
{ "todoId": "TODO1", "status": "closed", "actualFinish": "2026-08-19T12:00:00Z" }
POST — Reopen a Todo
POST {{baseUrl}}/instances/:instanceId/todos/:todoId/reopen
| Header | Value |
|---|---|
| Authorization | Bearer {{token}} |
Response 200 OK
{ "todoId": "TODO1", "status": "open" }
DELETE — Delete a Todo
DELETE {{baseUrl}}/instances/:instanceId/todos/:todoId
| Header | Value |
|---|---|
| Authorization | Bearer {{token}} |
Response 200 OK
{ "message": "deleted" }
Time Entries
Time entries are keyed by todoId + date. Submitting the same pair again overwrites the existing entry. Date format: YYYY-MM-DD.
POST — Log Time
POST {{baseUrl}}/instances/:instanceId/todos/:todoId/timeentries/:date
| Header | Value |
|---|---|
| Authorization | Bearer {{token}} |
| Content-Type | application/json |
| Path Variable | Required | Description |
|---|---|---|
| date | req | Format YYYY-MM-DD, e.g. 2026-08-19. Cannot be a future date. |
{
"actual": 3.5,
"remaining": 0.5
}
actual is required (hours logged). remaining and estimate are optional.
Response 201 CREATED
{
"actual": 3.5,
"remaining": 0.5,
"latestRemaining": 0.5,
"totalActual": 7.0,
"timesheetDate": "2026-08-19"
}
GET — Get Time Entry for a Date
GET {{baseUrl}}/instances/:instanceId/todos/:todoId/timeentries/:date
| Header | Value |
|---|---|
| Authorization | Bearer {{token}} |
| accept | application/json |
Response 200 OK
{
"actual": 3.5,
"remaining": 0.5,
"timesheetDate": "2026-08-19"
}
Returns 404 if no entry exists for that todo + date combination.
GET — List Time Entries by Date Range
GET {{baseUrl}}/timeentries?timesheetStartDate=2026-08-01×heetEndDate=2026-08-19&limit=50
| Header | Value |
|---|---|
| Authorization | Bearer {{token}} |
| accept | application/json |
| Param | Required | Description |
|---|---|---|
| timesheetStartDate | req | YYYY-MM-DD |
| timesheetEndDate | req | YYYY-MM-DD |
| workspaceIds[] | opt | Repeatable — filter by workspace |
| limit | opt | 1–100, default 50 |
| pageToken | opt | Cursor for next page |
Response 200 OK
{
"items": [
{
"todoId": "TODO1",
"instanceId": "523440-42",
"actual": 3.5,
"timesheetDate": "2026-08-19"
}
],
"total": 1
}
