Skip to content

One-time codes

A case created with multiFactorType asks each participant for a one-time code before it shows the document or accepts a signature. The code proves the participant has the mailbox or phone you named; the signing link alone is not enough.

{
"title": "Loan agreement 2026/0917",
"validUntil": "2026-10-15T23:59:59Z",
"multiFactorType": "EMAIL",
"participants": [{"firstName": "Jana", "lastName": "Nováková", "email": "jana.novakova@example.com"}]
}

TrustInk’s signing page runs this flow for you. You only need the details below if you build your own signing page on the participant routes.

  1. The signing page loads GET /participant/{participantId}/caseDefinition. Without a session it answers otpRequired: true and leaves out originalDocument and signedDocument.

  2. POST /participant/{participantId}/otp (participant token) sends a six-digit code by the case’s multiFactorType and answers {sentTo, channel, expiresAt}:

    {"sentTo": "j***@example.com", "channel": "EMAIL", "expiresAt": "2026-09-24T10:10:00.000Z"}

    A code is valid ten minutes; a new one replaces the previous one.

  3. POST /participant/{participantId}/otp/verify with {"code": "004711"} answers {otpSession, expiresAt}.

  4. The page sends Trustink-Otp-Session: <otpSession> with every participant request for the next 30 minutes: the case definition then has its document links, and the signature and the signed document are accepted. After that, or on another device, the participant verifies a new code.

Endpoint Status code When
POST .../otp 409 OTP_NOT_REQUIRED the case has no multiFactorType
409 OTP_NO_DESTINATION the participant has no email address or phone number for the channel
429 OTP_RATE_LIMITED five codes were sent in the last hour; retryAfterSeconds says when the next one can go
501 OTP_CHANNEL_UNAVAILABLE SMS, until the SMS channel is available
POST .../otp/verify 400 OTP_INVALID wrong code; attemptsLeft says how many tries remain
423 OTP_LOCKED the fifth wrong code, and any try after it, until a new code is requested
409 OTP_NOT_REQUESTED no code was sent, or the last one was used
409 OTP_EXPIRED the code is older than ten minutes, or a newer one replaced it
POST .../signature, GET .../signedDocument 401 OTP_REQUIRED the case has multiFactorType and the request has no valid Trustink-Otp-Session

A code that is not six digits answers 400 with validationErrors and does not count as a try. Both code endpoints answer 410 CASE_NOT_ACTIVE or LINK_EXPIRED like the other participant endpoints.

TrustInk never stores the code itself, only a salted hash, compared in constant time; a right code is removed once used. The audit trail records that a code was sent (to the masked address), each wrong try and the successful verification, never the code. The evidence summary shows when each participant verified.