Generate signature
Issues the signature that authorizes opening one Invox Genesis consultation for one physician. This call is made server to server: never call it from the browser, since it requires your API Key credentials.
Request description
Endpoint: /api/v1/generate-soft-integration-signature
Method: POST
Header
{
"Content-Type": "application/json",
"Authorization": "Bearer <accessToken>"
}
Note: the <accessToken> is obtained as described in Prerequisites.
The API Key behind it must hold the GENESIS-SOFT-INTEGRATION permission.
To set the API version on a specific request, you can add a specific header named X-Invox-Medical-Api-Version with the value of the version you are targeting:
X-Invox-Medical-Api-Version: 2026-08-01
SOFT Integration was introduced in 2026-08-01, so that is the only version this endpoint accepts. Omitting the
header resolves to the latest version. Sending an earlier version such as 2026-03-01 is rejected with 400 and
invalidApiVersionForEndpoint, because SOFT Integration did not exist back then.
Payload
{
"organizationId": "1111-1111-1111-1111",
"email": "doctor@cliente.com",
"requestId": "2222-2222-2222-2222",
"consultationMetadata": {
"patientId": "PAT-123-56",
"hcId": "1234567"
}
}
Payload structure
type GenerateSoftIntegrationSignaturePayload = {
organizationId: string;
email: string;
requestId: string;
consultationMetadata?: Record<string, unknown>;
};
consultationMetadata is free-form. The fields shown above are only an example. You can send as many fields
as you need to describe the consultation — patient name, appointment identifier, department, episode number, or
anything else meaningful in your EHR. Invox Medical stores them as sent and returns them untouched in the
notification and in the result, so you can use them to reconcile the consultation on your side.Field rules
| Field | Required | Rules |
|---|---|---|
organizationId | Yes | Your organization in the Invox Medical platform. The physician must belong to it. |
email | Yes | Email of the physician. Normalized to lower case before resolving the user, so it is case-insensitive. |
requestId | Yes | Identifier generated by you. Single-use: it can never be reused, not even after cancelling. |
consultationMetadata | No | Consultation context displayed to the physician inside Invox Genesis. Free-form; never used for authorization. |
requestId is single-use. Once a requestId has been accepted it stays reserved, so a later request carrying
the same value is rejected with 400 and duplicatedRequestId. This holds even if the consultation was finished
or cancelled: cancelling releases the physician, never the
requestId. Generate a fresh value on every retry, and keep your own mapping from requestId to the encounter
in your EHR.requestId is the key you will use later to retrieve the result, and the value echoed back in the notification.
Use a value that is unique in your system. If you derive it from an encounter identifier, add a suffix such as an
attempt counter or a timestamp so that reopening the same encounter still produces a new value.Validation performed
Before issuing the signature, the platform verifies fail-closed that:
- The access token is valid and the API Key holds the
GENESIS-SOFT-INTEGRATIONpermission. - The payload is well formed and the
requestIdhas never been used before. - The physician identified by
emailexists in the identity provider. - The physician is enabled.
- The physician belongs to the declared
organizationId.
If any of these checks fails, no signature is issued.
Signature lifetime
The issued signature is valid for a maximum of 3 hours. After that it can no longer be used to open Invox Genesis or to open the notification WebSocket, and every attempt is rejected.
The latest session wins
A physician can only have one active SOFT Integration session at a time. Requesting a new signature for a physician who already has one does not fail: the previous session is cancelled automatically and the new one takes over.
Only the physician opens these sessions, so a second request means they moved on and the earlier consultation was abandoned.
A session stops being active when:
- the physician finishes the consultation,
- you release it with Cancel consultation,
- a newer signature is issued for the same physician, or
- the signature reaches its 3-hour lifetime.
requestId. Reusing the
one you just displaced is rejected with 400 and duplicatedRequestId.Responses
Correct response
Successful request
Describe the characteristics of a satisfactory response
200
Response structure:
{
"signature": "<signature>"
}
Wrong responses
Bad request
Describe the characteristics of a bad request
400
Response body
{
"message": "Field \"requestId\" is required.",
"errorType": "missingOrInvalidParameter"
}
errorTypetype GenerateSignatureBadRequestErrorType =
| "missingOrInvalidParameter" // organizationId, email or requestId missing or malformed
| "duplicatedRequestId"; // the requestId was already used and cannot be reused
Unauthorized request
Describe the characteristics of an unauthorized request
401
Response body
{
// empty body
}
Description: this error occurs when the endpoint authorizer fails to validate the token sent in the request header.
Forbidden request
Describe the characteristics of a forbidden request
403
Response body
{
"message": "User does not belong to the specified organization.",
"errorType": "userNotEligible"
}
errorTypetype GenerateSignatureForbiddenErrorType =
| "invalidPermission" // the API Key does not hold GENESIS-SOFT-INTEGRATION
| "userNotEligible"; // user unknown, disabled, or in another organization
userNotEligible is deliberately returned for the three cases (unknown user, disabled user, wrong
organization) without distinguishing between them, to avoid disclosing which emails exist in the platform.Conflict
Describe the characteristics of two signature requests racing for the same physician
409
Response body
{
"message": "The physician already has an active SOFT Integration session.",
"errorType": "activeSessionExists"
}
Description: rare. An existing session no longer causes this, because it is cancelled automatically. It only happens when two requests for the same physician arrive at the same instant and one loses the race. Retry.
Example
const response = await fetch(
"https://api-suite.invoxmedical.com/api/v1/generate-soft-integration-signature",
{
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${accessToken}`,
},
body: JSON.stringify({
organizationId,
email: physicianEmail,
requestId,
consultationMetadata: { patientId, hcId },
}),
},
);
if (!response.ok) {
// handle 400 / 401 / 403 / 409 — do not open Invox Genesis
}
const { signature } = await response.json();
Next step
Use the signature to open the Invox Genesis consultation.