Skip to content

Permissions & Errors

Authorization combines the partner-specific hostname, a matching API credential, the endpoint scope, and resource ownership checks.

Permission matrix

Method and path Required scope Ownership rule
POST /v1/workspaces workspaces:write Workspace is created or reused inside the authenticated partner tenant
GET /v1/workspaces workspaces:read Only the authenticated partner's workspaces are returned
GET /v1/workspaces/{workspace_id} workspaces:read Workspace must belong to the authenticated partner
POST /v1/workspaces/{workspace_id}/visibility-reports reports:write Workspace must belong to the authenticated partner
GET /v1/workspaces/{workspace_id}/visibility-reports reports:read Workspace must belong to the authenticated partner
GET /v1/visibility-reports/{report_id} reports:read Report's workspace must belong to the authenticated partner
GET /v1/workspaces/{workspace_id}/actions actions:read Workspace must belong to the authenticated partner
GET /v1/actions/{action_id} actions:read Action's workspace must belong to the authenticated partner
POST /v1/actions/{action_id}/executions actions:write Action's workspace must belong to the authenticated partner
GET /v1/action-executions/{execution_id} actions:read Execution's action must belong to the authenticated partner
GET /v1/action-executions/{execution_id}/output actions:read Execution and output must belong to the authenticated partner
POST /v1/action-executions/{execution_id}/output/images/{image_index}/generate actions:write Execution must resolve to the authenticated partner's completed article
GET /v1/action-executions/{execution_id}/output/images/{image_index} Signed URL URL must be valid for the partner host, execution, image position, current image, and expiration

Scopes do not nest. For example, actions:write does not grant actions:read, and report scopes do not grant workspace scopes.

X-External-Actor-Id does not change any ownership or permission rule.

Isolation behavior

  • A request that does not use a recognized partner hostname returns 404.
  • Missing, invalid, expired, inactive, or host-mismatched credentials return the same 401.
  • A valid credential without the endpoint scope returns 403.
  • Missing and cross-tenant resources both return 404; the response does not reveal whether a resource exists for another tenant.
  • A cursor must belong to the same collection hierarchy and match the active filters.

Error response shapes

The type of detail depends on the status and validation path. Branch on the HTTP status before inspecting it.

Status Typical detail shape
400 String
401 Object with code: "invalid_partner_credentials"
403 Object with code: "insufficient_scope" and required_scope
404 String
409 Object with a code, or a string for a non-executable action state
422 Validation array, model-selection string, or invalid_created_range object
500 String
503 Object with report_not_queued or action_output_not_queued

Invalid credentials — 401

{
  "detail": {
    "code": "invalid_partner_credentials"
  }
}

The response includes WWW-Authenticate: Bearer. Correct the hostname or credential before retrying.

Insufficient scope — 403

{
  "detail": {
    "code": "insufficient_scope",
    "required_scope": "reports:write"
  }
}

Use a credential issued with the named scope.

Invalid cursor — 400

{
  "detail": "Invalid cursor"
}

Restart without cursor, or send the exact pagination.next_cursor returned by the preceding page of the same collection with the same filters.

Not found — 404

Examples include:

{
  "detail": "Workspace not found"
}
{
  "detail": "Action execution not found"
}
{
  "detail": "Generated image not found"
}

The API does not distinguish a missing resource from one that belongs to another partner.

Conflict — 409

Generated output is not ready:

{
  "detail": {
    "code": "output_not_ready"
  }
}

The execution is not an article output:

{
  "detail": {
    "code": "article_output_required"
  }
}

A manual action or an action in a non-executable lifecycle state returns a string detail, for example:

{
  "detail": "Action type technical_change is completed manually"
}

Validation — 422

Standard request validation returns an array:

{
  "detail": [
    {
      "type": "greater_than_equal",
      "loc": ["query", "limit"],
      "msg": "Input should be greater than or equal to 1",
      "input": "0",
      "ctx": {"ge": 1}
    }
  ]
}

An invalid date window returns:

{
  "detail": {
    "code": "invalid_created_range"
  }
}

Workspace model-selection rules return a string, for example:

{
  "detail": "At least one analysis model must be enabled"
}

Not queued — 503

Report launch:

{
  "detail": {
    "code": "report_not_queued"
  }
}

Retry with the same Idempotency-Key; no report was created for that failed attempt.

Action output launch:

{
  "detail": {
    "code": "action_output_not_queued"
  }
}

The action is left in failed and can be executed again as a new attempt.

HTTP failures versus asynchronous failures

An HTTP failure describes the API request itself. An asynchronous report or content-generation failure is returned as a normal resource response:

  • a failed report returns 200 with status: "failed", result: null, and an error;
  • a failed action execution returns 200 with status: "failed", output_url: null, and an error.

Always inspect both the HTTP status and the returned asynchronous resource status.

The API Reference lists the possible responses for every endpoint.