Split an issue into sub-issues
const url = 'https://api.pealboard.com/v1/issues/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/sub-issues';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"children":[{"repositoryId":"2489E9AD-2EE2-8E00-8EC9-32D5F69181C0","title":"example","body":"example"}]}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://api.pealboard.com/v1/issues/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/sub-issues \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "children": [ { "repositoryId": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "title": "example", "body": "example" } ] }'Creates each child in the repository it names and links it to this issue as a GitHub sub-issue. A child may be in a different repository, which is the point: an issue filed in the workspace’s tracking repository is split into the code repositories that will actually carry the work. GitHub allows this within one account, and every repository a Pealboard workspace can see belongs to one.
Each child’s body ends with Part of <owner>/<repo>#<number> naming this issue, so the relationship is legible on GitHub to somebody reading the child on its own, and the usual Pealboard attribution is added above it when the issue is written as pealboard[bot].
Creating and linking are two GitHub calls, and the second one can be refused on its own. GitHub allows a hundred sub-issues per parent and eight levels of nesting; a child past either limit is created and not attached, and comes back as linked: false with GitHub’s own sentence in error. The issue exists in GitHub either way — reporting it as a failure would be reporting a write GitHub accepted as one it did not.
A closed issue cannot be split (409): sub-issues are how work is planned, and planning work under something that is finished is a mistake worth refusing rather than recording.
One to twenty children per request, because each one is a GitHub write. Send Idempotency-Key to make a retry return the first answer rather than creating a second set.
Access. Requires the member role or above (member, admin, owner). Splitting an issue creates issues in the customer’s GitHub repositories under their installation. API-key scope: issues:write.
Billing. Refused with 402 while the workspace’s billing has lapsed. Reads continue and nothing is deleted.
Retries. Send Idempotency-Key and a retry with the same key within 24 hours returns the first answer rather than acting twice.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Path Parameters
Section titled “Path Parameters”From GET /v1/issues.
From GET /v1/issues.
Request Body
Section titled “Request Body”object
object
From GET /v1/github/repositories. It may be a different repository from the parent’s.
Examplegenerated
{ "children": [ { "repositoryId": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "title": "example", "body": "example" } ]}Responses
Section titled “Responses”The parent, with its refreshed sub-issue summary, and every child with whether GitHub attached it.
object
object
A UUID this API issued.
What the person typed. The attribution block Pealboard writes for a portal request or for a member, and the hidden marker beside it, are stripped here and kept on GitHub. Sending an edited body back keeps them.
GitHub’s own word for whether the issue is open or closed.
Why the issue is in this state. Null while it is open. duplicate is what makes a portal show a request as Merged.
The issue this one was closed as a duplicate of, when the close went through Pealboard with duplicateOfIssueId. GitHub takes the canonical issue and never sends it back, so a duplicate closed on GitHub itself is stateReason: duplicate with null here. Cleared on reopen.
object
A UUID this API issued.
object
GitHub’s numeric user id.
User, Bot or Organization.
object
A UUID this API issued.
The display name. Never an email address.
team: a workspace member, the same word a portal uses for the same people. customer: a portal customer, whose request or comment the App wrote on their behalf; membershipId is null.
object
GitHub’s numeric user id.
User, Bot or Organization.
object
object
A UUID this API issued.
A UUID this API issued.
The organization issue type, when the organization uses them.
object
object
The issue this one was split out of, when it is a sub-issue. The children are GET /v1/issues/{issueId}/sub-issues.
object
Null when the parent’s repository is not synced, so Pealboard holds no row for it.
object
A UUID this API issued.
object
Pass this to the project item routes.
A UUID this API issued.
Keyed by the field’s node id, which is what GitHub identifies it by.
object
object
object
object
object
object
object
Empty for an issue no portal knows about, which is most of them.
A portal request that points at this issue. One issue maps to at most one request per portal.
object
A UUID this API issued.
A UUID this API issued.
Lowercase letters, digits and hyphens.
The portal-local request number.
The issue on GitHub.
When Pealboard last read this issue from GitHub.
object
object
A UUID this API issued.
What the person typed. The attribution block Pealboard writes for a portal request or for a member, and the hidden marker beside it, are stripped here and kept on GitHub. Sending an edited body back keeps them.
GitHub’s own word for whether the issue is open or closed.
Why the issue is in this state. Null while it is open. duplicate is what makes a portal show a request as Merged.
The issue this one was closed as a duplicate of, when the close went through Pealboard with duplicateOfIssueId. GitHub takes the canonical issue and never sends it back, so a duplicate closed on GitHub itself is stateReason: duplicate with null here. Cleared on reopen.
object
A UUID this API issued.
object
GitHub’s numeric user id.
User, Bot or Organization.
object
A UUID this API issued.
The display name. Never an email address.
team: a workspace member, the same word a portal uses for the same people. customer: a portal customer, whose request or comment the App wrote on their behalf; membershipId is null.
object
GitHub’s numeric user id.
User, Bot or Organization.
object
object
A UUID this API issued.
A UUID this API issued.
The organization issue type, when the organization uses them.
object
object
The issue this one was split out of, when it is a sub-issue. The children are GET /v1/issues/{issueId}/sub-issues.
object
Null when the parent’s repository is not synced, so Pealboard holds no row for it.
object
A UUID this API issued.
object
Pass this to the project item routes.
A UUID this API issued.
Keyed by the field’s node id, which is what GitHub identifies it by.
object
object
object
object
object
object
object
Empty for an issue no portal knows about, which is most of them.
A portal request that points at this issue. One issue maps to at most one request per portal.
object
A UUID this API issued.
A UUID this API issued.
Lowercase letters, digits and hyphens.
The portal-local request number.
The issue on GitHub.
When Pealboard last read this issue from GitHub.
False when the issue was created and GitHub refused the link.
GitHub’s own sentence, when it refused the link.
Example
{ "parent": { "id": "8f1c2b3e-0a4d-4e6f-9c11-2d3e4f5a6b7c", "nodeId": "I_kwDOAbc123", "number": 412, "title": "Board columns lose their order after a drag", "body": "Dragging a card to the last column reorders every other column.", "state": "open", "stateReason": null, "duplicateOfIssueId": null, "repository": { "id": "1b2c3d4e-5f60-4718-8293-a4b5c6d7e8f9", "nodeId": "R_kgDOAbc123", "fullName": "mersoft-corp/pealboard-api", "ownerLogin": "mersoft-corp", "name": "pealboard-api", "private": false }, "author": { "id": 4891, "login": "jdoe", "avatarUrl": null, "type": "User" }, "authoredBy": null, "assignees": [ { "id": 5120, "login": "asmith", "avatarUrl": null, "type": "User" } ], "labels": [ { "nodeId": "LA_kwDOAbc", "name": "bug", "color": "d73a4a" } ], "milestone": null, "issueType": null, "subIssues": null, "parent": null, "projectItems": [], "requests": [], "commentsCount": 3, "locked": false, "htmlUrl": "https://github.com/mersoft-corp/pealboard-api/issues/412", "createdAt": "2026-09-01T09:14:00.000Z", "updatedAt": "2026-09-08T16:02:11.000Z", "closedAt": null, "syncedAt": "2026-09-08T16:02:14.000Z" }, "children": [ { "issue": { "id": "8f1c2b3e-0a4d-4e6f-9c11-2d3e4f5a6b7c", "nodeId": "I_kwDOAbc123", "number": 412, "title": "Board columns lose their order after a drag", "body": "Dragging a card to the last column reorders every other column.", "state": "open", "stateReason": null, "duplicateOfIssueId": null, "repository": { "id": "1b2c3d4e-5f60-4718-8293-a4b5c6d7e8f9", "nodeId": "R_kgDOAbc123", "fullName": "mersoft-corp/pealboard-api", "ownerLogin": "mersoft-corp", "name": "pealboard-api", "private": false }, "author": { "id": 4891, "login": "jdoe", "avatarUrl": null, "type": "User" }, "authoredBy": null, "assignees": [ { "id": 5120, "login": "asmith", "avatarUrl": null, "type": "User" } ], "labels": [ { "nodeId": "LA_kwDOAbc", "name": "bug", "color": "d73a4a" } ], "milestone": null, "issueType": null, "subIssues": null, "parent": null, "projectItems": [], "requests": [], "commentsCount": 3, "locked": false, "htmlUrl": "https://github.com/mersoft-corp/pealboard-api/issues/412", "createdAt": "2026-09-01T09:14:00.000Z", "updatedAt": "2026-09-08T16:02:11.000Z", "closedAt": null, "syncedAt": "2026-09-08T16:02:14.000Z" } } ]}No valid credentials.
object
object
A stable identifier for the kind of failure. Safe to branch on.
What went wrong, written for a person.
Structured particulars, when there are any.
object
What to do about it, when there is something to do.
Quote this when asking about a specific failure.
Examplegenerated
{ "error": { "code": "example", "message": "example", "detail": { "additionalProperty": "example" }, "remedy": "example", "requestId": "example" }}The workspace’s billing has lapsed, so writes are refused.
object
object
A stable identifier for the kind of failure. Safe to branch on.
What went wrong, written for a person.
Structured particulars, when there are any.
object
What to do about it, when there is something to do.
Quote this when asking about a specific failure.
Examplegenerated
{ "error": { "code": "example", "message": "example", "detail": { "additionalProperty": "example" }, "remedy": "example", "requestId": "example" }}Authenticated, but not permitted.
object
object
A stable identifier for the kind of failure. Safe to branch on.
What went wrong, written for a person.
Structured particulars, when there are any.
object
What to do about it, when there is something to do.
Quote this when asking about a specific failure.
Examplegenerated
{ "error": { "code": "example", "message": "example", "detail": { "additionalProperty": "example" }, "remedy": "example", "requestId": "example" }}No such resource, or it is not visible to you.
object
object
A stable identifier for the kind of failure. Safe to branch on.
What went wrong, written for a person.
Structured particulars, when there are any.
object
What to do about it, when there is something to do.
Quote this when asking about a specific failure.
Examplegenerated
{ "error": { "code": "example", "message": "example", "detail": { "additionalProperty": "example" }, "remedy": "example", "requestId": "example" }}The request conflicts with the current state.
object
object
A stable identifier for the kind of failure. Safe to branch on.
What went wrong, written for a person.
Structured particulars, when there are any.
object
What to do about it, when there is something to do.
Quote this when asking about a specific failure.
Examplegenerated
{ "error": { "code": "example", "message": "example", "detail": { "additionalProperty": "example" }, "remedy": "example", "requestId": "example" }}The request did not match the expected shape.
object
object
A stable identifier for the kind of failure. Safe to branch on.
What went wrong, written for a person.
Structured particulars, when there are any.
object
What to do about it, when there is something to do.
Quote this when asking about a specific failure.
Examplegenerated
{ "error": { "code": "example", "message": "example", "detail": { "additionalProperty": "example" }, "remedy": "example", "requestId": "example" }}Rate limited. Retry after the interval in the header.
object
object
A stable identifier for the kind of failure. Safe to branch on.
What went wrong, written for a person.
Structured particulars, when there are any.
object
What to do about it, when there is something to do.
Quote this when asking about a specific failure.
Examplegenerated
{ "error": { "code": "example", "message": "example", "detail": { "additionalProperty": "example" }, "remedy": "example", "requestId": "example" }}GitHub or another dependency refused or did not answer. Nothing in the workspace changed.
object
object
A stable identifier for the kind of failure. Safe to branch on.
What went wrong, written for a person.
Structured particulars, when there are any.
object
What to do about it, when there is something to do.
Quote this when asking about a specific failure.
Examplegenerated
{ "error": { "code": "example", "message": "example", "detail": { "additionalProperty": "example" }, "remedy": "example", "requestId": "example" }}