API reference
Skunk Works is the hub's project management: each project's work items (stories, tasks, bugs and epics), its backlog and its sprints. With the skunkworks:read scope a key reads them in every project of the account that has opened Skunk Works: the projects and their key prefixes, the items with their status, sprint, epic, labels, assignee and dates, one item with its description, its linked Data Management documents and its whole history (comments included), and the sprints with their totals and, once finished, their review. An item is named by its key, such as WR-12; a key with a project's old prefix still finds the item. The API is read-only for Skunk Works: items are created and changed in the hub, and reading never opens Skunk Works in a project that has not used it.
/v1/skunkworks/projectsskunkworks:readThe account's projects that have opened Skunk Works, the most recently opened first, each with its key prefix (and any prefixes it had before), how many items and epics it holds, how many are still open, and its running sprint. A project that has never opened Skunk Works is not listed, and listing does not open it. Deleted projects are left out.
| Name | Type | Description |
|---|---|---|
limitquery | integer | How many to return. 1 to 100. Default 25. |
cursorquery | string | The next_cursor from the previous page. Leave it out for the first page. |
| Field | Type | Description |
|---|---|---|
data | array of object | |
data[].project_id | string (uuid) | The project's id (the same id as in List projects). |
data[].name | string | The project's name. |
data[].key_prefix | string | The prefix of its item keys, such as WR in WR-12. |
data[].old_prefixes | array of string | Prefixes it had before. Keys with them still find its items. |
data[].items | integer | Its work items, epics not counted. |
data[].open_items | integer | Those not yet done. |
data[].epics | integer | |
data[].open_sprints | integer | Sprints planned or running. |
data[].active_sprint_id | string or null (uuid) | The running sprint, or null. |
data[].opened_at | string (date-time) | When Skunk Works was first opened in the project. |
has_more | boolean | |
next_cursor | string or null |
The codes are listed under Errors.
curl "https://api.veragen.ai/v1/skunkworks/projects?limit=25" \
-H "Authorization: Bearer $VERAGEN_API_KEY"const res = await fetch("https://api.veragen.ai/v1/skunkworks/projects?limit=25", {
headers: { Authorization: `Bearer ${process.env.VERAGEN_API_KEY}` },
});
const data = await res.json();import os, requests
res = requests.get(
"https://api.veragen.ai/v1/skunkworks/projects",
params={"limit": 25},
headers={"Authorization": f"Bearer {os.environ['VERAGEN_API_KEY']}"},
)
data = res.json(){
"data": [
{
"project_id": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
"name": "Website Redesign",
"key_prefix": "WR",
"old_prefixes": [],
"items": 42,
"open_items": 17,
"epics": 3,
"open_sprints": 2,
"active_sprint_id": "2b3c4d5e-6f70-4812-93a4-b5c6d7e8f901",
"opened_at": "2026-09-14T10:02:33.120Z"
}
],
"has_more": false,
"next_cursor": null
}/v1/skunkworks/projects/{project_id}/itemsskunkworks:readA project's work items, epics included, most recently changed first. Filters combine: status, type, sprint_id (one sprint, from List sprints), assignee_email (the person's sign-in email, any case), epic_key (the items in one epic), label, q (an item key, or words in the title or description) and changed_since (only items changed at or after a time, for keeping another system in step). A value that is not one of the listed ones is refused with 400 invalid_parameter, never ignored.
| Name | Type | Description |
|---|---|---|
project_idpath, required | string (uuid) | The project's id, from List Skunk Works projects. |
limitquery | integer | How many to return. 1 to 100. Default 25. |
cursorquery | string | The next_cursor from the previous page. Leave it out for the first page. |
statusquery | string | Only items with this status. One of todo, in_progress, in_review, done. |
typequery | string | Only items of this type. One of story, task, bug, epic. |
sprint_idquery | string (uuid) | Only the items in this sprint. |
assignee_emailquery | string (email) | Only the items assigned to the person with this sign-in email. |
epic_keyquery | string | Only the items in this epic, by its key. |
labelquery | string | Only the items with this label. |
qquery | string | An item key, or words in the title or description. |
changed_sincequery | string | Only items changed at or after this time: a date (YYYY-MM-DD, UTC) or an ISO-8601 date and time with a zone. |
| Field | Type | Description |
|---|---|---|
data | array of object | |
data[].key | string | The item's key, such as WR-12. It does not change unless the project's prefix is renamed (and the old key still finds it). |
data[].title | string | |
data[].type | string | |
data[].status | string | To Do, In Progress, In Review or Done. |
data[].priority | string | |
data[].points | integer or null | Its estimate in points, or null. |
data[].due_date | string or null (date) | |
data[].labels | array of string | |
data[].epic_key | string or null | The epic it belongs to, by key. |
data[].sprint_id | string or null (uuid) | The sprint it is in, or null in the backlog. |
data[].sprint_name | string or null | |
data[].assignee_email | string or null | The sign-in email of the person it is assigned to. |
data[].assignee_name | string or null | |
data[].linked_documents | integer | How many Data Management documents are linked to it, from its description, its comments or by hand. |
data[].created_at | string (date-time) | |
data[].updated_at | string (date-time) | When anything about it last changed. Lists are ordered by it, newest first. |
data[].closed_at | string or null (date-time) | When it was done, or null. |
has_more | boolean | |
next_cursor | string or null |
The codes are listed under Errors.
curl "https://api.veragen.ai/v1/skunkworks/projects/{project_id}/items?limit=25" \
-H "Authorization: Bearer $VERAGEN_API_KEY"const res = await fetch("https://api.veragen.ai/v1/skunkworks/projects/{project_id}/items?limit=25", {
headers: { Authorization: `Bearer ${process.env.VERAGEN_API_KEY}` },
});
const data = await res.json();import os, requests
res = requests.get(
"https://api.veragen.ai/v1/skunkworks/projects/{project_id}/items",
params={"limit": 25},
headers={"Authorization": f"Bearer {os.environ['VERAGEN_API_KEY']}"},
)
data = res.json(){
"data": [
{
"key": "WR-12",
"title": "Pricing page: annual toggle",
"type": "story",
"status": "in_progress",
"priority": "high",
"points": 5,
"due_date": "2026-10-16",
"labels": [
"frontend"
],
"epic_key": "WR-3",
"sprint_id": "2b3c4d5e-6f70-4812-93a4-b5c6d7e8f901",
"sprint_name": "Sprint 4",
"assignee_email": "sam@acme.example",
"assignee_name": "Sam Ortiz",
"linked_documents": 1,
"created_at": "2026-10-01T09:12:40.512Z",
"updated_at": "2026-10-06T15:30:02.004Z",
"closed_at": null
}
],
"has_more": false,
"next_cursor": null
}/v1/skunkworks/projects/{project_id}/items/{key}skunkworks:readOne work item by its key: everything in the list, its description as plain text and as the HTML the hub shows, the Data Management documents linked to it (by their current names, and whether each is archived), and its whole history, oldest first: created, every change of status, sprint, assignee and the other fields, documents linked, and every comment with its text. Images in the description are references to the item's own images; the API hands out no image files.
| Name | Type | Description |
|---|---|---|
project_idpath, required | string (uuid) | The project's id, from List Skunk Works projects. |
keypath, required | string | The item's key, such as WR-12. A key with one of the project's old prefixes, or the number alone, finds it too. |
| Field | Type | Description |
|---|---|---|
key | string | The item's key, such as WR-12. It does not change unless the project's prefix is renamed (and the old key still finds it). |
title | string | |
type | string | |
status | string | To Do, In Progress, In Review or Done. |
priority | string | |
points | integer or null | Its estimate in points, or null. |
due_date | string or null (date) | |
labels | array of string | |
epic_key | string or null | The epic it belongs to, by key. |
sprint_id | string or null (uuid) | The sprint it is in, or null in the backlog. |
sprint_name | string or null | |
assignee_email | string or null | The sign-in email of the person it is assigned to. |
assignee_name | string or null | |
linked_documents | integer | How many Data Management documents are linked to it, from its description, its comments or by hand. |
created_at | string (date-time) | |
updated_at | string (date-time) | When anything about it last changed. Lists are ordered by it, newest first. |
closed_at | string or null (date-time) | When it was done, or null. |
description_text | string | The description as plain text. |
description_html | string | The description as the hub shows it: formatting, links, document and item chips, and references to the item's images. |
documents | array of object | The Data Management documents linked to it. |
documents[].id | string (uuid) | The document's id in Data Management (Get an item, with content:read). |
documents[].name | string | Its name now. |
documents[].archived | boolean | true when it has been archived in Data Management. |
history | array of object | Everything that happened to it, oldest first, comments included. |
history[].id | string (uuid) | |
history[].at | string (date-time) | |
history[].kind | string | What happened, such as created, status, sprint, assignee, priority, points, due, epic, labels, title, description, comment, mention, doclink, docunlink, attachment, resolution or reopened. More kinds may be added. |
history[].actor_email | string or null | Who did it: their sign-in email. null when the hub did it itself. |
history[].from | string or null | For a change, the value before, as the hub shows it (a status, a sprint's name or Backlog, an email or Unassigned). |
history[].to | string or null | For a change, the value after; for a mention, the email of the person mentioned; for a document, its name. |
history[].text | string or null | For a comment, its text. |
The codes are listed under Errors.
curl "https://api.veragen.ai/v1/skunkworks/projects/{project_id}/items/{key}" \
-H "Authorization: Bearer $VERAGEN_API_KEY"const res = await fetch("https://api.veragen.ai/v1/skunkworks/projects/{project_id}/items/{key}", {
headers: { Authorization: `Bearer ${process.env.VERAGEN_API_KEY}` },
});
const data = await res.json();import os, requests
res = requests.get(
"https://api.veragen.ai/v1/skunkworks/projects/{project_id}/items/{key}",
headers={"Authorization": f"Bearer {os.environ['VERAGEN_API_KEY']}"},
)
data = res.json(){
"key": "WR-12",
"title": "Pricing page: annual toggle",
"type": "story",
"status": "in_progress",
"priority": "high",
"points": 5,
"due_date": "2026-10-16",
"labels": [
"frontend"
],
"epic_key": "WR-3",
"sprint_id": "2b3c4d5e-6f70-4812-93a4-b5c6d7e8f901",
"sprint_name": "Sprint 4",
"assignee_email": "sam@acme.example",
"assignee_name": "Sam Ortiz",
"linked_documents": 1,
"created_at": "2026-10-01T09:12:40.512Z",
"updated_at": "2026-10-06T15:30:02.004Z",
"closed_at": null,
"description_text": "Add a monthly / annual toggle above the plan cards. Annual shows the yearly price and the saving.",
"description_html": "<p>Add a monthly / annual toggle above the plan cards. Annual shows the yearly price and the saving.</p>",
"documents": [
{
"id": "5d4c3b2a-1f0e-4d9c-8b7a-6e5f4d3c2b1a",
"name": "Pricing research",
"archived": false
}
],
"history": [
{
"id": "a1b2c3d4-e5f6-4071-8293-a4b5c6d7e8f9",
"at": "2026-10-01T09:12:40.512Z",
"kind": "created",
"actor_email": "lee@acme.example",
"from": null,
"to": "todo",
"text": null
},
{
"id": "b2c3d4e5-f607-4182-93a4-b5c6d7e8f9a0",
"at": "2026-10-02T08:00:11.300Z",
"kind": "sprint",
"actor_email": "lee@acme.example",
"from": "Backlog",
"to": "Sprint 4",
"text": null
},
{
"id": "c3d4e5f6-0718-4293-a4b5-c6d7e8f9a0b1",
"at": "2026-10-06T15:30:02.004Z",
"kind": "comment",
"actor_email": "sam@acme.example",
"from": null,
"to": null,
"text": "Toggle is in; the saving badge is next."
}
]
}/v1/skunkworks/projects/{project_id}/sprintsskunkworks:readA project's sprints, newest first: planned, running (active) and finished (completed). A sprint that was removed before it started is left out. Each carries its dates, its goal, and what is in it now: the number of items and points, and how many of them are done. When a sprint is completed its unfinished items move on, so a completed sprint's totals are the work it finished. A completed sprint also carries its review, as the team saved it.
| Name | Type | Description |
|---|---|---|
project_idpath, required | string (uuid) | The project's id, from List Skunk Works projects. |
limitquery | integer | How many to return. 1 to 100. Default 25. |
cursorquery | string | The next_cursor from the previous page. Leave it out for the first page. |
statequery | string | Only sprints in this state. One of planned, active, completed. |
| Field | Type | Description |
|---|---|---|
data | array of object | |
data[].id | string (uuid) | |
data[].name | string | |
data[].goal | string | |
data[].state | string | planned, active (running) or completed. |
data[].starts_on | string or null (date) | |
data[].ends_on | string or null (date) | |
data[].items | integer | The items in it now. |
data[].items_done | integer | |
data[].points | integer | Their points added up. |
data[].points_done | integer | The points of the items that are done. |
data[].review | string or null | A completed sprint's review, as the team saved it; null otherwise. |
data[].started_at | string or null (date-time) | |
data[].completed_at | string or null (date-time) | |
data[].created_at | string (date-time) | |
has_more | boolean | |
next_cursor | string or null |
The codes are listed under Errors.
curl "https://api.veragen.ai/v1/skunkworks/projects/{project_id}/sprints?limit=25" \
-H "Authorization: Bearer $VERAGEN_API_KEY"const res = await fetch("https://api.veragen.ai/v1/skunkworks/projects/{project_id}/sprints?limit=25", {
headers: { Authorization: `Bearer ${process.env.VERAGEN_API_KEY}` },
});
const data = await res.json();import os, requests
res = requests.get(
"https://api.veragen.ai/v1/skunkworks/projects/{project_id}/sprints",
params={"limit": 25},
headers={"Authorization": f"Bearer {os.environ['VERAGEN_API_KEY']}"},
)
data = res.json(){
"data": [
{
"id": "2b3c4d5e-6f70-4812-93a4-b5c6d7e8f901",
"name": "Sprint 4",
"goal": "Ship the new pricing page.",
"state": "active",
"starts_on": "2026-10-05",
"ends_on": "2026-10-16",
"items": 9,
"items_done": 3,
"points": 31,
"points_done": 11,
"review": null,
"started_at": "2026-10-05T08:30:00.000Z",
"completed_at": null,
"created_at": "2026-09-29T14:00:00.000Z"
},
{
"id": "3c4d5e6f-7081-4923-a4b5-c6d7e8f9a012",
"name": "Sprint 3",
"goal": "Navigation and footer.",
"state": "completed",
"starts_on": "2026-09-21",
"ends_on": "2026-10-02",
"items": 8,
"items_done": 8,
"points": 26,
"points_done": 26,
"review": "Finished the navigation and the footer; the search box moved to Sprint 4.",
"started_at": "2026-09-21T08:30:00.000Z",
"completed_at": "2026-10-02T16:45:10.000Z",
"created_at": "2026-09-15T11:20:00.000Z"
}
],
"has_more": false,
"next_cursor": null
}