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.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. 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.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.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. Setsettings.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.
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 aSigner, 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.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:
POST /signing-requests/{id}/resend— re-sends the notification email to recipients who are currently at the active signing tier and haven’t finished yet. It does not let you change their email or any other recipient data.POST /signing-requests/{id}/cancel— stops the whole request for everyone.
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