API reference
Authenticate and call the 8090 Software Factory REST API from your own tools, scripts, and automations.
The 8090 Software Factory REST API lets your own tools and scripts read and write requirements, blueprints, work orders, feedback, Knowledge Base resources, and automations. It can also read your agent conversations.
Base URL
All endpoints are served under a single base URL:
https://api.factory.8090.dev/v2/external-apiCreate an API key
Every request needs an External API key for the project you want to work in.
- In your project, open Settings → API Keys → External API.
- Select Create External API Key and enter a Name.
- Under Expiration, choose 90 days (the default), 1 year, or Custom, or turn on Never expires.
- Select Create Key, then copy the key from the External API Key Created dialog. The full key is shown only once.
An expired key stops working and requests return 401 with the message API key has expired. Create a new key to replace it.
Authentication
Send the key on every request as a bearer token in the Authorization header:
Authorization: Bearer sofa-ext-...You can send it in an X-API-Key: sofa-ext-... header instead.
Only External API keys, which start with sofa-ext-, work with this API. Reporting API keys (sf-rpt-) and older keys that start with sf- are rejected with 401.
A key acts as the member who created it and inherits that member's project access. If that member loses access to the project, the key stops working until their access is restored.
Keep your key secret
Treat an API key like a password. Send it only over HTTPS, keep it out of source control, and rotate it if it is ever exposed.
Resources
The reference in the sidebar groups endpoints by resource:
| Resource | What you can do |
|---|---|
| Requirements | List, search, read, create, save, rename, move, and delete requirements documents. Read versions and comment threads, add comments, and propose edits as tracked suggestions. |
| Blueprints | The same operations for blueprints, plus listing blueprint categories. |
| Work orders | List, search, read by ID or number, create and update in batches, replace a description, and delete work orders. Manage comments, list and create labels, and list phases. |
| Knowledge Base | List, read, download, create, update, and delete Knowledge Base resources, and delete folders. |
| Feedback items | List and read feedback, read and add comments, manage labels, and link feedback to work orders. |
| Feedback themes | List, read, create, update, and delete themes. Read and add comments, manage labels, link feedback items, work orders, and a feature requirements document, and set the assignee. |
| Users | List project members, optionally filtered by name or email. |
| Automations | List, read, create, and update automations, and list the integrations you can grant to one. The API does not run or delete automations. |
| Agent conversations | List and read the agent conversations that belong to the key's creator. |
| Health | Check that the API is reachable with your key. |
To submit new feedback from your application, use the Feedback Integration API instead. It has its own endpoint and key. See Feedback.
A work order's status is always one of the seven built-in statuses. If a work order has a custom status, the API reports the built-in status that represents the custom status's category, and the status filter matches it the same way. For example, a custom status in the Started category reads as in_progress.
Pagination
These list endpoints are page-based: requirements, blueprints, work orders, Knowledge Base resources, feedback items, and users. Pass the page (starting at 1) and page_size query parameters. page_size defaults to 20 and can be at most 100. Each response returns the page as items, along with total, page, page_size, and total_pages.
Some collections work differently, and each endpoint page shows which applies:
- Work order search takes
pageandpage_sizein the request body, with the same default and maximum. Its response contains onlyitems, so keep requesting the next page until one comes back with fewer thanpage_sizeitems. - Agent conversations are cursor-based.
page_sizedefaults to 20 and can be at most 100. Each response includesnext_cursor, which isnullat the end of the collection. To fetch the next page, pass it back unchanged as thecursorquery parameter, with the same filters. - Everything else returns the whole list in one response, without page metadata. This covers requirements and blueprint search, version history, comments, labels, blueprint categories, phases, feedback themes, automations, and integrations. Version lists also include a
total_count.
Errors
A 4xx status means the request needs to change before you retry it. A 5xx status means something went wrong on our side, and you can retry the request.
Most errors return a JSON body like this:
{
"detail": {
"error_code": "not_found",
"message": "A human-readable description of what went wrong.",
"details": null
},
"exception_class_name": "SofaExternalApiNotFoundException"
}error_code is a stable, machine-readable string: bad_request, unauthorized, forbidden, not_found, conflict, unprocessable_entity, internal_server_error, or bad_gateway (a service the request depends on is unavailable). Handle errors in code by error_code, not by message or exception_class_name. details is an optional object with extra context, or null when there is none.
If the key's creator doesn't have permission for an action, the API can instead return a 403 authorization denial:
{
"detail": "Authorization denied",
"reason_code": "denied_missing_relation",
"exception_class_name": "AuthorizationDeniedError",
"authz_denial": {
"attempt_id": "0b9f2d4e-3c1a-4f7e-9a51-6d2c8e7b1f30",
"occurred_at": "2026-09-29T15:04:05Z",
"reason_code": "denied_missing_relation",
"action": "work_order.update",
"resource_type": "work_order"
}
}An unexpected server error returns 500 with an error_id. Include it when you contact support so we can trace the request:
{
"detail": "An internal error occurred",
"error_id": "4bf92f3577b34da6a3ce929d0e0e4736"
}Request validation errors use a different shape: a detail array where each entry names the field that failed and why.
{
"detail": [
{
"loc": ["body", "title"],
"msg": "Field required",
"type": "missing"
}
]
}Explore the endpoints
Browse the reference by resource in the sidebar. Each page documents a single endpoint with its parameters, an example request in the language of your choice, and an example response.