Skip to content
English
  • There are no suggestions because the search field is empty.

07.04 Using the API for Integrations

SimpleRisk's v2 REST API is the supported surface for programmatic access. Authenticate with an X-API-KEY header bound to a SimpleRisk user; call CRUD endpoints under /api/v2/risks, /api/v2/governance, /api/v2/assets, etc.; integrate with the OpenAPI/Swagger documentation at /api/v2/documentation.php. No native rate limiting; no native pagination; the API is the integration surface for everything that isn't Jira or email.

Why this matters

The v2 API is the universal integration surface. Where the Jira Extra targets one specific downstream and the Notification Extra targets email, the API targets everything: scripts that import vendor risks from a spreadsheet weekly, custom dashboards that render the register in a different shape, mobile apps that let executives approve mitigations, CI pipelines that auto-close risks when their corresponding fix ships, partner integrations that pull a customer's compliance posture for a security questionnaire. None of this is Jira-specific or email-specific; all of it is API.

The honest scope to know up front: the API is read-and-write CRUD on the major SimpleRisk entities, not a complete platform SDK. You can list, create, read, update, and delete risks, controls, frameworks, audits, documents, assets, exceptions, and similar. You can't do everything the UI does — some operations (configuration changes, certain bulk operations, activation flows) aren't exposed via API. For the substantial majority of integration use cases, this is fine; for the edge cases where the API doesn't cover what you need, the path is to file a request to add the endpoint.

The other thing worth knowing: the API has no native rate limiting and no native pagination. There's no per-key request quota; integrations can call as fast as they want, bounded only by application performance. List endpoints return all matching records in one response — GET /api/v2/risks returns every risk, not the first page of risks. Plan integrations accordingly: large-result-set endpoints can produce multi-megabyte responses; integrations that hammer the API can produce real load.

The third thing: OpenAPI documentation is in-product. The Swagger UI at /api/v2/documentation.php (or /api/v2/documentation/) is auto-generated from the per-endpoint annotations. Use it as the canonical reference for endpoint shapes, parameters, and response formats — it's always current with the running install's API surface, where this article is current at write time.

Before you start

Have these in hand:

  • API access enabled — the master api toggle on; the API Extra activated. See API Key Management.
  • A dedicated user account for the integration (don't reuse an admin account); generate that user's API key.
  • Awareness of the user's permissions and team membership — the API key inherits these. The integration can do exactly what the user can do, and sees exactly what the user sees.
  • The base URL of your SimpleRisk instance (e.g., https://simplerisk.example.com).
  • A way to make HTTPS calls with custom headerscurl for ad-hoc testing; your integration's HTTP client for production.

Step-by-step

1. Authenticate every request

Pass the API key as the X-API-KEY header. Example:

curl -H "X-API-KEY: 
  
   " \ -H "Accept: application/json" \ https://simplerisk.example.com/api/v2/risks 
  

The header is the recommended pattern. Alternatives: key= as a query parameter, or key field in a POST body. The header is preferred because URLs end up in logs more often than headers.

The API authenticates each request independently — there's no session establishment for API calls. If the key is valid and the master toggle is on, the request proceeds; otherwise 401 Unauthorized.

2. Use explicit /api/v2/ paths

Every internal-facing or integration-facing call should use /api/v2/ explicitly. Don't use:

  • /api/v1/ — v1 is frozen, gated behind the "Enable API v1 Endpoints" admin setting (off by default on fresh installs), and won't have new endpoints added.
  • /api/ (unversioned) — a transitional fallback that may behave differently across versions.

Always /api/v2/ . This is also more grep-able and audit-friendly.

3. Browse the available endpoints in Swagger UI

Open https://your-simplerisk-instance/api/v2/documentation.php in a browser. The Swagger UI lists every documented endpoint grouped by topic area:

  • Risks/api/v2/risks (CRUD), /api/v2/risks/submit (the multi-step submission), /api/v2/risks/{id}/review, /api/v2/risks/{id}/mitigation.
  • Governance/api/v2/governance/frameworks, /api/v2/governance/controls, /api/v2/governance/documents.
  • Assets/api/v2/assets, /api/v2/assets/{id}.
  • Compliance/api/v2/compliance/... (tests, audits).
  • Admin/api/v2/admin/... (limited surface; some admin operations are UI-only).
  • AI/api/v2/ai/... (if the AI Extra is active).
  • Reporting/api/v2/reporting/....

Each endpoint shows its parameters, request body shape, and response format. The "Try it out" button lets you make calls against the live API directly from the docs (handy for development; don't accidentally mutate production from the docs).

4. Handle pagination... or its absence

The v2 API generally doesn't paginate. GET /api/v2/risks returns every risk the authenticated user can see. For large registers (10,000+ risks), this means multi-megabyte responses and longer response times.

Strategies:

  • Filter at the source: most list endpoints accept query parameters that narrow the result set (status, team, owner, etc.). Use them.
  • Cache locally: pull once, cache, query the cache for subsequent reads. Re-pull on a schedule.
  • Read-then-diff: pull the list, diff against a previous local snapshot, act only on the changes.
  • Use the per-record endpoints when you know the ID: GET /api/v2/risks/{id} is fast and small.

If the application later adds pagination to specific endpoints, integrations should pick it up via the response shape change (typically a next_page_token or next_url field appears).

5. Handle errors and HTTP status codes

The API returns standard HTTP status codes:

  • 200 OK — success, response body contains the result.
  • 204 No Content — success, no body (typical for DELETE).
  • 400 Bad Request — the request was malformed (missing required field, invalid format).
  • 401 Unauthorized — missing or invalid API key.
  • 403 Forbidden — the authenticated user doesn't have permission for the requested operation.
  • 404 Not Found — the resource doesn't exist (or the user can't see it due to team filtering).
  • 500 Internal Server Error — server-side error; check application logs.

Response format is JSON wrapped in a structure that includes status_code, status_message, and data:

{
  "status_code": 200,
  "status_message": "OK",
  "data": [ ... ]
}

Integrations should check status_code (or the HTTP status) before processing data.

6. Plan for rate limiting

There is no native rate limiting in the v2 API. Integrations that hammer the API at high frequency can produce real application load. To be a good citizen:

  • Throttle your own calls: don't poll GET /api/v2/risks once a second. 1-minute or longer intervals are appropriate for almost every use case.
  • Batch operations: for bulk creates/updates, use endpoints that accept arrays where available; otherwise serialize calls with appropriate spacing.
  • Cache aggressively: most data doesn't change minute-to-minute. Cache locally; re-fetch on a deliberate schedule.
  • Coordinate with the SimpleRisk operations team: if your integration is high-volume, let them know so they can monitor.

If your environment requires enforced rate limiting, deploy a reverse proxy (nginx, HAProxy) in front of SimpleRisk with rate-limiting modules; the proxy enforces the limit before requests reach the application.

7. Common integration patterns

Pattern A: Risk import from an external source.

A weekly script reads vendor risk data from a spreadsheet or external system, calls POST /api/v2/risks/submit for each new risk, deduplicates against existing risks via subject match.

Pattern B: Bidirectional sync.

A polling service reads from GET /api/v2/risks every 5 minutes, diffs against a local cache, dispatches outbound events for changed risks. See Webhook Integration for the broader webhook-substitute pattern.

Pattern C: Custom dashboard.

A custom internal dashboard reads from multiple /api/v2/... endpoints; renders the data in a custom UI tailored to specific stakeholders. The API key is bound to a service user with read-only permissions.

Pattern D: Mobile app.

A mobile app for executives reads from /api/v2/risks filtered to high-risk items; lets the executive approve mitigations via POST /api/v2/risks/{id}/mitigation/approve (or equivalent). API key per executive, with their permission set.

Pattern E: CI/CD integration.

A CI pipeline closes risks when their corresponding code fix ships: PATCH /api/v2/risks/{id} to update status. API key bound to a "ci-system" user with limited permissions.

8. Test thoroughly before going live

Integration code is the place where small misunderstandings become production incidents:

  • Test against a non-production SimpleRisk instance first.
  • Test with realistic data shapes (custom fields, encryption, etc.).
  • Test error paths (what happens when SimpleRisk is unreachable, when the key is revoked, when the response shape changes).
  • Test rate limits under load.
  • Test the integration's own retry and error-handling logic.

Production integrations that fail silently are worse than no integration; failures should alert someone.

Common pitfalls

A handful of patterns recur with API integrations.

  • Using /api/v1/ or unversioned /api/ paths. Always /api/v2/.

  • Hardcoding the API key in source. Use environment variables or a secrets manager.

  • Polling at high frequency. Pace yourself; cache; use modified-since queries where supported.

  • Treating the API as a complete platform SDK. Some operations are UI-only. Test what you actually need; if it's missing, file a request.

  • Forgetting that the API key inherits the user's permissions. A key for a user with no submit_risks permission can't submit risks. Configure the user appropriately.

  • Forgetting that the API key inherits team membership. A key for a user on the Engineering team only sees Engineering-team risks. If you need broader visibility, assign the user to more teams.

  • Not handling team-filter empty results. A query that returns nothing might be "no risks match the filter" or "the user doesn't have access to any risks matching the filter." The integration should handle both.

  • Logging full API request/response bodies in production. Risk descriptions can contain sensitive content; avoid logging more than necessary.

  • Not version-pinning your integration to a SimpleRisk release. Major SimpleRisk upgrades may change the API surface (typically additive, but occasionally breaking). Track the SimpleRisk release version your integration was tested against.

  • Building integrations against documentation rather than the live API. The Swagger UI is generated from annotations in the running code; it's authoritative. If a behavior in the live API contradicts the docs, file a bug — but trust the live API for integration development.

  • Treating the lack of pagination as the API's bug. It's a current state. Filter at the source; cache locally; design integrations that don't depend on pagination.

  • Not setting Accept: application/json header. The API generally returns JSON regardless, but explicit headers prevent ambiguous cases.

  • Sending bare GET requests with query parameters in the URL containing the API key. Use the X-API-KEY header instead; URLs land in proxy logs.

Related

Reference

  • Permission required: Per-endpoint; the API key inherits the user's full permission set. The user must have the relevant permissions for whichever operations the integration performs.
  • API base path: /api/v2/ — always use explicitly. The unversioned /api/ and /api/v1/ paths are for backward compatibility only.
  • Authentication header: X-API-KEY: <64-char-key> — recommended. Query parameter (?key= ) and POST body (key= ) also work but expose the key more readily.
  • Implementing files: simplerisk/api/v2/index.php (the v2 router); simplerisk/api/v2/documentation/ (per-domain OpenAPI annotations); simplerisk/extras/api/index.php (api_authenticate(), the per-request auth flow).
  • Database tables: api_keys (per-user key hashes); standard SimpleRisk entity tables (risks, frameworks, controls, etc.) for the data the API operates on.
  • config_settings keys: api (master API toggle); api_salt (key hashing salt); api_v1 (legacy v1 toggle, default off on fresh installs).
  • Documentation: /api/v2/documentation.php — Swagger UI generated from in-code OpenAPI annotations. Always current with the running install's API surface.
  • Pagination: None native at present; list endpoints return full result sets.
  • Rate limiting: None native at present; integrations should self-throttle. Reverse-proxy-based rate limiting is the path for enforcement.
  • External dependencies: None beyond the API Extra and the api master toggle.