Skip to main content

Case Management

This document details the operation and usage of endpoints for managing cases in the Certificall application.


Endpoint: GET /cases​

Description​

The case search endpoint allows authenticated users to query and retrieve cases registered in the Certificall system, applying various filters to refine results according to specific needs.

Authentication​

Access to this endpoint requires valid authentication. Include a JWT (JSON Web Token) in the header of your HTTP request as follows:

Authorization: Bearer <Your_JWT_Token>

HTTP Request​

Method: GET URL: /cases

Query Parameters​

  • reportToken (String, optional): Report token associated with the cases being searched.
  • companyId (Number, optional): Identifier of the company associated with the cases.
  • frameId (Number, optional): Identifier of the frame used for the cases.
  • hours (Number, optional): Number of hours in the past during which cases were created, maximum 240 hours, default 12 hours.
  • withReportToken (Boolean, optional): Indicates whether the report token should be included in the results.
  • closed (Boolean, optional): Filters by status. Accepted values: true (closed cases only) or false (open cases only). If the parameter is absent or does not match a valid boolean, the endpoint returns both open AND closed cases.
  • format (Enum, required): Specifies the response format (ZIP or metadata), using RESPONSE_FORMAT.
  • caseId (Number, optional): Identifier of the case being searched.

Note: specify hours if you want to receive cases older than the last 12 hours

Example:

curl -X 'GET' \
'https://admin.certificall.app/certificall/api/cases?format=metadata&hours=48' \
-H 'accept: application/json' \
-H 'Authorization: Bearer xxxx'

Responses​

200 OK: Returns a list of cases matching the specified criteria.

Response example for a request with format=metadata:

[
{
"cfRef": "REF123",
"closingDate": "2023-01-01T00:00:00Z",
"createdAt": "2022-12-01T00:00:00Z",
"closed": true,
"frame": "Frame A",
"companyName": "Company XYZ",
"reportId": "TOKEN123",
"caseUrl": "https://certificall.example.com/download/SHARETOKEN123",
"metadata": { "site": "Paris", "zone": "A1" }
}
]

metadata (object): the case's free-form metadata, exactly as supplied on creation — through the metadata field of POST /cases/create, a Certilink or the mobile SDK. The key is absent from cases that carry none. It does not look a case up (use reportToken), but it filters consumption.

400 Bad Request: The request is invalid, usually due to missing or incorrect parameters.

500 Internal Server Error: Internal server error preventing request processing.


Case Creation​

Endpoint: POST /cases/create​

Description​

This API endpoint allows authenticated users to create a new case in the Certificall system. The case can be associated with a specific user or a certilink (Magic Link) for use without authentication.

Authentication​

Access to this endpoint requires valid authentication. Include a JWT (JSON Web Token) in the header of your HTTP request as follows:

Authorization: Bearer <Your_JWT_Token>

HTTP Request​

Method: POST URL: /cases/create

Request Body (Payload)​

Required parameter:

  • frameId (Number): Identifier of the frame to use for the case.

Optional parameters:

  • title (String): Case title.
  • userId (String): Keycloak identifier of the user to associate with the case (exclusive with magicLinkToken).
  • childCompanyId (Number): ID of the target child company (used only with certilink).
  • magicLinkToken (String): Token of an existing certilink to use (exclusive with userId).
  • certilinkOptions (Object): Options to automatically create a new certilink.
    • reportToken (String, required): Unique report token for the certilink.
    • maxUses (Number, optional): Maximum number of authorized uses.
    • expirationDate (String, optional): Expiration date (format: yyyy-mm-ddThh:mm:ss.sss+hhmm).
  • reportToken (String): Report token to associate or create a report.
  • caseContext (Object): Case context (visible data).
    • visibleData (Object): Data visible in the case.
      • beneficiary (Object): Beneficiary information.
        • lastName (String): Last name.
        • firstName (String): First name.
        • address (String): Address.
        • city (String): City.
        • postCode (String): Postal code.
        • email (String): Email address.
      • issuer (String): Case issuer.
      • photoRef (String): Photo reference.
      • reportRef (String): Report reference.
      • instructions (String): Specific instructions for the user.
      • user (String): User name to display in the PDF.
  • metadata (Object, optional): the case's free-form metadata, string key-value pairs (20 keys max, 40 characters per key, 500 per value). Returned with the case in GET /cases and in the case webhook.

Request Examples​

Example 1: Create a case for a specific user

{
"frameId": 10,
"title": "Technical inspection",
"userId": "user-keycloak-id-123",
"reportToken": "REPORT-2024-001",
"caseContext": {
"visibleData": {
"beneficiary": {
"lastName": "Dupont",
"firstName": "Jean",
"email": "jean.dupont@example.com"
},
"issuer": "ACME Company",
"instructions": "Check the general condition of the equipment"
}
},
"metadata": {
"source": "api",
"version": "1.0"
}
}

Example 2: Create a case with an automatic certilink

{
"frameId": 10,
"title": "External inspection",
"certilinkOptions": {
"reportToken": "REPORT-2024-002",
"maxUses": 5,
"expirationDate": "2025-12-31T23:59:59.000+0100"
},
"caseContext": {
"visibleData": {
"beneficiary": {
"lastName": "Martin",
"firstName": "Sophie",
"address": "123 Rue de la Paix",
"city": "Paris",
"postCode": "75001",
"email": "sophie.martin@example.com"
},
"instructions": "Please note the apartment number"
}
}
}

Example 3: Create a case with an existing certilink

{
"frameId": 10,
"magicLinkToken": "09ca0baf-ce70-47a0-b84e-0b4acb0ecec3",
"title": "Scheduled inspection",
"caseContext": {
"visibleData": {
"issuer": "ABC Company",
"instructions": "Follow the standard protocol"
}
}
}

Responses​

Successful response:

  • Status: 201 Created
  • Description: The case has been created successfully.
  • Response example:
    {
    "id": 12345,
    "cfRef": "CAS-12345_CMP-1",
    "frameId": 10,
    "title": "Technical inspection",
    "createdAt": "2024-01-15T10:30:00Z",
    "closed": false,
    "magicLinkUrl": "https://app.certificall.app/?mt=09ca0baf-ce70-47a0-b84e-0b4acb0ecec3"
    }

Error response:

  • Status: 400 Bad Request

  • Description: The request is invalid (missing or incorrect parameters).

    {
    "statusCode": 400,
    "message": "frameId is required",
    "error": "Bad Request"
    }
  • Status: 403 Forbidden

  • Description: You do not have the necessary permissions to create a case.

  • Status: 404 Not Found

  • Description: The specified frame does not exist or does not belong to your company.

Required Permissions​

  • The user must have the p_api scope and the create permission on the case resource.
  • The frame must belong to your company or be accessible.

Use Cases​

Use this endpoint to:

  • Create a case intended for a specific user on your team
  • Generate a case accessible via a certilink (Magic Link) for external users
  • Initialize a case with pre-filled information (beneficiary, instructions, etc.)
  • Create a case and a certilink in a single operation

Important Notes​

  • userId and magicLinkToken are mutually exclusive: you must use one or the other, but not both.
  • If you use certilinkOptions, a new certilink will be automatically created for this case.
  • The reportToken field in certilinkOptions is required if you use this option.
  • Metadata must be key-value pairs with string-type values.
Several cases to create?

Do not call this endpoint in a loop: you would quickly hit the rate limit and get a 429. Use bulk create below, which counts as a single request.


Bulk Create​

Endpoint: POST /cases/bulk-create​

Creates several cases in a single request. Designed for integrations that need to open a set of cases at once — for instance one case per intervention on the same site.

Only one call is counted, whatever the size of the array. This endpoint has its own rate limit of 10 requests per minute — up to 500 cases created per minute, against 60 when looping on the single creation.

Request​

POST /certificall/api/cases/bulk-create
Authorization: Bearer <Your_JWT_Token>
Content-Type: application/json

The body is an array of objects, each in the same format as the single creation (POST /cases/create):

[
{ "frameId": 10, "title": "Intervention batch A", "userMail": "technician@example.com" },
{ "frameId": 10, "title": "Intervention batch B", "userMail": "technician@example.com" },
{ "frameId": 12, "title": "Final check" }
]

Limit: 50 cases per request. Beyond that the API responds 400 — split your processing into several calls.

No deduplication

Two identical lines in the array create two distinct cases. Before resending an interrupted request (network failure, timeout), check with GET /cases which cases were already created.

Required Permissions​

Two permissions are required:

PermissionPurpose
p_api:case:createCreating a case
p_api:case:bulk_createAccess to bulk create

If either is missing, the API responds 403 and no case is created.

Response​

Status code: 200 OK, even if some cases fail. Each case is created independently: one failure does not cancel the others, and cases already created are kept.

{
"state": "Cases bulk create ended",
"date": "2026-09-15T09:12:34.567Z",
"company": 42,
"success": [
{ "index": 0, "caseId": 12345 },
{ "index": 2, "caseId": 12346 }
],
"error": [
{ "index": 1, "error": "Error while creating case" }
]
}
FieldDescription
successCases actually created
errorLines not created, each with its reason
indexPosition in the array you sent
caseIdIdentifier assigned to the created case. Absent from error entries, since the case does not exist
Always check the error array

A 200 does not mean every case was created. Walk through error to find the lines to fix and resend.

Processing order is not guaranteed: rely on index to match each caseId with the corresponding line of your request. Only the identifier is returned; to get the details of a created case, use GET /cases with the caseId parameter.

The failure reason is the one returned by the business service (frame not found, unknown user…) or, by default, Error while creating case. These labels are not guaranteed to be stable: route your errors on a line being present in error[] rather than on the exact wording.

Request errors​

In these cases, no case is created:

StatusContext
400Empty array, more than 50 cases, or invalid element. Errors for every element are returned, prefixed with their position: [1] frameId must be a number conforming to the specified constraints
403One of the two required permissions is missing
429Rate limit of 10 requests per minute exceeded on this endpoint

Closing a Case​

Endpoint: GET /cases/close/:caseId​

Description​

This API endpoint allows users to close an ongoing case. Once closed, the case is considered finalized and can no longer be modified. This action is essential to indicate the end of the data collection process.

Request​

  • URL: /cases/close/:caseId

  • HTTP Method: GET

  • Path parameters:

    • caseId: number - The unique identifier of the case to close.
  • Required headers:

    Authorization: Bearer <Your_JWT_Token>

Responses​

Successful response:

  • Status: 200 OK
  • Description: The case has been closed successfully.
  • Response example:
    {
    "status": "Success",
    "message": "Case closed successfully"
    }

Error response:

  • Status: 400 Bad Request

  • Description: The request is invalid or the case does not exist.

    {
    "statusCode": 400,
    "message": "Invalid case ID",
    "error": "Bad Request"
    }
  • Status: 403 Forbidden

  • Description: You do not have the necessary permissions or the case does not belong to your company.

Required Permissions​

  • The case must belong to your company to be closed.

Use Cases​

Use this endpoint when you have finished collecting all necessary data for a case and want to finalize it. Once closed, the case can no longer receive new items.


Updating a Case​

Endpoint: PATCH /cases/update​

Description​

This API endpoint allows users to update information of an existing case. You can modify the title, associated frame, user, report token, or case context.

Request​

  • URL: /cases/update

  • HTTP Method: PATCH

  • Required headers:

    Authorization: Bearer <Your_JWT_Token>
    Content-Type: application/json

Request Body (Payload)​

  • caseId (Number, required): Identifier of the case to update.
  • title (String, optional): New case title (maximum 255 characters).
  • frameId (Number, optional): Identifier of the new frame to associate.
  • userId (String, optional): Keycloak identifier of the user to associate.
  • reportToken (String, optional): Report token to associate with the case.
  • caseContext (Object, optional): Case context (visible data).
    • visibleData (Object, optional): Data visible in the case.
      • beneficiary (Object, optional): Beneficiary information.
        • lastName (String): Last name.
        • firstName (String): First name.
        • address (String): Address.
        • city (String): City.
        • postCode (String): Postal code.
        • email (String): Email address.
      • issuer (String): Case issuer.
      • photoRef (String): Photo reference.
      • reportRef (String): Report reference.
      • instructions (String): Specific instructions.
      • user (String): User name to display.
  • metadata (Object, optional): the case's free-form metadata, string key-value pairs (20 keys max, 40 characters per key, 500 per value). Replaces the case's current metadata; null clears it. Returned in GET /cases and in the case webhook.

Request body example:

{
"caseId": 12345,
"title": "Updated inspection",
"reportToken": "REPORT-2024-001",
"caseContext": {
"visibleData": {
"beneficiary": {
"lastName": "Dupont",
"firstName": "Jean",
"email": "jean.dupont@example.com"
},
"issuer": "ACME Company",
"instructions": "Check the general condition of the equipment"
}
},
"metadata": {
"source": "api",
"version": "2.0"
}
}

Responses​

Successful response:

  • Status Code: 200 OK
  • Description: The case has been updated successfully.

Successful response example:

{
"success": true
}

Error response:

  • Status Code: 400 Bad Request

  • Description: The request is invalid (missing or incorrect parameters).

  • Status Code: 403 Forbidden

  • Description: You do not have the necessary permissions or the case does not belong to your company.

  • Status Code: 404 Not Found

  • Description: The specified case does not exist.

Required Permissions​

  • The case must belong to your company to be updated.

Use Cases​

Use this endpoint to:

  • Correct a case title
  • Modify beneficiary information
  • Associate a new report token
  • Add or modify metadata
  • Change the frame associated with the case
Several cases to update?

Do not call this endpoint in a loop: you would quickly hit the rate limit and get a 429. Use bulk update below, which counts as a single request.


Bulk Update​

Endpoint: PATCH /cases/bulk-update​

Updates several cases in a single request. Designed for integrations that need to propagate the same information across a set of related cases — for instance reflecting a date change on every case attached to the same deal.

Only one call is counted, whatever the size of the array. This endpoint has its own rate limit of 10 requests per minute — up to 1000 cases updated per minute, against 60 when looping on the single update.

Request​

PATCH /certificall/api/cases/bulk-update
Authorization: Bearer <Your_JWT_Token>
Content-Type: application/json

The body is an array of objects, each in the same format as the single update:

[
{ "caseId": 12345, "scheduledAt": "2026-09-10T09:00:00+02:00" },
{ "caseId": 12346, "scheduledAt": "2026-09-10T09:00:00+02:00" },
{ "caseId": 12347, "scheduledAt": "2026-09-10T09:00:00+02:00" }
]

Limit: 100 cases per request. Beyond that the API responds 400 — split your processing into several calls.

Required Permissions​

Two permissions are required:

PermissionPurpose
p_api:case:updateUpdating a case
p_api:case:bulk_updateAccess to bulk update

If either is missing, the API responds 403 and no case is processed.

Response​

Status code: 200 OK, even if some cases fail. Each case is processed independently: one failure does not cancel the others.

{
"state": "Cases bulk update ended",
"date": "2026-08-13T09:12:34.567Z",
"company": 42,
"success": [
{ "index": 0, "caseId": 12345 },
{ "index": 2, "caseId": 12347 }
],
"error": [
{ "index": 1, "caseId": 12346, "error": "case.notBelongCompany" }
]
}
FieldDescription
successCases actually updated
errorFailed cases, each with its reason
indexPosition in the array you sent
caseIdIdentifier of the case concerned
Always check the error array

A 200 does not mean every case was updated. Walk through error to find which ones failed and why.

Processing order is not guaranteed: do not rely on the position within success or error, but on the index field, which points back to the original position in your request.

Common failure reasons​

MessageCause
case.notBelongCompanyThe case belongs to another company
case.scheduledAt.mustBeCurrentOrFutureMonthThe scheduled date is earlier than the current month
case.scheduledAt.invalidUnrecognised date format
Error while updating caseThe case does not exist, or the business service is temporarily unavailable
note

These labels come from the business service and are not guaranteed to be stable. To route your errors, rely on a case being present in error[] rather than on the exact wording.


Deleting a Case​

Endpoint: DELETE /cases/delete/:caseId​

Description​

This API endpoint allows users to permanently delete a case from the system. This action is irreversible and deletes all data associated with the case.

Request​

  • URL: /cases/delete/:caseId

  • HTTP Method: DELETE

  • Path parameters:

    • caseId: number - The unique identifier of the case to delete.
  • Required headers:

    Authorization: Bearer <Your_JWT_Token>

Responses​

Successful response:

  • Status: 200 OK
  • Description: The case has been deleted successfully.
  • Response example:
    {
    "status": "Success",
    "message": "Case deleted successfully"
    }

Error response:

  • Status: 400 Bad Request

  • Description: The request is invalid or the case does not exist.

  • Status: 403 Forbidden

  • Description: You do not have the necessary permissions or the case does not belong to your company.

Required Permissions​

  • The case must belong to your company to be deleted.

Warning​

WARNING: This operation is irreversible. Once the case is deleted, all associated data (items, photos, videos, metadata) will be permanently lost.

Use Cases​

Use this endpoint only when you need to permanently delete a case, for example:

  • Case created by mistake
  • Erroneous data that requires complete deletion
  • Compliance with data retention policies
Several cases to delete?

Do not call this endpoint in a loop: you would quickly hit the rate limit and get a 429. Use bulk delete below, which counts as a single request.


Bulk Delete​

Endpoint: POST /cases/bulk-delete​

Deletes several cases in a single request. Each case is deleted exactly as with the single deletion.

Only one call is counted, whatever the size of the array. This endpoint has its own rate limit of 10 requests per minute — up to 500 cases deleted per minute, against 60 when looping on the single deletion.

Request​

POST /certificall/api/cases/bulk-delete
Authorization: Bearer <Your_JWT_Token>
Content-Type: application/json

The body is an object holding the list of identifiers to delete:

{
"caseIds": [12345, 12346, 12347]
}
Why POST and not DELETE?

Many HTTP clients and proxies handle a request body on DELETE poorly. POST guarantees that the list of cases reaches the API intact.

Limit: 50 cases per request, with no duplicates. Beyond that the API responds 400 — split your processing into several calls.

Irreversible operation

As with the single deletion, all data associated with the deleted cases (items, photos, videos, metadata) is permanently lost. Double-check the list of identifiers before sending it.

Required Permissions​

Two permissions are required:

PermissionPurpose
p_api:case:deleteDeleting a case
p_api:case:bulk_deleteAccess to bulk delete

If either is missing, the API responds 403 and no case is deleted.

Response​

Status code: 200 OK, even if some cases fail. Each case is processed independently: one failure does not cancel the others.

{
"state": "Cases bulk delete ended",
"date": "2026-09-15T09:12:34.567Z",
"company": 42,
"success": [
{ "index": 0, "caseId": 12345 },
{ "index": 2, "caseId": 12347 }
],
"error": [
{ "index": 1, "caseId": 12346, "error": "Error while deleting case" }
]
}
FieldDescription
successCases actually deleted
errorFailed cases, each with its reason
indexPosition in the caseIds array you sent
caseIdIdentifier of the case concerned
Always check the error array

A 200 does not mean every case was deleted. Walk through error to find which ones failed and why.

Processing order is not guaranteed: do not rely on the position within success or error, but on the index field.

The failure reason is the one returned by the business service (case from another company, case not found…) or, by default, Error while deleting case. These labels are not guaranteed to be stable: route your errors on a case being present in error[] rather than on the exact wording.

Request errors​

In these cases, no case is deleted:

StatusContext
400Empty caseIds, more than 50 identifiers, non-numeric identifier, or the same identifier sent several times
403One of the two required permissions is missing
429Rate limit of 10 requests per minute exceeded on this endpoint

Security and Best Practices​

  • Ensure that all necessary data has been collected before closing a case.
  • Only the fields provided in the update request will be modified. Other fields will retain their current values.
  • Consider backing up important data before deletion.
  • Always verify that the caseId corresponds to the case you want to manipulate.
  • Metadata must be key-value pairs with string-type values.
  • Interactions with the Certificall API must always be performed via a secure connection (HTTPS).
  • Store and manage the authentication token securely.

By following these instructions, you will be able to securely manage your cases via the Certificall API.