Core API
Base URL: https://api.bcmlogic.com/v1/core
Style: RESTful, JSON. Resource-oriented. Plural nouns. Standard HTTP verbs and status codes.
Purpose: Source of truth for all business data in BCMLogic Next.
For guidance on when to call Core API versus Intelligence Service, see The Two-API Model.
Modules
Core API is organised into bounded contexts. Each context owns its resources and its part of the data model.
| Module | Path prefix | Primary resources |
|---|---|---|
| Continuity | /v1/core/continuity | processes, bia, dr-plans, exercises |
| ERM | /v1/core/erm | risks, kri, controls, assessments |
| Vendor | /v1/core/vendors | vendors, contracts, assessments, incidents |
| Documents | /v1/core/documents | documents, versions, attachments |
| Identity | /v1/core/identity | users, roles, groups, tenants |
| Audit | /v1/core/audit | events — read-only |
| Reports | /v1/core/reports | reports, templates — the PDF/DOCX artifacts; generation is via Intelligence Service |
Note the split on reports: the report file (PDF, DOCX) lives in Core API because it is an audit-bound artifact; the generation logic lives in Intelligence Service because it uses an LLM. See Intelligence Service → Reports.
Resource Conventions
- Resources use plural names:
/risks, not/risk. - Identifiers are opaque ULIDs with type prefixes:
rsk_01HQ8K3.... Do not parse or construct them. - Timestamps are RFC 3339 in UTC:
2026-05-15T10:30:00Z. - Money is represented as
{ "amount": "1234.56", "currency": "EUR" }— string amount to avoid floating-point errors. - Enumerations use
snake_casestring values, never integers. - Boolean fields are prefixed
is_,has_, orrequires_.
Response Envelopes
Single resource
{
"id": "rsk_01HQ8K3ABCDEF",
"type": "risk",
"attributes": { },
"relationships": { },
"meta": {
"created_at": "2026-05-15T10:30:00Z",
"updated_at": "2026-05-15T10:30:00Z",
"version": 3
}
}
List
{
"data": [
{ "id": "rsk_01HQ8K3ABCDEF", "type": "risk", "attributes": { } }
],
"pagination": {
"next_cursor": "eyJpZCI6...",
"has_more": true,
"page_size": 50
}
}
See Cross-cutting Concerns → Pagination for cursor usage.
Mutations
Writes (POST, PUT, PATCH, DELETE) require:
- A valid bearer token — see Authentication.
- An
Idempotency-Keyheader — UUID v4 recommended. Repeating a request with the same key within 24 hours returns the original response without re-executing the operation. See ADR-007. - A valid request body — the server validates against JSON Schema. Validation failures return
422 Unprocessable Entitywith field-level errors.
Example — create a risk
curl -X POST https://api.bcmlogic.com/v1/core/erm/risks \
-H "Authorization: Bearer eyJhbGc..." \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \
-d '{
"attributes": {
"name": "Concentration risk in cloud provider",
"severity": "high",
"status": "open"
}
}'
const response = await fetch('https://api.bcmlogic.com/v1/core/erm/risks', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json',
'Idempotency-Key': crypto.randomUUID(),
},
body: JSON.stringify({
attributes: {
name: 'Concentration risk in cloud provider',
severity: 'high',
status: 'open',
},
}),
});
Optimistic concurrency
To update safely under concurrency, include If-Match: <version> on PATCH and PUT. The server returns 409 Conflict if the version no longer matches.
curl -X PATCH https://api.bcmlogic.com/v1/core/erm/risks/rsk_01HQ8K3ABCDEF \
-H "If-Match: 3" \
-H "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440001" \
...
Versioning
The API version is in the URL path: /v1/core/.... Breaking changes ship as a new major version: /v2/.... See API Lifecycle for the full versioning and deprecation policy.