Product Updates

New in Firma.dev: Proof Your Signer Entered the One-Time Code, on Every Certificate

Written by

Content

Firma.dev API v1.40.3 shipped on October 20, 2026, and it changes what the email one-time code leaves behind. When a signing request requires the code, the moment a signer enters it correctly is now logged in the audit trail, with a time and an IP address, and printed on the completion certificate.

New: Code Verification Now Goes on the Record

Firma.dev now records the code entry in two places. The audit trail gets a new otp_verified event, written when the signer enters the correct code. The completion certificate prints, for every signer, how they authenticated and when the code was verified. Both apply to signing requests completed from October 20 on. Certificates issued before that date stay exactly as they were.

What the Completion Certificate Shows

Every signer row on the certificate now carries an Authentication line, and it reads one of two ways:

  • Email Link, for a signer who signed without a one-time code

  • Email Link + One-Time Code (code verified <time>), for a signer who entered the code

The Identity row near the top sumamrizes the whole request. When every signer authenticated the same way, it shows that method. When they differ, it shows "Mixed (see signers)", which tells you to read the individual rows.

A simplified sketch of a signer row for someone who used the code:

Signer:          Alice Johnson (alice@example.com)
Viewed:          2026-10-21 09:14:11
Authentication:  Email Link + One-Time Code (code verified 2026-10-21 09:14:03)
Signer:          Alice Johnson (alice@example.com)
Viewed:          2026-10-21 09:14:11
Authentication:  Email Link + One-Time Code (code verified 2026-10-21 09:14:03)
Signer:          Alice Johnson (alice@example.com)
Viewed:          2026-10-21 09:14:11
Authentication:  Email Link + One-Time Code (code verified 2026-10-21 09:14:03)

The code time sits before the Viewed time in that sketch, and that's expected. The signer enters the code before the document loads, so the verification lands ahead of the first view (it would look odd on paper if you didn't know why).

What the Audit Trail Records

The new event is otp_verified, described as "Entered the one-time code sent by email". Like every signer event, it carries a timestamp, the signer's name and email as the actor, and the signer's IP address. Open any signing request in the dashboard and click the Audit Trail tab to see it in the timeline, alongside the views, field entries and signatures.

The code itself is never included. The event references the verified code record by its ID, so the trail ties the entry to a specific code without exposing the code to anyone reading it.

When the signer finishes, the document_finished event carries that same reference as long as the finishing session was linked to a verified code. And that links the code entry to the finished signature, in the same trail...

For more on what a complete trail should hold, see our e-signature audit trail explainer and the audit trail feature page.

Why It Matters When Someone Asks Later

Picture a contract signed six months ago... the signer now says they never saw it, or an auditor reveiwing your vendor paperwork wants to know how you checked who was signing. Both questions point at the same document.

With the one-time code switched on, the certificate answers them on one page. It shows the signer proved access to their email address by entering the code, and when they did it. The audit trail adds the IP address the code was entered from. You can forward the certificate as it is, and nobody has to dig through dashboards or old email threads to rebuild the timeline...

Firma.dev is compliant with the ESIGN Act, UETA, eIDAS (SES and AES) and UK eIDAS, and signatures made with it are legally binding in 55+ countries. The one-time code evidence covers the signer's side of the record. If you also want your company's side on the finished document, organization seals add it, and the two work well together.

Turning On the One-Time Code

You can require the code for a whole workspace in its settings (an Owner has to make that change), or per request through the API with settings.require_otp_verification:

{
  "settings": {
    "require_otp_verification": true
  }
}
{
  "settings": {
    "require_otp_verification": true
  }
}
{
  "settings": {
    "require_otp_verification": true
  }
}

Verification runs by email only. Signers receive the code in their inbox and enter it before the document opens. More on the signer flow is on the email OTP feature page.

The code costs nothing extra. You pay €0.049 per envelope (~5¢ USD), pay-as-you-go, with no monthly minimums and no per-seat fees. Details are on the pricing page.

For Developers: Reading the Evidence From the API

GET /signing-requests/{id}/audit returns the full event list under results. Filter for event equal to otp_verified, then read timestamp, ip_address and details.otp_code_id. One event looks like this:

{
  "id": "a1b2c3d4-0000-0000-0000-000000000007",
  "timestamp": "2026-10-21T09:14:03.000Z",
  "source": "signer",
  "event": "otp_verified",
  "description": "Entered the one-time code sent by email",
  "actor": { "name": "Alice Johnson", "email": "alice@example.com" },
  "ip_address": "203.0.113.42",
  "details": {
    "channel": "email",
    "otp_code_id": "5f0c9e2a-0000-0000-0000-000000000001"
  }
}
{
  "id": "a1b2c3d4-0000-0000-0000-000000000007",
  "timestamp": "2026-10-21T09:14:03.000Z",
  "source": "signer",
  "event": "otp_verified",
  "description": "Entered the one-time code sent by email",
  "actor": { "name": "Alice Johnson", "email": "alice@example.com" },
  "ip_address": "203.0.113.42",
  "details": {
    "channel": "email",
    "otp_code_id": "5f0c9e2a-0000-0000-0000-000000000001"
  }
}
{
  "id": "a1b2c3d4-0000-0000-0000-000000000007",
  "timestamp": "2026-10-21T09:14:03.000Z",
  "source": "signer",
  "event": "otp_verified",
  "description": "Entered the one-time code sent by email",
  "actor": { "name": "Alice Johnson", "email": "alice@example.com" },
  "ip_address": "203.0.113.42",
  "details": {
    "channel": "email",
    "otp_code_id": "5f0c9e2a-0000-0000-0000-000000000001"
  }
}

document_finished events carry details.otp_code_id too when the finishing session was linked to a verified code, so you can match the finish to the code entry. These events apply to requests under 1,000 tracking rows. Larger requests keep the existing truncation.

The verify-signing-otp responses also got more precise in this release:

  • 404 SIGNING_USER_NOT_FOUND for an unknown signer

  • 404 SIGNING_REQUEST_NOT_FOUND when the request was deleted

  • 400 INVALID_INPUT for a malformed signingUserId

  • 200 with code: "SIGNING_STATE_CHANGED" and a state when the request can no longer be signed (cancelled, declined, expired, already signed, and similar)

  • 500 INTERNAL for a database fault

A correct code that runs into a transient fault no longer uses up one of the signer's attempts. There's no OpenAPI schema change, and event stays a free-text string.

Admin descriptions changed too. A cancel from the dashboard now reads "Signing Request Cancellation requested", a delete reads "Signing Request Deletion requested", and a certificate retry adds "Certificate regeneration requested". Firma.dev writes each line before the change happens, so "requested" records the request and does not confirm it completed. Check the request's status before you act on one of these rows. Rows written before v1.40.3 keep the old wording.

The full list is in the API changelog and the audit trail guide.

Summary

Switch on the one-time code and every request completed from October 20 on carries proof of it: an otp_verified event with its time and IP address in the audit trail, and an Authentication line on each signer's certificate row.

Get started with Firma.dev for free, no credit card required.

  1. Heading

Background Image

Ready to add e-signatures to your application?

Get started for free. No credit card required. Pay only €0.049 per envelope when you're ready to go live.

Background Image

Ready to add e-signatures to your application?

Get started for free. No credit card required. Pay only €0.049 per envelope when you're ready to go live.

Background Image

Ready to add e-signatures to your application?

Get started for free. No credit card required. Pay only €0.049 per envelope when you're ready to go live.