Software Factory

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-api

Create an API key

Every request needs an External API key for the project you want to work in.

  1. In your project, open Settings → API Keys → External API.
  2. Select Create External API Key and enter a Name.
  3. Under Expiration, choose 90 days (the default), 1 year, or Custom, or turn on Never expires.
  4. 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:

ResourceWhat you can do
RequirementsList, search, read, create, save, rename, move, and delete requirements documents. Read versions and comment threads, add comments, and propose edits as tracked suggestions.
BlueprintsThe same operations for blueprints, plus listing blueprint categories.
Work ordersList, 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 BaseList, read, download, create, update, and delete Knowledge Base resources, and delete folders.
Feedback itemsList and read feedback, read and add comments, manage labels, and link feedback to work orders.
Feedback themesList, 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.
UsersList project members, optionally filtered by name or email.
AutomationsList, read, create, and update automations, and list the integrations you can grant to one. The API does not run or delete automations.
Agent conversationsList and read the agent conversations that belong to the key's creator.
HealthCheck 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 page and page_size in the request body, with the same default and maximum. Its response contains only items, so keep requesting the next page until one comes back with fewer than page_size items.
  • Agent conversations are cursor-based. page_size defaults to 20 and can be at most 100. Each response includes next_cursor, which is null at the end of the collection. To fetch the next page, pass it back unchanged as the cursor query 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.

On this page