Skip to main content
This guide covers the recurring shapes that signing workflows take: multiple signers who go in order, signers who don’t need an order, a second signer whose identity isn’t known until the first one acts, and a signer who also has to approve. Each pattern below is a variation on creating and sending a signing request, so read that guide first if you haven’t already.

Choosing a pattern

Pattern: Sequential signing, known recipients

Use this when every recipient’s email is known at send time and later signers should only be notified once earlier ones finish. This is the default: settings.use_signing_order is 1 unless you turn it off, and recipients sign in ascending order.
1

Create recipients with explicit order

Give each recipient an order. Lower numbers sign first.
2

Send the request

Use create-and-send for a single call, or create followed by /send if you need a review step first.
3

Only the first signer is emailed

Firma emails recipients at order: 1 immediately. Once they finish, Firma automatically emails the next order tier — you don’t drive this yourself. Subscribe to webhooks instead of polling if you want to track each step.
Bob does not receive an email until Alice completes her fields. Subscribe to signing_request.recipient.signed if you want to track each step, and signing_request.completed for when the whole chain finishes.
order values just need to sort correctly — they don’t need to be contiguous. However, tied order values (e.g. 1, 2, 2, 5) do not create a parallel signing tier — only one recipient per order value is notified at a time. If you need two signers to sign simultaneously, use the parallel pattern with use_signing_order: false instead.

Pattern: Dynamic second signer

This is the case behind most “how do I add a signer mid-flow” tickets: signer 1 fills something in — a referral, a co-signer, a beneficiary — and only then do you know signer 2’s email. The instinct is to send the request with just signer 1, then update it to add signer 2 once you know who they are.
That update is not possible on the same signing request. Once sent_on is set, PATCH/PUT /signing-requests/{id} and DELETE /signing-requests/{id} all return 409 ALREADY_SENT — a sent signing request is fully immutable, and that includes adding a new recipient. There is no endpoint that adds a recipient to, or changes a recipient’s email on, a request that’s already been sent. See Error handling: 409 ALREADY_SENT below for the full list of operations this blocks.
The workaround is to chain two signing requests instead of mutating one:
1

Send request #1 with only signer 1

Include a field (type: "text", some variable_name like next_signer_email) for signer 1 to name the next signer. Send it with create-and-send, exactly one recipient.
2

Listen for signer 1's completion

Since request #1 has a single signer, signing_request.completed fires as soon as they finish — you don’t need signing_request.recipient.signed for this case.
3

Read the field signer 1 filled in

The webhook payload doesn’t carry field values, so call GET /signing-requests/{id}/fields and read final_value off the field with the matching variable_name.
4

Create and send request #2 for signer 2

Use the email you just extracted. This is a new signing request with its own id.
Because this is two separate signing requests, it produces two separate completion certificates and two separate audit trails — there is no single certificate covering both signers. If a unified certificate is a hard requirement, the only alternative is to collect signer 2’s email before sending — e.g., through a form in your own app — rather than mid-flow.
Firma doesn’t have a metadata or external-reference field on the signing request itself to link request #1 and request #2 together. Store that mapping (e.g. original_signing_request_id) in your own database when you create request #2.

Approach 1: Webhook-triggered second request

Use this when signers receive email invitations and your backend handles the chain.
Respond 200 before doing the field lookup and the follow-up create-and-send call — Firma’s webhook delivery times out at 5 seconds, and the pattern above involves two outbound API calls of its own.

Approach 2: Embedded signing with editable identity fields

Use this when you embed signing directly in your app and want signer 2 to confirm or correct their own identity when they open the signing view — no email-based flow needed.
1

Create and send request #1 for signer 1

Include a text field (e.g. variable_name: "next_signer_email") for signer 1 to provide signer 2’s email. Set send_signing_email: false since you’re embedding the signing view yourself.
2

Embed signer 1's signing view

Use the embeddable signing component to render signer 1’s signing view in your app. Listen for the firma:signing:completed postMessage event.
3

On completion, read signer 2's email from the field

Call GET /signing-requests/{id}/fields and read final_value from the field with variable_name: "next_signer_email".
4

Create request #2 with identity_editable_fields

Create a new signing request for signer 2 with settings.identity_editable_fields set to ["name", "company"]. Recognized keys are name (covers first and last name together), phone, company, title, and address. This lets signer 2 review and correct their own name and company when they open the signing view — useful when signer 1 may have provided approximate details. Note: email is not editable through this mechanism.
5

Embed signer 2's signing view

Render signer 2’s signing view in your app. Signer 2 sees their pre-filled identity, can correct it if needed, and signs.
Setting identity_editable_fields: ["name", "company"] lets signer 2 update their own name and company in the signing view before signing. Recognized keys: name (first + last name together), phone, company, title, address. Email is not editable through this mechanism — the email provided when creating the signing request is permanent. Set notify_identity_change_email: 1 to receive a notification when a signer changes their identity.

Pattern: Parallel signing

Use this when signers are independent of each other — nobody needs to wait for anyone else to finish. Set settings.use_signing_order: false on the request. With it off, Firma emails every recipient at send time instead of gating later tiers on earlier ones finishing. order values are still stored on each recipient, but they aren’t enforced — nobody gets an out-of-turn block.
All three receive their signing email immediately. The request completes (and signing_request.completed fires) once all of them have finished, regardless of the order they actually sign in.

Pattern: Signer and approver

Firma’s designation model is deliberately mutually exclusive: a recipient row is a Signer, an Approver, or CC — never more than one. If the same person needs to both sign and then approve, they appear as two rows with different order values, not one row with two roles.
Fields matter here too: approval_signature, approval_checkmark, and approval_date fields can only be assigned to a recipient whose designation is Approver — assigning one to a Signer row returns a 400. Their value is authored server-side when the approver completes their review; you don’t submit one yourself.
This also composes with sequential signing: give the Signer row a lower order than the Approver row, and Alice’s own approval step won’t unlock until she’s finished signing.

Error handling: 409 ALREADY_SENT

ALREADY_SENT means the signing request has a sent_on timestamp and the operation you tried only works on a draft. It’s returned, at 409, from: What you can still do to a sent-but-not-finished request: If you hit ALREADY_SENT while trying to fix a typo’d recipient email or add a recipient you forgot, there’s no in-place fix — cancel and recreate, or (for the “didn’t know the second recipient yet” case) use the dynamic second signer pattern above.

Next steps

  • Sending a signing request — the base create/send flow these patterns build on
  • Webhooks — event types, signature verification, and retry behavior
  • Field prefilling — populate fields with known data instead of asking a signer to fill them in