Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.contraforce.com/llms.txt

Use this file to discover all available pages before exploring further.

The v2 API surfaces every error as an RFC 7807 ProblemDetails document, served as application/problem+json. Switch on the code extension — it’s part of the contract and won’t move under your feet. The title and detail strings are human-readable and may be reworded between releases.

Response shape

{
  "type": "https://docs.contraforce.com/api-reference/errors",
  "title": "Resource not found",
  "status": 404,
  "detail": "Incident 'INC-12345' not found",
  "instance": "/api/v2/workspaces/6eca6a1f-b7d1-4bb8-a055-35ad6bb4b9b1/incidents/Sentinel/INC-12345",
  "code": "NOT_FOUND",
  "requestId": "0HNLBAGCRD4RN:00000003",
  "timestamp": "2026-04-15T20:00:00.0000000+00:00"
}
FieldSourceDescription
typeRFC 7807URI identifying the problem class. Points at this reference page (https://docs.contraforce.com/api-reference/errors); the code extension is the programmatic discriminator.
titleRFC 7807Short, stable per-code summary.
statusRFC 7807HTTP status code, mirrored in the response status line.
detailRFC 7807Per-instance message describing what went wrong.
instanceRFC 7807URI of the failing request.
codeextensionStable identifier you should switch on. See the catalogue below.
requestIdextensionTrace identifier for the failed request. Quote this when contacting support.
timestampextensionUTC ISO-8601 timestamp the failure was generated at.
targetextension, optionalField or identifier the error refers to.
errorsextension, optionalField-keyed validation error map. Empty key means an object-level error.

Validation responses

When binding fails or a FluentValidation rule rejects, the response includes an errors map:
{
  "type": "https://docs.contraforce.com/api-reference/errors",
  "title": "Validation failed",
  "status": 400,
  "detail": "One or more validation errors occurred.",
  "instance": "/api/v2/workspaces/.../incidents/Sentinel/INC-12345/comments",
  "code": "VALIDATION_ERROR",
  "errors": {
    "content": ["'Content' must not be empty."],
    "extensionId": ["'Extension Id' is required."],
    "": ["At least one of source or workspaceId must be provided."]
  },
  "requestId": "0HNLBAGCRD4RN:00000007",
  "timestamp": "2026-04-15T20:00:00.0000000+00:00"
}
Keys are JSON property paths; the empty key carries object-level errors that aren’t tied to a specific field.

Error code catalogue

CodeStatusWhen you see itWhat to do
VALIDATION_ERROR400A required field is missing, malformed, or rejected by validation. The errors extension carries the per-field detail.Inspect the errors map. Empty keys map to object-level errors; named keys map to JSON paths.
BAD_REQUEST400A 400 not classified as a validation failure (e.g. a malformed body the framework couldn’t parse at all).Inspect detail. Confirm the body matches the documented shape.
UNAUTHORIZED401Missing or invalid Authorization header, revoked or rotated clientSecret, or a disabled service account.Re-authenticate with valid credentials. If you rotated, update both halves of the credential.
FORBIDDEN403Authenticated, but the calling principal can’t perform this action on this resource.Check that the credential carries the scope the endpoint requires and that the service account has the right workspace role.
INSUFFICIENT_SCOPE403The credential is missing one of the scopes required by the endpoint.Add the scope to the credential in the portal. Scopes follow the {resource}:{action} convention.
INSUFFICIENT_WORKSPACE_ROLE403The calling principal has no role on the target workspace.Have an organization admin assign a workspace role to the service account.
MFA_REQUIRED403The user-flow path requires MFA from the configured IdP.Complete the MFA challenge in the portal. Service accounts do not encounter this code.
USER_NOT_REGISTERED403The authenticated user is not registered in the ContraForce user store.An organization admin must sync or invite the user before they can call the API.
EXTENSION_NOT_ENABLED400The endpoint requires an integration (e.g. Defender XDR, Jira) that hasn’t been consented and enabled for this workspace.Enable the integration via the workspace configuration endpoints or in the portal.
NOT_FOUND404A workspace, incident, gamebook, or other addressed resource doesn’t exist or isn’t visible to the credential.Verify the IDs in the path. For workspace-scoped routes, confirm the workspace is mapped to the service account.
METHOD_NOT_ALLOWED405Wrong HTTP verb on the route.Check the endpoint reference for the correct verb.
CONFLICT409The resource version on the server differs from yours, the same operation was already performed, or two concurrent writes collided.Refetch the resource and retry with the latest state.
UNSUPPORTED_MEDIA_TYPE415Wrong Content-Type header for the body shape.Use application/json for JSON requests, multipart/form-data for SOP uploads.
RATE_LIMITED429Too many requests in the rolling window.Honor Retry-After if present, otherwise back off exponentially.

Mapping behavior

A few specific cases are worth calling out because they affect how you should design retries and surface failures to your own users.
When a downstream SIEM rejects a request with a 4xx (404 for an unknown ID, 400 for an unparseable filter, 409 for a conflict, 429 for rate-limit, 408/504 for timeout), the v2 API surfaces that as the matching 4xx — NOT_FOUND, VALIDATION_ERROR, CONFLICT, RATE_LIMITED, TIMEOUT — rather than collapsing onto an opaque 502. That way your retry logic can act on what’s actually wrong.Only opaque or 5xx upstream failures stay as UPSTREAM_ERROR. Upstream 401/403 also stay opaque (they mean our credential to the upstream is broken; that’s not something you can fix).
When the caller disconnects mid-request, the response is an empty 499 and no ProblemDetails body is written. Treat 499 as “request was cancelled before we could respond” — your client probably already knows.
Some development-mode payloads previously carried a traceId extension from ASP.NET. The v2 contract is requestId only. Quote the requestId value when contacting support — we can correlate it to backend logs without you needing to share anything else.

Correlating with our logs

Every requestId is also recorded in our backend logs. Including it in support requests dramatically shortens triage:
Hello, I’m seeing intermittent 502 UPSTREAM_ERROR on POST /api/v2/incidents/across-workspaces. Example requestId: 0HNLBAGCRD4RN:00000003 at 2026-04-15T20:00:00Z.
We can pull the full backend trace and pinpoint the failure without needing the request body or your credentials.