Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions docs/TurboSign/Setting-up-TurboSign.md
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,18 @@ After clicking "Send Document":
3. **You track progress** on your TurboSign dashboard as each person signs
4. **Everyone receives** a copy of the fully signed document, including you as the sender

### What Your Signers See

When a signer opens the document, a **Pages** panel shows every page as a thumbnail. A mark sits wherever that signer has a field: indigo for a field they still need to fill, green for one that's done, and dashed for an optional one. Each page also shows how many required fields are left on it. Clicking a thumbnail jumps to that page, and the highlight follows the page the signer is reading.

![The signing page on a desktop, with the Pages panel open on the left showing 6 pages, page 2 highlighted with 2 left, page 3 with 1 left, and the Needs you, Done and Optional legend](/img/turbosign/page-navigation/01-desktop-rail.png)

- **Wide screens:** the panel is open on the left.
- **Narrower screens:** the panel collapses to slim tabs with a count badge. The signer can open it again, and their choice is remembered.
- **Tablets and phones:** a page button in the bottom bar (a grid icon with the current page, like **3/6**) opens the same thumbnails in a drawer or a bottom sheet.

![The Pages bottom sheet on a phone, showing 4 required fields left and a row of page thumbnails with 2 left on page 2 and 1 left on page 3](/img/turbosign/page-navigation/02-phone-pages-sheet.png)

<br/>

## Congratulations! 🎉
Expand Down
4 changes: 4 additions & 0 deletions docs/TurboSign/embedded-signing/build/own-iframe.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ In your page, ask your server for a URL and set it as the iframe's `src`. Give t

The browser code is the same whichever language your server uses.

The signing page shows a page thumbnail rail that follows the iframe's width, not the browser window's: open at 1200px and wider, collapsed to slim tabs from 900px to 1199px, and under 900px a page button in the bottom bar (a grid icon with the current page, like **3/6**). Picking a page scrolls only the document inside the iframe, never your page. To start the rail collapsed or hide it, pass `pageNavigation` when you request the signing URL. See [Page navigation](../reference.md#page-navigation).

![The signing page in a host app's iframe, with the page thumbnail rail collapsed to slim tabs and count badges on the pages that still need the signer](/img/embedded-signing/page-navigation-iframe.png)

## Step 4: Listen for the completion message

When the signer finishes, the signing page posts a `turbosign:completed` message to your page. Accept it only when it comes from the TurboSign origin **and** from your own iframe.
Expand Down
2 changes: 2 additions & 0 deletions docs/TurboSign/embedded-signing/build/react-widget.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ export function SignStep({ name, email }: { name: string; email: string }) {
| `onDeclined`, `onError` | No | Reserved. The signing page does not send these events yet. |
| `allowAnyOrigin` | No | Development only. Accepts messages from any origin. Never ship it. |

The widget has no prop for the signing page's page navigation. The thumbnail rail follows the widget's width (open at 1200px and wider, collapsed from 900px to 1199px, a page button in the bottom bar under 900px). To start it collapsed or hide it, pass `pageNavigation` on your server when you request the signing URL. See [Page navigation](../reference.md#page-navigation).

:::warning Don't leave origin empty
The widget fails closed. If `origin` is missing, it ignores every message, logs a one-time warning in the console, and `onCompleted` never fires. `allowAnyOrigin` turns that off for local debugging, but then any frame on your page could fake a completion.
:::
Expand Down
2 changes: 2 additions & 0 deletions docs/TurboSign/embedded-signing/build/web-component.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ Add a route to your server, for example `POST /api/signing-session`. It calls `c
| `title` | No | The iframe's accessible name. Defaults to `TurboSign signing`. |
| `allow-any-origin` | No | Development only. Accepts messages from any origin. Never ship it. |

The element has no attribute for the signing page's page navigation. The thumbnail rail follows the element's width (open at 1200px and wider, collapsed from 900px to 1199px, a page button in the bottom bar under 900px). To start it collapsed or hide it, pass `pageNavigation` on your server when you request the signing URL. See [Page navigation](../reference.md#page-navigation).

The element re-emits `turbosign:completed` as a bubbling `CustomEvent`, so a listener on a parent element works too. It also defines `turbosign:declined` and `turbosign:error`, which the signing page does not send yet.

:::warning Don't leave origin empty
Expand Down
41 changes: 35 additions & 6 deletions docs/TurboSign/embedded-signing/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ keywords:
- identityVerification
- signing-url endpoint
- turbosign:completed
- pageNavigation
- embedded signing errors
- OtpOverrideNotAllowed
---
Expand Down Expand Up @@ -47,6 +48,7 @@ Creates the document, adds each signer, and returns a signing URL for whoever si
| `fields` | No | Full field list. When set, it replaces every recipient's `fields` shorthand. |
| `sendEmail` | No | Defaults to `false`. |
| `returnUrl` | No | `https` URL the signer returns to after signing. |
| `pageNavigation` | No | `auto` (default), `collapsed` or `hidden`. How the signing page shows its page thumbnails in your iframe. See [Page navigation](#page-navigation). |

A recipient's `auth` asks for a passcode, and its `fields` places fields on text anchors such as `{signature1}`. Leave `auth` off for no passcode (the [organization default](#the-organization-default) then applies).

Expand Down Expand Up @@ -106,6 +108,7 @@ REST: `POST /turbosign/documents/{documentId}/signing-url`
|---|---|---|
| `recipientId` or `externalId` | Exactly one | Picks the recipient. |
| `returnUrl` | No | `https` URL the signer returns to after signing. See [Return URL](#return-url). |
| `pageNavigation` | No | `auto` (default), `collapsed` or `hidden`. How the signing page shows its page thumbnails in your iframe. See [Page navigation](#page-navigation). |
| `identityAssertion` | For `external_idv` | Your provider's verification. See [External identity verification](../identity-verification/external-identity-verification.md). |

Unknown keys are rejected.
Expand Down Expand Up @@ -150,6 +153,24 @@ The REST response wraps the result in `data.results`. The SDKs return the inner
- The signing page reads it back when it loads and redirects there after the signer finishes.
- It is set per request. Requesting a new signing URL without `returnUrl` clears the one stored earlier.

#### Page navigation {#page-navigation}

The signing page shows every page of the document as a thumbnail, marks where the signer's fields are, and counts the required fields left on each page. `pageNavigation` sets how that navigation appears in your iframe:

| Value | What the signer sees |
|---|---|
| `auto` (default) | Sized to the iframe's width, not the browser window's: the thumbnail rail is open at 1200px and wider, collapsed to slim tabs from 900px to 1199px, and replaced under 900px by a page button in the bottom bar (a grid icon with the current page, like **3/6**). |
| `collapsed` | The rail starts collapsed at any width. The signer can still open it. |
| `hidden` | No rail and no page button in the bottom bar. |

- Any other value is rejected with a `400`.
- It is set per request, like `returnUrl`. Requesting a new signing URL without `pageNavigation`, or with `auto`, resets it to `auto`.
- `createEmbeddedSignature` passes it to the signing URL it returns for the first signer. When you mint a URL for a later signer with `createSigningUrl`, pass it again.
- It applies only to signing URLs from `createSigningUrl` and `createEmbeddedSignature`. Signing links sent by email always behave as `auto`.
- When the signer picks a page, only the document inside the iframe scrolls, never your page.

In the SDKs: `pageNavigation` in JavaScript / TypeScript (type `PageNavigationMode`), `page_navigation=` in Python, `PageNavigation` with the `PageNavigationAuto`, `PageNavigationCollapsed` and `PageNavigationHidden` constants in Go, the `PageNavigation` enum in PHP and Java, and `page_navigation:` on `create_signing_url` in Ruby (`pageNavigation:` in the `create_embedded_signature` request hash).

### Example

<Tabs groupId="language" queryString>
Expand All @@ -161,6 +182,7 @@ const { url, expiresAt, identityVerificationMode, pendingChecks } =
await TurboSign.createSigningUrl(documentId, {
externalId: "your_customer_123", // or recipientId, exactly one
returnUrl: "https://app.yourcompany.com/signed",
pageNavigation: "collapsed", // optional: "auto" (default), "collapsed" or "hidden"
});
```

Expand All @@ -173,6 +195,7 @@ link = await TurboSign.create_signing_url(
document_id,
external_id="your_customer_123", # or recipient_id, exactly one
return_url="https://app.yourcompany.com/signed",
page_navigation="collapsed", # optional: "auto" (default), "collapsed" or "hidden"
)
url, pending_checks = link["url"], link["pendingChecks"]
```
Expand All @@ -181,11 +204,13 @@ url, pending_checks = link["url"], link["pendingChecks"]
<TabItem value="php" label="PHP" attributes={{className: 'tab-lang tab-lang--php'}}>

```php
use TurboDocx\Types\PageNavigation;
use TurboDocx\Types\Requests\CreateSigningUrlRequest;

$link = TurboSign::createSigningUrl($documentId, new CreateSigningUrlRequest(
externalId: 'your_customer_123', // or recipientId, exactly one
returnUrl: 'https://app.yourcompany.com/signed'
returnUrl: 'https://app.yourcompany.com/signed',
pageNavigation: PageNavigation::COLLAPSED // optional: AUTO (default), COLLAPSED or HIDDEN
));
$url = $link->url;
```
Expand All @@ -196,8 +221,9 @@ $url = $link->url;
```go
// Inside a function that returns error, with client and ctx as in "Your own iframe". pdf holds the PDF bytes.
link, err := client.TurboSign.CreateSigningURL(ctx, documentID, &turbodocx.CreateSigningURLRequest{
ExternalID: "your_customer_123", // or RecipientID, exactly one
ReturnURL: "https://app.yourcompany.com/signed",
ExternalID: "your_customer_123", // or RecipientID, exactly one
ReturnURL: "https://app.yourcompany.com/signed",
PageNavigation: turbodocx.PageNavigationCollapsed, // optional: Auto (default), Collapsed or Hidden
})
if err != nil {
return err
Expand All @@ -215,6 +241,7 @@ CreateSigningUrlResponse link = client.turboSign().createSigningUrl(
new CreateSigningUrlRequest.Builder()
.externalId("your_customer_123") // or recipientId, exactly one
.returnUrl("https://app.yourcompany.com/signed")
.pageNavigation(PageNavigation.COLLAPSED) // optional: AUTO (default), COLLAPSED or HIDDEN
.build());
String url = link.getUrl();
```
Expand All @@ -227,7 +254,8 @@ String url = link.getUrl();
link = TurboDocxSdk::TurboSign.create_signing_url(
document_id,
external_id: "your_customer_123", # or recipient_id:, exactly one
return_url: "https://app.yourcompany.com/signed"
return_url: "https://app.yourcompany.com/signed",
page_navigation: "collapsed" # optional: "auto" (default), "collapsed" or "hidden"
)
url = link["url"]
```
Expand All @@ -239,8 +267,9 @@ url = link["url"]

| Status | `code` | Meaning |
|---|---|---|
| 400 | `RecipientSelectorInvalid`, `InvalidReturnUrl` | Send exactly one selector; `returnUrl` must be `https`. |
| 400 | `RecipientSelectorInvalid` | Send exactly one selector. |
| 400 | `IdentityAssertion*`, `IdentityProviderMismatch`, `IdentityEmailMismatch` | The `external_idv` assertion is missing or fails a check. |
| 400 | none (`type` is `ValidationError`) | The body failed validation: `returnUrl` is not an `https` URL, or `pageNavigation` is not `auto`, `collapsed` or `hidden`. |
| 403 | none (a plain `403 Forbidden`) | The API key belongs to a **User**. |
| 403 | `EmbeddedSigningNotEnabled`, `ExternalIdvNotAllowed`, `IdentityOverrideNotAllowed` | The organization has not turned on what the recipient uses. |
| 404 | `RecipientNotFound` | No recipient matches the selector. |
Expand Down Expand Up @@ -523,7 +552,7 @@ Identity and passcode errors from sending a document and from `createSigningUrl`
| 400 | `IdentityConfigInvalid`, `IdvProviderRequired`, `OverrideNotAcknowledged`, `IdentityModeConflict` | The recipient's `identityVerification` block is invalid or incomplete. |
| 400 | `DuplicateExternalId` | Two recipients on the document share an `externalId`. |
| 400 | `RecipientSelectorInvalid` | `createSigningUrl` needs exactly one of `recipientId` or `externalId`. |
| 400 | `InvalidReturnUrl` | `returnUrl` is not an `https` URL. |
| 400 | none (`type` is `ValidationError`) | The `createSigningUrl` body failed validation: a `returnUrl` that is not `https`, or a `pageNavigation` other than `auto`, `collapsed` or `hidden`. This body is `{ "message", "type", "data": { "errors" } }`, not the four-field body above. |
| 400 | `IdentityAssertionRequired`, `IdentityAssertionInvalid`, `IdentityProviderMismatch`, `IdentityEmailMismatch`, `IdentityAssertionStale`, `IdentityAssertionReused` | The `external_idv` assertion is missing or fails a check (see [External identity verification](../identity-verification/external-identity-verification.md#errors)). |
| 402 | `OtpNotEntitled`, `SmsOtpLimitExceeded` | The plan does not include this verification, or the SMS allowance is used up. |
| 403 | none (a plain `403 Forbidden`) | The API key belongs to a **User**. Requesting a signing URL needs an **Administrator** or **Contributor** key. |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,7 @@ url = link["url"]

Open `url` right away: it is single-use and expires in about five minutes. To show it inside your app, hand it to the [React widget](../embedded-signing/build/react-widget.md), frame it in [your own iframe](../embedded-signing/build/own-iframe.md), or use the [web component](../embedded-signing/build/web-component.md).

The REST equivalent is `POST /turbosign/documents/{documentId}/signing-url` with the same body (`externalId` or `recipientId`, `identityAssertion`, optional `returnUrl`). Unknown keys are rejected.
The REST equivalent is `POST /turbosign/documents/{documentId}/signing-url` with the same body (`externalId` or `recipientId`, `identityAssertion`, optional `returnUrl`, optional `pageNavigation`). Unknown keys are rejected.

### Required assertion fields

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading