Skip to main content

Passcodes in Embedded Signing

Agent Skill

Let an agent scaffold this for you

Install the TurboDocx Quickstart Skill and let Claude Code, Cursor, Copilot, Codex, or any agent that speaks the Agent Skills standard install the SDK, wire it into your app, and write a working TurboSign integration end-to-end.

bash — turbodocx
$npx skills add TurboDocx/quickstart
# then, inside your agent:›/turbodocx-sdk turbosign
TurboDocx embedded signing sample app showing the signing panel inside a host web page
Complete embedded signing sample appFour working flows: widget, own iframe, external identity verification and kiosk. Clone it and run it locally.
View on GitHub →

An admin turns passcodes on in Email and SMS passcode. Your code then asks for a passcode on each embedded signer.

  • Email passcode: every build guide uses one: auth: { emailOtp: true } in createEmbeddedSignature.
  • SMS passcode: this page.
  • Which channel applies when you set none, and how each SDK leaves the channel out: see The recipient in the API reference.
Passcodes only for signers in your own app

If only the signers in your own app should verify, keep Only when requested. Turn on SMS and connect a provider (Steps 4-5), then have your integration request SMS on each recipient it embeds.

Other signature requests, including Pipelines, stay passcode-free. See Verify only your embedded signers by SMS.

Request an SMS passcode from your code​

Before you start, check these:

  1. Your plan includes SMS passcodes (Pro or Enterprise).
  2. An admin turned on Allow SMS as an alternative to email (Step 4).
  3. An admin connected an SMS provider, and its status reads Connected (Step 5). Your request does not choose a provider; TurboSign uses the one your organization connected.
  4. You have the signer's mobile number in international format, for example +15551234567.

Then give the recipient an SMS auth block instead of emailOtp. createEmbeddedSignature sets the recipient's phone from it.

// Continues the setup from "Your own iframe": imports and TurboSign.configure(...).
const { documentId, recipients } = await TurboSign.createEmbeddedSignature({
file: await readFile("contract.pdf"),
fileName: "contract.pdf",
documentName: "Service Agreement",
recipients: [
{
name: "Jane Doe",
email: "jane@example.com",
auth: { sms: { phoneNumber: "+15551234567" } }, // text the passcode
fields: { signature: "{signature1}", date: "{date1}" },
},
],
});
const embedUrl = recipients[0].embedUrl;

Frame embedUrl exactly as in the build guides. The signer sees the same gate as for email, and the code arrives by text message.

If you send with sendSignature instead, set phone on the recipient and identityVerification: { "mode": "otp", "channel": "sms" }.

ErrorCause
OtpPhoneRequired (400), or PhoneRequiredForSmsOtp from the JS, Python, Go, Java or Ruby SDK before the request is sentThe recipient asks for SMS but has no phone number. The PHP SDK doesn't check first, so PHP callers get OtpPhoneRequired from the API. With the createEmbeddedSignature SMS shorthand, the phone comes from phoneNumber, so this only happens when that is empty.
OtpPhoneInvalid (400)The number is well-formed but cannot exist.
OtpNotEntitled, SmsOtpLimitExceeded (402)The plan does not include SMS passcodes, or the SMS allowance is used up.
SmsOtpNotEnabled (403)Allow SMS as an alternative to email is off.
OtpOverrideNotAllowed (403)The organization verifies every request and locked the method to a different channel. Ask an admin to turn on Let senders change the method per recipient.
SmsProviderNotConfigured (409)No SMS provider is saved for the organization.

Verify only your embedded signers by SMS​

A common setup: your team keeps sending ordinary signature requests (from the TurboDocx app and from Pipelines) with no passcode, while signers in your own app verify by text message. You do not need an SMS default for the whole organization to do this.

  1. On the One-time passcode tab, turn on Enable identity verification.
  2. Under When to verify signers, keep Only when requested (the default). Signature requests sent from the app and from Pipelines keep signing with no passcode; in the app, each signer's Identity verification stays on No verification unless a sender changes it.
  3. Under Text message (SMS), turn on Allow SMS as an alternative to email, then connect your SMS provider and check the status reads Connected to Twilio (or RingCentral).
  4. In your integration, ask for SMS on each recipient you embed, as in the code above. With sendSignature, the recipient looks like this:
{
"name": "Jane Doe",
"email": "jane@example.com",
"phone": "+15551234567",
"identityVerification": { "mode": "otp", "channel": "sms" }
}
Pick the channel in your app, not from defaultChannel

Choose SMS in your own app's configuration. Do not copy it from defaultChannel: with Only when requested that value is none, which tells you nothing about the channel you want.

Check the organization default from your code​

Your integration can read the result with GET /turbosign/embedded-signing-settings:

  • defaultChannel is none, email, or sms.
  • allowChannelOverride tells it whether a different channel is accepted.

See The organization default for details.

Next​