Kulpa Docs Help

Partner API Reference

Machine-readable contract for the kulpa partner API. Operations, request/response schemas, security, and webhooks are rendered live from the OpenAPI specification at specs/third-party/partner-api/2026-04-01/.

Endpoints

List cases

/cases

Returns cases accessible to the partner. By default, returns cases across the calling client's organisation and all its sub-organisations.

Pass source and sourceId together to narrow to a single sub-organisation (e.g. one of the partner's neighbourhoods). Pass referenceNumber to filter to cases initiated against a specific partner reference (e.g. an appeal id) — useful for correlation lookups.

Results are paginated. Follow the rel="next" URL in the Link response header to retrieve the next page; the absence of rel="next" indicates the last page.

Request parameters

Responses

[ { "id": "18ad0215-778d-352d-8f14-959901273e8d", "number": "example", "personAffectedName": "example", "referenceNumber": "example", "numberOfEvidenceContributions": 96, "creationDateTime": "1971-04-26T12:26:06Z", "updateDateTime": "1971-04-26T12:26:06Z" } ]

Get case details

/cases/{caseId}

Returns full details for a case, including person affected and incident information.

Request parameters

Responses

{ "id": "18ad0215-778d-352d-8f14-959901273e8d", "number": "JS/20200110/015", "personAffected": { "fullName": "example", "dateOfBirth": "1970-01-14", "phoneNumber": "+44123456789", "profilePhotoURL": "example" }, "owner": { "id": "example", "fullName": "example", "emailAddress": "email@example.com", "profilePictureURL": "example", "isCreator": true }, "incident": { "location": { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 87 ] }, "properties": { "name": "example" } }, "descriptions": [ { "id": "example", "text": "example", "creationDateTime": "1971-04-26T12:26:06Z", "author": { "id": "example", "fullName": "example", "emailAddress": "email@example.com", "profilePictureURL": "example", "isCreator": true } } ], "dateTime": "2020-01-29T15:54:10", "duration": 58, "witnesses": [ { "id": "example", "text": "example", "creationDateTime": "1971-04-26T12:26:06Z", "author": { "id": "example", "fullName": "example", "emailAddress": "email@example.com", "profilePictureURL": "example", "isCreator": true } } ], "perpetrators": [ { "id": "example", "text": "example", "creationDateTime": "1971-04-26T12:26:06Z", "author": { "id": "example", "fullName": "example", "emailAddress": "email@example.com", "profilePictureURL": "example", "isCreator": true } } ] }, "referenceNumber": "example", "creationDateTime": "1971-04-26T12:26:06Z", "updateDateTime": "1971-04-26T12:26:06Z" }

List evidence contributions

/cases/{caseId}/evidence-contributions

Returns evidence contributions submitted for the case, including preview/thumbnail URLs. To obtain download URLs for the files, fetch the individual evidence contribution via GET /cases/{caseId}/evidence-contributions/{evidenceContributionId}, or request a case bundle via POST /case-bundles for a packaged download with the signed MG11.

Results are paginated. Follow the rel="next" URL in the Link response header to retrieve the next page; the absence of rel="next" indicates the last page.

Request parameters

Responses

[ { "id": "18ad0215-778d-352d-8f14-959901273e8d", "evidenceReference": "example", "description": "example", "creationDateTime": "1971-04-26T12:26:06Z", "type": "Image", "status": "WaitingForUpload", "previewImages": [ [ { "url": "https://kulpa.example/preview/2560.jpg", "width": 2560 }, { "url": "https://kulpa.example/preview/1200.jpg", "width": 1200 }, { "url": "https://kulpa.example/preview/600.jpg", "width": 600 }, { "url": "https://kulpa.example/preview/300.jpg", "width": 300 }, { "url": "https://kulpa.example/preview/122.jpg", "width": 122 } ] ], "author": { "id": "example", "fullName": "example", "emailAddress": "email@example.com", "profilePictureURL": "example", "isCreator": true } } ]

Get evidence contribution details

/cases/{caseId}/evidence-contributions/{evidenceContributionId}

Returns details for a single evidence contribution, including download URLs for the file.

Request parameters

Responses

{ "id": "18ad0215-778d-352d-8f14-959901273e8d", "evidenceReference": "example", "description": "example", "creationDateTime": "1971-04-26T12:26:06Z", "type": "Image", "status": "WaitingForUpload", "previewImages": [ [ { "url": "https://kulpa.example/preview/2560.jpg", "width": 2560 }, { "url": "https://kulpa.example/preview/1200.jpg", "width": 1200 }, { "url": "https://kulpa.example/preview/600.jpg", "width": 600 }, { "url": "https://kulpa.example/preview/300.jpg", "width": 300 }, { "url": "https://kulpa.example/preview/122.jpg", "width": 122 } ] ], "author": { "id": "example", "fullName": "example", "emailAddress": "email@example.com", "profilePictureURL": "example", "isCreator": true } }

Request a case bundle

/case-bundles

Requests generation of a case bundle for the specified case. The bundle includes a signed, dated MG11 exhibit form together with all submitted evidence files.

Poll GET /case-bundles/{caseBundleId} to check status. Once the status is Completed, download the bundle from the downloadUrl field on the returned resource.

Request parameters

{ "caseId": "18ad0215-778d-352d-8f14-959901273e8d", "format": "CriminalCase" }

Responses

{ "id": "18ad0215-778d-352d-8f14-959901273e8d", "requestNumber": "example", "caseNumber": "example", "status": "Pending", "expirationDateTime": "1971-04-26T12:26:06Z", "downloadUrl": "example" }

Get case bundle

/case-bundles/{caseBundleId}

Returns the current state of a case bundle request. Poll this endpoint until status is Completed or Error.

Once status is Completed, the downloadUrl field will contain a URL pointing at the bundle file (signed MG11 + evidence).

Request parameters

Responses

{ "id": "18ad0215-778d-352d-8f14-959901273e8d", "requestNumber": "example", "caseNumber": "example", "status": "Pending", "expirationDateTime": "1971-04-26T12:26:06Z", "downloadUrl": "example" }

Negotiate a SignalR connection for case bundle updates

/case-bundles/hub/negotiate

Establishes a real-time connection to the case-bundles SignalR hub, where partners receive push notifications about bundle generation progress.

After a successful POST, connect using a SignalR client (e.g. @microsoft/signalr) and subscribe to the Update method. The hub will invoke Update with a CaseBundleUpdate payload as generation progresses — initial 0.0, incremental updates between 0.0 and 0.8 while documents are produced, 0.9 once the archive is compressed, and 1.0 when complete with downloadUrl populated. On failure, an update with status: Error and errorMessage populated is sent.

By default, the connection receives updates for every case bundle accessible to the calling client's organisation (and its descendants). Pass source and sourceId to scope the connection to a single sub-organisation.

For SignalR client setup, refer to the Microsoft SignalR client documentation.

Request parameters

Responses

Webhooks

Case submitted notification

caseSubmitted

Kulpa calls this endpoint on the partner's registered webhook URL when a case is submitted by a member of the public. The partner's endpoint must return 204 No Content to acknowledge receipt.

Authenticity: kulpa signs every webhook request. Two headers are sent:

  • X-Kulpa-Timestamp — Unix epoch seconds at the time of dispatch.

  • X-Kulpa-Signaturesha256=<hex>, where <hex> is the lowercase hex-encoded HMAC-SHA256 of the string <timestamp>.<raw request body> using the shared signing secret as the key.

Partners MUST verify the signature and reject any request whose timestamp differs by more than 5 minutes from the current time (replay protection). Pattern is identical to GitHub / Stripe / Slack webhooks; standard libraries exist in every major language.

Delivery semantics: at-least-once. Kulpa will retry on transport errors and non-2xx responses; the specific retry policy (intervals, max attempts, backoff) is subject to change. Partners MUST treat the endpoint as idempotent and de-duplicate by caseId, since the same event MAY be delivered more than once.

Request parameters

{ "caseId": "18ad0215-778d-352d-8f14-959901273e8d", "caseNumber": "example", "referenceNumber": "example", "status": "Submitted", "submittedAt": "1971-04-26T12:26:06Z", "evidenceContributionsUrl": "example" }

Responses

16 July 2026