docs
API

Spec sections

Read one heading of a spec, search inside it, list its acceptance criteria, and what the questions route does.

The /prd paths read a spec one piece at a time, for an agent that wants a heading or the acceptance criteria rather than the whole body. They work off the document's markdown, computed on each request from the blocks the document is stored as, so they always reflect the body as it is right now.

On for every workspace. These paths carry no version segment, and they are /prd, not /documents. The id in the path is still a document id, the same UUID the spec list returns.

Spec section operations

MethodPathScopeMCP tool
GET/prd/{documentId}/sections/{heading}prd:readnone
GET/prd/{documentId}/searchprd:readnone
GET/prd/{documentId}/criteriaprd:readnone
POST/prd/{documentId}/questionsprd:writenone

Paths are relative to https://api.getnima.io, and every call carries Authorization: Bearer <your key>. Both scopes are open to any member and can be granted to an API key. See Scopes and permissions. No MCP tool wraps these routes; over MCP, read the whole spec as markdown with the spec tools in Pipeline tools.

None of these bind themselves to the workspace your credential belongs to. They check only that you own the document or belong to the workspace holding it, so a credential whose owner is a member of two workspaces reads in both.

Read one section of a spec

GET/prd/{documentId}/sections/{heading}
scopeprd:read

One section of the body, as markdown. The heading is a path segment, so URL encode it: Acceptance Criteria becomes Acceptance%20Criteria. Encode a slash in the heading as %2F (encodeURIComponent does this for you): Build / Deploy becomes Build%20%2F%20Deploy.

The match is case insensitive against the heading text at any level, and the section runs to the next heading at the same or a higher level. The heading line itself is not part of content.

Headings are matched as the markdown spells them, so a heading with bold or code formatting keeps its ** or backticks. A line inside a code block that starts with # also counts as a heading.

Response fields

headingstring
Echoed back exactly as you asked for it, not as the document spells it.
contentstring
The section body as markdown, trimmed.
blockIdsstring[]
Read with care: it lists the blocks whose text contains the heading string, not the blocks of the section.

Errors

StatuserrorWhen
403ForbiddenNot a member of the workspace holding the document
404Not FoundNo such document, or no heading matches. The message reads Section "…" not found for the second.

Search inside a spec

GET/prd/{documentId}/search
scopeprd:read

One result per matching section, most relevant first, as a bare JSON array with no pagination.

Search splits the body at every heading, whatever its level, so a result for a ## heading covers only the text before its first ###. That is narrower than a section read, which includes subsections.

relevance is a raw count: matches in the heading counted twice, plus matches in the body. It is not normalised, so it is comparable between sections of one document and meaningless between documents. The snippet is roughly 60 characters either side of the first match. When q matches only the heading, snippet is the first 120 characters of the section body instead. Text above the first heading belongs to no section and is not searched.

qstring
Case insensitive substring. Only the first 200 characters are used.

Always send q. Omitting it matches every section with a relevance proportional to the section's length, which reads like a ranking and is not one.

Response fields

headingstring
The section's own heading text, as the document spells it.
snippetstring
A window around the first match in the body, with an ellipsis on each truncated side. For a heading-only match, the first 120 characters of the body, with no ellipsis.
relevanceinteger
The raw count described above.

Errors

StatuserrorWhen
403ForbiddenNot a member of the workspace holding the document
404Not FoundNo such document

List the acceptance criteria

GET/prd/{documentId}/criteria
scopeprd:read

Reads one section, the one headed Acceptance Criteria, and returns its checkbox lines as a bare JSON array.

A ticked box is met, an empty box is pending. Only top-level checkbox lines count: - [x] or - [X] is met, - [ ] is pending. Indented (nested) checkboxes and any other lines are skipped. The heading match is case insensitive, and a document without that heading returns an empty array rather than an error, which is the same answer as a spec whose criteria are all prose.

Response fields

criterionstring
The line with the checkbox stripped off.
sectionstring
Always Acceptance Criteria, since that is the only section read.
statusenum
met or pending. The shape also allows unmet; nothing produces it today.

Errors

StatuserrorWhen
403ForbiddenNot a member of the workspace holding the document
404Not FoundNo such document

Raise a question on a spec

POST/prd/{documentId}/questions
scopeprd:write

This endpoint records nothing. It echoes your question back with a generated id and threadId, never looks at documentId, and nothing appears in nima. It answers 201 for a document that does not exist and for one you are not allowed to read. Do not build on it. Not available yet as a real feature.

It is written up here because a key with prd:write reaches it and gets a success back, which is worth knowing before you treat that success as a record. The shape is not promised: it is a placeholder for the comment integration.

sectionstringrequired
The heading the question is about. Not checked against the document.
questionstringrequired
The question itself.
severityenumrequired
blocking, clarification or suggestion.

Response fields

idstring
Generated per call, from the clock. Not a UUID, and not stored anywhere.
sectionstring
Your section, unchanged.
questionstring
Your question, unchanged.
severityenum
Your severity, unchanged.
createdAtISO 8601
The moment of the call, UTC.
threadIdstring
Generated the same way as id. It leads to no thread.

Errors

StatuserrorWhen
400Bad RequestA missing field, or a severity outside the three values
403INSUFFICIENT_PERMISSIONSMissing prd:write scope, a role without the permission, or a plan without prd_generation

There is no 403 Forbidden and no 404 for the document, whatever id you put in the path; a missing prd:write scope still answers 403 INSUFFICIENT_PERMISSIONS.

The spec section object

The spec section object is what a section read returns.

headingstring
The heading you asked for, echoed.
contentstring
Everything under it, down to the next heading at the same or a higher level, as markdown.
blockIdsstring[]
The blocks whose text contains the heading string. Not the blocks of the section.

The spec search result object

headingstring
The matching section's heading.
snippetstring
Around 60 characters either side of the first match.
relevanceinteger
Heading matches counted twice plus body matches. Only comparable inside one document.

The acceptance criterion object

criterionstring
The checkbox line, without the box.
sectionstring
Always Acceptance Criteria.
statusenum
met for a ticked box, pending for an empty one.

The spec question object

idstring
Generated per call. Nothing stores it.
sectionstring
As sent.
questionstring
As sent.
severityenum
As sent.
createdAtISO 8601
The moment of the call, UTC.
threadIdstring
Generated per call. It leads to no thread.

Plan feature for the spec section routes

The four spec section routes are declared under the plan feature prd_generation, separate from the documents feature the rest of the spec surface uses. A workspace whose plan lacks prd_generation can get a 403 with error set to INSUFFICIENT_PERMISSIONS and details.feature set to prd_generation. Handle that response; do not assume a scope alone is enough. Nobody is billed today.

Errors from the spec section routes

Errors from the spec section routes use nima's standard envelope, described in API errors. As on the specs routes, the error field is not dependable: branch on statusCode, and on details when it is there.

StatuserrorWhen
400Bad RequestA field failed validation on the questions route. message reads Bad Request Exception and names nothing.
403ForbiddenThe document belongs to a workspace you are not a member of
401TOKEN_INVALIDMissing, expired or revoked bearer
403INSUFFICIENT_PERMISSIONSWrong scope, a role without the permission, or a plan without prd_generation (details.feature)
404Not FoundNo such document, or no heading matches
429RATE_LIMITEDOver the limit. See Rate limits.
500INTERNAL_SERVER_ERROROn the three reads, a document id that is not a UUID reaches the database as it is, so it answers 500 rather than 404. Validate before you send.

There is no RESOURCE_NOT_FOUND on this page: because these reads are not bound to your credential's workspace, a document you cannot reach is a 403 rather than a 404 in disguise.