From e5a1f4546ea318059f4fc40d21fa211e6c602138 Mon Sep 17 00:00:00 2001 From: yacinekahlerras-turbodocx Date: Wed, 21 Oct 2026 10:22:17 +0100 Subject: [PATCH 1/6] docs(turbosign): later kiosk signer URLs aren't issued early, not 'can't be created' (#214) (#219) Every recipient's access token exists from document creation; for passcode and no-verification signers the signing URL is that reusable token link. TurboSign refuses to issue it out of turn (409 RecipientNotInTurn) and refuses an out-of-turn signature even with a valid link. Co-authored-by: Yacine Kahlerras Co-authored-by: Claude Opus 5.5 --- docs/TurboSign/embedded-signing/build/sequential-signers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/TurboSign/embedded-signing/build/sequential-signers.md b/docs/TurboSign/embedded-signing/build/sequential-signers.md index 91fe78b2..00acb43a 100644 --- a/docs/TurboSign/embedded-signing/build/sequential-signers.md +++ b/docs/TurboSign/embedded-signing/build/sequential-signers.md @@ -324,7 +324,7 @@ end :::warning Mint just in time, never ahead -Don't try to pre-mint every signer's URL. TurboSign enforces the order: a later signer's URL can't be created until it is genuinely their turn. +Don't try to pre-mint every signer's URL. TurboSign enforces the order: it won't issue a later signer's URL until it is their turn, and it refuses an out-of-turn signature even with a valid link. ::: ## Step 4: Frame each signer in turn From f6d0dec02f7348086c85c43ead939dfa7f8a8f0d Mon Sep 17 00:00:00 2001 From: yacinekahlerras-turbodocx Date: Wed, 21 Oct 2026 10:35:30 +0100 Subject: [PATCH 2/6] docs(turbosign): drop NotSignersTurn, the API only returns RecipientNotInTurn (#217) * docs(turbosign): drop NotSignersTurn, the API only returns RecipientNotInTurn (#213) The embedded-signing pages listed a 409 NotSignersTurn that createSigningUrl never returns: the only turn refusal is RecipientNotInTurn. Remove it from the error tables and prose, and retry only RecipientNotInTurn in the six code samples. Co-Authored-By: Claude Opus 5.5 * docs(turbosign): drop NotSignersTurn from the send and update error codes too (#213) The API never returns NotSignersTurn; its only turn refusal is RecipientNotInTurn. This was the last mention left in the docs. Co-Authored-By: Claude Opus 5.5 (1M context) --------- Co-authored-by: Yacine Kahlerras Co-authored-by: Claude Opus 5.5 Co-authored-by: Amit Sharma --- docs/TurboSign/API-Signatures.md | 2 +- .../build/sequential-signers.md | 22 +++++++------------ docs/TurboSign/embedded-signing/index.md | 2 +- docs/TurboSign/embedded-signing/reference.md | 4 ++-- 4 files changed, 12 insertions(+), 18 deletions(-) diff --git a/docs/TurboSign/API-Signatures.md b/docs/TurboSign/API-Signatures.md index 53372460..acf18e41 100644 --- a/docs/TurboSign/API-Signatures.md +++ b/docs/TurboSign/API-Signatures.md @@ -2179,7 +2179,7 @@ formData.Add(new StringContent(recipients), "recipients"); | `402` | `OtpNotEntitled`, `SmsOtpLimitExceeded` | The plan does not include this verification, or the SMS allowance is used up. | | `403` | `ExternalIdvNotAllowed`, `IdentityOverrideNotAllowed`, `OtpOverrideNotAllowed`, `EmbeddedSigningNotEnabled`, `SmsOtpNotEnabled` | The organization has not turned on the feature or mode the request uses, or has locked the passcode method. | | `404` | `DocumentNotFound`, `RecipientNotFound` | The document or recipient does not exist, was deleted, or belongs to another organization. On `update-with-recipients`, a document ID that does not exist returns `404` with only `{ "error": "Document not found" }`. | -| `409` | `DocumentNotSignable`, `RecipientAlreadySigned`, `RecipientNotInTurn`, `NotSignersTurn`, `SmsProviderNotConfigured`, `RecipientRequiresSingleUseUrl` | The document or recipient is not in a state that allows the request, or the organization has no SMS provider saved. | +| `409` | `DocumentNotSignable`, `RecipientAlreadySigned`, `RecipientNotInTurn`, `SmsProviderNotConfigured`, `RecipientRequiresSingleUseUrl` | The document or recipient is not in a state that allows the request, or the organization has no SMS provider saved. | | `410` | `SigningUrlNotRedeemable` | A single-use signing URL was already used or has expired. | None of these signature errors return a `5xx` status. A `500` from these endpoints means an unexpected server problem, not a problem with your request. diff --git a/docs/TurboSign/embedded-signing/build/sequential-signers.md b/docs/TurboSign/embedded-signing/build/sequential-signers.md index 00acb43a..78b2203d 100644 --- a/docs/TurboSign/embedded-signing/build/sequential-signers.md +++ b/docs/TurboSign/embedded-signing/build/sequential-signers.md @@ -57,7 +57,7 @@ Return the `documentId` and the list (with each `recipientId`) to your page. ## Step 3: Mint the next signer's URL when it is their turn -When a signer finishes, the signing page sends `turbosign:completed` right away, but TurboSign advances the turn a moment later. A mint fired immediately can get HTTP `409` with `RecipientNotInTurn` or `NotSignersTurn`. Retry those two codes a few times with a short delay; treat every other error as real. +When a signer finishes, the signing page sends `turbosign:completed` right away, but TurboSign advances the turn a moment later. A mint fired immediately can get HTTP `409` with `RecipientNotInTurn`. Retry that code a few times with a short delay; treat every other error as real. Both server calls, Step 2 and Step 3, in each SDK language: @@ -87,15 +87,13 @@ export async function startKiosk(signers: Array<{ name: string; email: string }> } // Step 3: POST /api/kiosk/next -const TURN_RACE = new Set(["RecipientNotInTurn", "NotSignersTurn"]); - export async function mintNext(documentId: string, recipientId: string): Promise { for (let attempt = 0; ; attempt++) { try { const { url } = await TurboSign.createSigningUrl(documentId, { recipientId }); return url; } catch (err: any) { - if (!TURN_RACE.has(err?.code) || attempt >= 5) throw err; + if (err?.code !== "RecipientNotInTurn" || attempt >= 5) throw err; await new Promise((r) => setTimeout(r, 1500)); } } @@ -130,15 +128,13 @@ async def start_kiosk(signers: list[dict]) -> dict: ) # {"documentId": ..., "recipients": [...]}, first one "ready" # Step 3: POST /api/kiosk/next -TURN_RACE = {"RecipientNotInTurn", "NotSignersTurn"} - async def mint_next(document_id: str, recipient_id: str) -> str: for attempt in range(6): try: link = await TurboSign.create_signing_url(document_id, recipient_id=recipient_id) return link["url"] except ConflictError as err: - if err.code not in TURN_RACE or attempt == 5: + if err.code != "RecipientNotInTurn" or attempt == 5: raise await asyncio.sleep(1.5) ``` @@ -185,7 +181,7 @@ function mintNext(string $documentId, string $recipientId): string $link = TurboSign::createSigningUrl($documentId, new CreateSigningUrlRequest(recipientId: $recipientId)); return $link->url; } catch (ConflictException $e) { - $race = in_array($e->errorCode, ['RecipientNotInTurn', 'NotSignersTurn'], true); + $race = $e->errorCode === 'RecipientNotInTurn'; if (!$race || $attempt >= 5) { throw $e; } @@ -230,7 +226,7 @@ func MintNext(ctx context.Context, client *turbodocx.Client, documentID, recipie return link.URL, nil } var conflict *turbodocx.ConflictError - race := errors.As(err, &conflict) && (conflict.Code == "RecipientNotInTurn" || conflict.Code == "NotSignersTurn") + race := errors.As(err, &conflict) && conflict.Code == "RecipientNotInTurn" if !race || attempt >= 5 { return "", err } @@ -274,7 +270,7 @@ public String mintNext(String documentId, String recipientId) throws Exception { return client.turboSign().createSigningUrl(documentId, new CreateSigningUrlRequest.Builder().recipientId(recipientId).build()).getUrl(); } catch (TurboDocxException.ConflictException e) { - boolean race = "RecipientNotInTurn".equals(e.getCode()) || "NotSignersTurn".equals(e.getCode()); + boolean race = "RecipientNotInTurn".equals(e.getCode()); if (!race || attempt >= 5) throw e; Thread.sleep(1500); } @@ -305,14 +301,12 @@ def start_kiosk(signers) end # Step 3: POST /api/kiosk/next -TURN_RACE = %w[RecipientNotInTurn NotSignersTurn].freeze - def mint_next(document_id, recipient_id) attempts = 0 begin TurboDocxSdk::TurboSign.create_signing_url(document_id, recipient_id: recipient_id)["url"] rescue TurboDocxSdk::ConflictError => e - raise unless TURN_RACE.include?(e.code) && (attempts += 1) <= 5 + raise unless e.code == "RecipientNotInTurn" && (attempts += 1) <= 5 sleep 1.5 retry @@ -412,7 +406,7 @@ For the **whole document**, don't rely on the last browser event. Check the docu | Symptom | Cause | Fix | |---|---|---| -| HTTP `409` `RecipientNotInTurn` or `NotSignersTurn` right after a signer finishes | TurboSign has not advanced the turn yet. | Retry for a few seconds, as in Step 3. | +| HTTP `409` `RecipientNotInTurn` right after a signer finishes | TurboSign has not advanced the turn yet. | Retry for a few seconds, as in Step 3. | | HTTP `409` `RecipientNotInTurn` that never clears | An earlier signer has not actually signed. | Frame the earlier signer again. | | HTTP `409` `RecipientAlreadySigned` | That signer already signed. | Skip to the next one. | | The second signer's panel is blank | Same as any blank frame: your origin is not allowed. | Add your origin under **Allowed embedding domains**. | diff --git a/docs/TurboSign/embedded-signing/index.md b/docs/TurboSign/embedded-signing/index.md index 881e9e15..652bf167 100644 --- a/docs/TurboSign/embedded-signing/index.md +++ b/docs/TurboSign/embedded-signing/index.md @@ -122,7 +122,7 @@ The [API reference](./reference.md) has every request and response field. | 403 | none (a plain `403 Forbidden`) | The API key belongs to a **User**. Use an **Administrator** or **Contributor** key. | | 403 | `EmbeddedSigningNotEnabled` | Ask an admin to turn on **Enable identity verification**. | | 403 | `OtpOverrideNotAllowed` | Your organization locked the passcode method. Omit the channel, or ask an admin to let senders change it. | -| 409 | `RecipientNotInTurn`, `NotSignersTurn` | An earlier signer has not finished. Mint this signer's URL when it is their turn. | +| 409 | `RecipientNotInTurn` | An earlier signer has not finished. Mint this signer's URL when it is their turn. | | 410 | `SigningUrlNotRedeemable` | A single-use URL was used or expired. Request a new one. | Every error code is in the [API reference](./reference.md#errors). diff --git a/docs/TurboSign/embedded-signing/reference.md b/docs/TurboSign/embedded-signing/reference.md index f7363de1..175c4313 100644 --- a/docs/TurboSign/embedded-signing/reference.md +++ b/docs/TurboSign/embedded-signing/reference.md @@ -244,7 +244,7 @@ url = link["url"] | 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. | -| 409 | `RecipientNotInTurn`, `NotSignersTurn`, `RecipientAlreadySigned`, `DocumentNotSignable` | Not this signer's turn, already signed, or the document can't be signed. | +| 409 | `RecipientNotInTurn`, `RecipientAlreadySigned`, `DocumentNotSignable` | Not this signer's turn, already signed, or the document can't be signed. | | 410 | `SigningUrlNotRedeemable` | A single-use URL was opened already or expired. Request a new one. | :::caution Deprecated: GET signing-link @@ -532,7 +532,7 @@ Identity and passcode errors from sending a document and from `createSigningUrl` | 404 | `RecipientNotFound` | No recipient on the document matches the selector. | | 409 | `SmsProviderNotConfigured` | The recipient resolves to SMS but the organization has no SMS provider saved. | | 409 | `RecipientRequiresSingleUseUrl` | The deprecated `signing-link` endpoint was called for an `external_idv` or `override` recipient. Use `createSigningUrl`. | -| 409 | `DocumentNotSignable`, `RecipientAlreadySigned`, `RecipientNotInTurn`, `NotSignersTurn` | The document or recipient is not in a signable state. | +| 409 | `DocumentNotSignable`, `RecipientAlreadySigned`, `RecipientNotInTurn` | The document or recipient is not in a signable state. | | 410 | `SigningUrlNotRedeemable` | A single-use signing URL was already used or has expired. Request a new one. | | 423 | `locked` | The signer entered 20 wrong codes. See [Passcode attempts and lockout](#passcode-attempts-and-lockout). | From 08ebb4dc40c1d0ee76e5a45046108b2ba4bb0411 Mon Sep 17 00:00:00 2001 From: yacinekahlerras-turbodocx Date: Wed, 21 Oct 2026 10:44:00 +0100 Subject: [PATCH 3/6] docs(turbosign): say embedded verification is recommended, not enforced (#215) (#218) With no verification on a recipient and an org that verifies only when requested, TurboSign still issues a reusable signing link. Reword the two spots that said every embedded signer needs a method, add a caution, and link to the identity-verification warning that already says so. Co-authored-by: Yacine Kahlerras Co-authored-by: Claude Opus 5.5 --- docs/TurboSign/embedded-signing/build/_setup-and-verify.mdx | 2 +- docs/TurboSign/embedded-signing/index.md | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/TurboSign/embedded-signing/build/_setup-and-verify.mdx b/docs/TurboSign/embedded-signing/build/_setup-and-verify.mdx index d8535a55..2adbe502 100644 --- a/docs/TurboSign/embedded-signing/build/_setup-and-verify.mdx +++ b/docs/TurboSign/embedded-signing/build/_setup-and-verify.mdx @@ -1,3 +1,3 @@ An admin must have completed [Set up your organization](../set-up-your-organization.md): **Enable identity verification** is on (it is the master switch for embedded signing), and your app's origin is under **Allowed embedding domains**. -This guide verifies each signer with an **email passcode**. Every embedded signer needs a verification method unless you use the sender override while testing. To use SMS, your own identity provider, or the override, see [Identity verification](../../identity-verification/index.md). +This guide verifies each signer with an **email passcode**. Give every embedded signer a verification method. TurboSign does not enforce this: with no verification, and an organization that verifies only when requested, it still issues a reusable link that anyone holding it can use (see [A recipient with no verification is unprotected](../../identity-verification/index.md#signers-in-your-own-app-embedded-signing)). To use SMS, your own identity provider, or the override, see [Identity verification](../../identity-verification/index.md). diff --git a/docs/TurboSign/embedded-signing/index.md b/docs/TurboSign/embedded-signing/index.md index 652bf167..ee070132 100644 --- a/docs/TurboSign/embedded-signing/index.md +++ b/docs/TurboSign/embedded-signing/index.md @@ -49,7 +49,11 @@ Every embedded signing integration makes the same four moves: ## Choose how signers verify -Every embedded signer needs a verification method, unless you use the sender override while testing. Your app shows the signing page itself and TurboSign emails no link, so a check is what ties the person at the screen to the signer of record. +Give every embedded signer a verification method. Your app shows the signing page itself and TurboSign emails no link, so a check is what ties the person at the screen to the signer of record. + +:::caution TurboSign does not enforce this +If you set no verification on a signer and your organization verifies only when requested, TurboSign still issues a reusable signing link, and anyone holding it can sign. If your organization verifies on every signature request, the signer gets your organization's default method instead. See [A recipient with no verification is unprotected](../identity-verification/index.md#signers-in-your-own-app-embedded-signing). +::: | Method | Who verifies the signer | Signing URL | |---|---|---| From 3219ab70bd4dbd881d6ae6c1bb16fbbfbe89ca8f Mon Sep 17 00:00:00 2001 From: yacinekahlerras-turbodocx Date: Wed, 21 Oct 2026 12:32:10 +0100 Subject: [PATCH 4/6] docs(turbosign): fix webhook verification samples, idempotency key, retries, HTTPS and URL limit (#227) * docs(turbosign): fix webhook verification samples, idempotency key, retries, HTTPS and URL limit (#211) - Rewrite the SDK verification samples against the real SDK signatures: JS passed one object (rejects every delivery), Python imported a non-existent turbodocx module with wrong keyword names, Go had the wrong argument order and didn't compile, and .NET used an API no SDK provides. Tabs are now JS, Python, PHP, Go, Java and Ruby. - Dedupe on the payload's event_id: X-TurboDocx-Delivery-Id is new on every attempt, so it can't catch retries. - 3 attempts in total (2 retries), with the real 1 min / 5 min backoff. - Webhook URLs must be HTTPS even for testing; up to 10 URLs, not 5. Co-Authored-By: Claude Opus 5.5 * docs(turbosign): Ruby gem caveat, header-case tip, no-redirect note (review of #227) - The Ruby tab now carries the same note the embedded-signing guides use: the turbodocx-sdk gem is not on RubyGems yet, install it from the SDK repo (the Ruby SDK pages are still hidden drafts, so no link to them). - Troubleshooting said header names must be lowercase; they are case-insensitive and the Go/Java samples use canonical case. - Delivery behavior: redirects (3xx) are not followed and count as a failure. Co-Authored-By: Claude Opus 5.5 * docs(turbosign): runnable Go sample, real Delivery Object, replay/event_id note, UI and alt-text fixes (review of #227) - Go sample is now a complete program (func main + log import): it built with go vet but not go build when copied verbatim. - Delivery Object matches the API response (no webhookId; adds responseBody, nextRetryAt, errorMessage, status) and explains the status values. - A manual replay keeps the same event_id; say so next to the dedupe advice. - Point to the SDK's testWebhook for sending a sample event. - "Webhooks" is a left-menu item in E-Signature Settings, not a tab. - regenerateWebhookSecret, not rotateSecret. - Real alt text on three images that all said "Get It Signed button". - Ruby caveat uses the same :::note admonition as the embedded-signing guide. Co-Authored-By: Claude Opus 5.5 * docs(turbosign): API objects match responses, test-event caveat, delivery-id vs id, UI wording (4th review of #227) - Step 3 heading and an alt text still said "Webhooks tab"; it's a left-menu item. - testWebhook payloads are sample data (placeholder ids, evt_test_ event_id, a few differing fields) and the call blocks for all retries (~6 min) if the endpoint fails; say so. - X-TurboDocx-Delivery-Id is not the delivery id the API/Delivery History uses (replay takes the UUID id). - Webhook and Delivery Objects match the API: UUID ids, isActive / isDelivered returned as 1/0, plus metadata, createdBy and deliveryStats; availableEvents noted. - Delivery History: timestamps are per delivery, and any delivery can be replayed. Co-Authored-By: Claude Opus 5.5 * docs(sdks): bring the Ruby SDK back in the tabbed SDK docs (TurboDocx/SDK#45) The turbodocx-sdk gem is on RubyGems (0.9.0), so the Ruby pages hidden in July come back, in the current design: one tabbed page per product plus a setup page per language, the same way the other five languages were merged. - turbosign, deliverable, quote, webhooks: a Ruby tab (after Java) in every language tab group, from the old Ruby pages, with shared text kept outside the tabs. Ruby-only sections (file upload by path or IO, Rails and Sinatra examples) get their own Ruby group. - Ruby text brought up to date with what the other languages got while it was hidden: conditional field metadata, the error-handling rewrite (one canonical error reference on the TurboSign page), the reminder/expiration and fileName request keys, and the wording fixes. Every Ruby call checked against the 0.9.0 gem. - ruby.md is now a setup page like python.md, listed under Install & configure. partner-ruby.md is unlisted like its siblings. - deliverable-ruby, quote-ruby and webhooks-ruby are folded into the tabs and 301 to ?language=ruby; old /docs/SDKs/ruby#section links hop to the TurboSign page. - Ruby rows and tabs on the SDKs overview; "not on RubyGems yet" notes removed. Co-Authored-By: Claude Opus 5.5 (1M context) * docs(sdks): link the Ruby TurboQuote runnable examples (TurboDocx/SDK#45) The JavaScript and Java tabs link their SDK's runnable quote examples; the Ruby SDK ships the same three (basic lifecycle, products, price books). Co-Authored-By: Claude Opus 5.5 (1M context) --------- Co-authored-by: Yacine Kahlerras Co-authored-by: Claude Opus 5.5 Co-authored-by: Amit Sharma --- docs/SDKs/deliverable-ruby.md | 535 ------------ docs/SDKs/deliverable.md | 483 ++++++++++- docs/SDKs/index.md | 62 +- docs/SDKs/partner-ruby.md | 39 +- docs/SDKs/quote-ruby.md | 985 ---------------------- docs/SDKs/quote.md | 991 ++++++++++++++++++++++- docs/SDKs/ruby.md | 678 +--------------- docs/SDKs/turbosign.md | 783 +++++++++++++++++- docs/SDKs/webhooks-ruby.md | 567 ------------- docs/SDKs/webhooks.md | 564 ++++++++++++- docs/TurboSign/Webhooks.md | 255 ++++-- docs/TurboSign/embedded-signing/index.md | 4 - sidebars.js | 5 + src/theme/Root.js | 4 +- static/_redirects | 9 + 15 files changed, 3094 insertions(+), 2870 deletions(-) delete mode 100644 docs/SDKs/deliverable-ruby.md delete mode 100644 docs/SDKs/quote-ruby.md delete mode 100644 docs/SDKs/webhooks-ruby.md diff --git a/docs/SDKs/deliverable-ruby.md b/docs/SDKs/deliverable-ruby.md deleted file mode 100644 index f208693f..00000000 --- a/docs/SDKs/deliverable-ruby.md +++ /dev/null @@ -1,535 +0,0 @@ ---- -# Hidden from the published site: the turbodocx-sdk gem is not on RubyGems yet. -# Remove `draft: true` when the gem is published (TurboDocx/SDK issue). -draft: true -title: Deliverable Ruby SDK -sidebar_position: 13 -sidebar_label: "Deliverable: Ruby" -description: Official TurboDocx Deliverable Ruby SDK. Simple synchronous API for document generation from templates. -keywords: - - turbodocx deliverable ruby - - document generation ruby - - template api ruby - - deliverable sdk ruby - - rails document generation - - gem turbodocx ---- - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; -import QuickstartSkillNudge from '@site/src/components/QuickstartSkillNudge'; - -# Deliverable Ruby SDK - - - -The official TurboDocx Deliverable SDK for Ruby applications. Generate documents from templates with dynamic variable injection, download source files and PDFs, and manage deliverables programmatically with a simple synchronous API and comprehensive error handling. Available on RubyGems as `turbodocx-sdk`. - -## Installation - - - - -```bash -gem install turbodocx-sdk -``` - - - - -Add to your `Gemfile`: - -```ruby -gem "turbodocx-sdk" -``` - -Then run: - -```bash -bundle install -``` - - - - -## Requirements - -- Ruby 2.7+ -- No runtime dependencies (uses the standard library's `net/http`) - ---- - -## Configuration - -```ruby -require "turbodocx_sdk" - -# Configure globally (recommended) -TurboDocxSdk::Deliverable.configure( - api_key: ENV["TURBODOCX_API_KEY"], # Required: Your TurboDocx API key - org_id: ENV["TURBODOCX_ORG_ID"] # Required: Your organization ID - # base_url: "https://api.turbodocx.com" # Optional: Override base URL -) -``` - -:::tip No Sender Email Required -Unlike TurboSign, the Deliverable module only requires `api_key` and `org_id` — no sender email or name is needed. -::: - -### Environment Variables - -```bash -# .env -TURBODOCX_API_KEY=your_api_key_here -TURBODOCX_ORG_ID=your_org_id_here -``` - -:::caution API Credentials Required -Both `api_key` and `org_id` parameters are **required** for all API requests. To get your credentials, follow the **[Get Your Credentials](/docs/SDKs#1-get-your-credentials)** steps from the SDKs main page. -::: - ---- - -## Quick Start - -### Generate a document from a template - -```ruby -require "turbodocx_sdk" - -TurboDocxSdk::Deliverable.configure( - api_key: ENV["TURBODOCX_API_KEY"], - org_id: ENV["TURBODOCX_ORG_ID"] -) - -# Generate a document from a template with variables -# Request-hash keys are camelCase — the SDK forwards them to the API verbatim -result = TurboDocxSdk::Deliverable.generate_deliverable( - "name" => "Q1 Report", - "templateId" => "your-template-id", - "variables" => [ - { "placeholder" => "{CompanyName}", "text" => "Acme Corporation", "mimeType" => "text" }, - { "placeholder" => "{Date}", "text" => "2026-03-12", "mimeType" => "text" } - ], - "description" => "Quarterly business report", - "tags" => ["reports", "quarterly"] -) - -puts JSON.pretty_generate(result) -``` - -### Download and manage deliverables - -```ruby -require "turbodocx_sdk" - -TurboDocxSdk::Deliverable.configure( - api_key: ENV["TURBODOCX_API_KEY"], - org_id: ENV["TURBODOCX_ORG_ID"] -) - -# List deliverables with pagination -items = TurboDocxSdk::Deliverable.list_deliverables(limit: 10, show_tags: true) -puts "Total: #{items['totalRecords']}" - -# Get deliverable details -details = TurboDocxSdk::Deliverable.get_deliverable_details("deliverable-uuid") -puts "Name: #{details['name']}" - -# Download source file (DOCX/PPTX) -source_bytes = TurboDocxSdk::Deliverable.download_source_file("deliverable-uuid") -File.binwrite("report.docx", source_bytes) - -# Download PDF -pdf_bytes = TurboDocxSdk::Deliverable.download_pdf("deliverable-uuid") -File.binwrite("report.pdf", pdf_bytes) - -# Update deliverable -TurboDocxSdk::Deliverable.update_deliverable_info( - "deliverable-uuid", - "name" => "Q1 Report - Final", - "description" => "Final quarterly business report" -) - -# Delete deliverable -TurboDocxSdk::Deliverable.delete_deliverable("deliverable-uuid") -``` - ---- - -## Variable Types - -The Deliverable module supports four variable types for template injection: - -### 1. Text Variables - -Inject plain text values into template placeholders: - -```ruby -variables = [ - { "placeholder" => "{CompanyName}", "text" => "Acme Corporation", "mimeType" => "text" }, - { "placeholder" => "{Date}", "text" => "2026-03-12", "mimeType" => "text" } -] -``` - -### 2. HTML Variables - -Inject rich HTML content with formatting: - -```ruby -variables = [ - { - "placeholder" => "{Summary}", - "text" => "

This is a formatted summary with rich text.

", - "mimeType" => "html" - } -] -``` - -### 3. Image Variables - -Inject images by providing a URL or base64-encoded content: - -```ruby -variables = [ - { - "placeholder" => "{Logo}", - "text" => "https://example.com/logo.png", - "mimeType" => "image" - } -] -``` - -### 4. Markdown Variables - -Inject markdown content that gets converted to formatted text: - -```ruby -variables = [ - { - "placeholder" => "{Notes}", - "text" => "## Key Points\n- First item\n- Second item\n\n**Important:** Review before submission.", - "mimeType" => "markdown" - } -] -``` - -:::info Variable Stack -For repeating content (e.g., table rows), use `variableStack` instead of `text` to provide multiple values for the same placeholder. See the [Types section](#createdeliverablerequest) for details. -::: - ---- - -## API Reference - -:::note Runnable snippets -The snippets below assume you have already called `TurboDocxSdk::Deliverable.configure(...)` and added `require "turbodocx_sdk"` (plus `require "json"` if the snippet calls `JSON.pretty_generate`), as shown in [Quick Start](#quick-start). All methods are synchronous. -::: - -### Configure - -Configure the SDK with your API credentials and organization settings. - -```ruby -TurboDocxSdk::Deliverable.configure( - api_key: nil, # API key (or use access_token) - access_token: nil, # OAuth2 access token (alternative to api_key) - org_id: nil, # Required: Your organization ID - base_url: "https://api.turbodocx.com" # Optional: API base URL -) -``` - -:::caution API Credentials Required -All keyword arguments are optional and fall back to environment variables. Either `api_key` or `access_token` must be provided for authentication, and `org_id` is **required** for all Deliverable operations (enforced at runtime). To get your credentials, follow the **[Get Your Credentials](/docs/SDKs#1-get-your-credentials)** steps from the SDKs main page. -::: - -### Generate deliverable - -Generate a new document from a template with variable substitution. - -```ruby -result = TurboDocxSdk::Deliverable.generate_deliverable( - "name" => "Q1 Report", - "templateId" => "your-template-id", - "variables" => [ - { "placeholder" => "{CompanyName}", "text" => "Acme Corp", "mimeType" => "text" }, - { "placeholder" => "{Date}", "text" => "2026-03-12", "mimeType" => "text" } - ], - "description" => "Quarterly business report", - "tags" => ["reports", "quarterly"] -) - -puts JSON.pretty_generate(result) -``` - -### List deliverables - -List deliverables with pagination, search, and filtering. - -```ruby -items = TurboDocxSdk::Deliverable.list_deliverables( - limit: 10, - offset: 0, - query: "report", - show_tags: true -) - -puts JSON.pretty_generate(items) -``` - -### Get deliverable details - -Retrieve the full details of a single deliverable, including variables and fonts. - -```ruby -details = TurboDocxSdk::Deliverable.get_deliverable_details("deliverable-uuid", show_tags: true) - -puts JSON.pretty_generate(details) -``` - -### Update deliverable info - -Update a deliverable's name, description, or tags. - -```ruby -result = TurboDocxSdk::Deliverable.update_deliverable_info( - "deliverable-uuid", - "name" => "Q1 Report - Final", - "description" => "Final quarterly business report", - "tags" => ["reports", "final"] -) - -puts JSON.pretty_generate(result) -``` - -### Delete deliverable - -Soft-delete a deliverable. - -```ruby -result = TurboDocxSdk::Deliverable.delete_deliverable("deliverable-uuid") - -puts JSON.pretty_generate(result) -``` - -### Download source file - -Download the original source file (DOCX or PPTX). - -```ruby -source_bytes = TurboDocxSdk::Deliverable.download_source_file("deliverable-uuid") - -# Save to file -File.binwrite("report.docx", source_bytes) -``` - -### Download PDF - -Download the PDF version of a deliverable. - -```ruby -pdf_bytes = TurboDocxSdk::Deliverable.download_pdf("deliverable-uuid") - -# Save to file -File.binwrite("report.pdf", pdf_bytes) -``` - ---- - -## Error Handling - -The SDK provides typed error classes for different failure scenarios. All errors extend the base `TurboDocxSdk::TurboDocxError` class. - -### Error Classes - -| Error Class | Status Code | Description | -| --------------------- | ----------- | ----------------------------------- | -| `TurboDocxError` | varies | Base error class for all SDK errors | -| `AuthenticationError` | 401 | Invalid or missing API credentials | -| `AuthorizationError` | 403 | Authenticated but lacks required permissions | -| `ValidationError` | 400 | Invalid request parameters | -| `NotFoundError` | 404 | Deliverable or template not found | -| `ConflictError` | 409 | Request conflicts with current resource state | -| `RateLimitError` | 429 | Too many requests | -| `NetworkError` | - | Network connectivity issues | - -### Handling Errors - -```ruby -require "turbodocx_sdk" - -begin - result = TurboDocxSdk::Deliverable.generate_deliverable( - "name" => "Q1 Report", - "templateId" => "your-template-id", - "variables" => [ - { "placeholder" => "{CompanyName}", "text" => "Acme Corp", "mimeType" => "text" } - ] - ) -rescue TurboDocxSdk::AuthenticationError => e - puts "Authentication failed: #{e.message}" - # Check your API key and org ID -rescue TurboDocxSdk::AuthorizationError => e - puts "Not authorized: #{e.message}" - # Authenticated, but lacks permission for this operation -rescue TurboDocxSdk::ValidationError => e - puts "Validation error: #{e.message}" - # Check request parameters -rescue TurboDocxSdk::NotFoundError => e - puts "Resource not found: #{e.message}" - # Template or deliverable doesn't exist -rescue TurboDocxSdk::ConflictError => e - puts "Conflict: #{e.message}" - # Request conflicts with the current resource state -rescue TurboDocxSdk::RateLimitError => e - puts "Rate limited: #{e.message}" - # Wait and retry -rescue TurboDocxSdk::NetworkError => e - puts "Network error: #{e.message}" - # Check connectivity -rescue TurboDocxSdk::TurboDocxError => e - puts "SDK error: #{e.message}, status_code=#{e.status_code}, code=#{e.code}" -end -``` - -### Error Properties - -All errors include these properties: - -| Property | Type | Description | -| ------------- | ---------------- | ------------------------------------ | -| `message` | `String` | Human-readable error description | -| `status_code` | `Integer \| nil` | HTTP status code (if applicable) | -| `code` | `String \| nil` | Machine-readable error code | - ---- - -## Ruby Request Hashes - -The SDK uses plain Ruby `Hash` objects for flexible JSON-like structures. Request-body keys stay **camelCase** (the SDK forwards them verbatim); only the method keyword arguments (`api_key:`, `show_tags:`, …) are snake_case. - -### DeliverableVariable - -Variable configuration for template injection: - -  - -| Property | Type | Required | Description | -| ------------------------ | ----------------- | -------- | ---------------------------------------------------- | -| `placeholder` | `String` | Yes | Template placeholder (e.g., `{CompanyName}`) | -| `text` | `String` | No\* | Value to inject | -| `mimeType` | `String` | Yes | `"text"`, `"html"`, `"image"`, or `"markdown"` | -| `isDisabled` | `Boolean` | No | Skip this variable during generation | -| `subvariables` | `Array` | No | Nested sub-variables for HTML content | -| `variableStack` | `Hash \| Array` | No | Multiple instances for repeating content | -| `aiPrompt` | `String` | No | AI prompt for content generation (max 16,000 chars) | - -\*Required unless `variableStack` is provided or `isDisabled` is true. - -### CreateDeliverableRequest - -Request hash for `generate_deliverable`: - -  - -| Property | Type | Required | Description | -| --------------- | --------------- | -------- | ------------------------------------------ | -| `name` | `String` | Yes | Deliverable name (3-255 characters) | -| `templateId` | `String` | Yes | Template ID to generate from | -| `variables` | `Array` | Yes | Variables for template substitution | -| `description` | `String` | No | Description (up to 65,535 characters) | -| `tags` | `Array` | No | Tag strings to associate | - -### UpdateDeliverableRequest - -Request hash for `update_deliverable_info`: - -  - -| Property | Type | Required | Description | -| ------------- | --------------- | -------- | ---------------------------------------- | -| `name` | `String` | No | Updated name (3-255 characters) | -| `description` | `String` | No | Updated description | -| `tags` | `Array` | No | Replace all tags (empty array to remove) | - -### ListDeliverablesOptions - -Options hash for `list_deliverables` (these are query parameters — `show_tags` is accepted as snake_case or camelCase and sent as `showTags`): - -  - -| Property | Type | Required | Description | -| --------------- | --------- | -------- | ------------------------------------ | -| `limit` | `Integer` | No | Results per page (1-100, default 6) | -| `offset` | `Integer` | No | Results to skip (default 0) | -| `query` | `String` | No | Search query to filter by name | -| `show_tags` | `Boolean` | No | Include tags in the response | - -### DeliverableRecord - -The deliverable hash returned by `list_deliverables`: - -  - -| Property | Type | Description | -| ----------------- | --------- | ------------------------------------- | -| `id` | `String` | Unique deliverable ID (UUID) | -| `name` | `String` | Deliverable name | -| `description` | `String` | Description text | -| `templateId` | `String` | Source template ID | -| `createdBy` | `String` | User ID of the creator | -| `email` | `String` | Creator's email address | -| `fileSize` | `Integer` | File size in bytes | -| `fileType` | `String` | MIME type of the generated file | -| `defaultFont` | `String` | Default font used | -| `fonts` | `Array` | Fonts used in the document | -| `isActive` | `Boolean` | Whether the deliverable is active | -| `createdOn` | `String` | ISO 8601 creation timestamp | -| `updatedOn` | `String` | ISO 8601 last update timestamp | -| `tags` | `Array` | Associated tags (when `show_tags: true`) | - -### DeliverableDetailRecord - -The deliverable hash returned by `get_deliverable_details`. Includes all fields from [DeliverableRecord](#deliverablerecord) **except `fileSize`**, plus: - -  - -| Property | Type | Description | -| -------------------- | ------------- | ---------------------------------------- | -| `templateName` | `String` | Source template name | -| `templateNotDeleted` | `Boolean` | Whether the source template still exists | -| `variables` | `Array` | Parsed variable objects with values | - -### Tag - -Tag object included when `show_tags` is enabled. Each tag is a `Hash` with: - -| Key | Type | Description | -| ----------- | --------- | ------------------------------------ | -| `id` | `String` | Tag unique identifier (UUID) | -| `label` | `String` | Tag display name | -| `isActive` | `Boolean` | Whether the tag is active | -| `updatedOn` | `String` | ISO 8601 last update timestamp | -| `createdOn` | `String` | ISO 8601 creation timestamp | -| `createdBy` | `String` | User ID of the tag creator | -| `orgId` | `String` | Organization ID | - ---- - -## Additional Documentation - -For detailed information about advanced configuration and API concepts, see: - -### Core API References - -- **[TurboDocx Templating](/docs/TurboDocx-Templating/How-to-Create-a-Template)** - How to create and configure document templates -- **[Variable Reference](/docs/API/Deliverable-API#variable-object-structure)** - Complete guide to variable types, formatting, and advanced injection options -- **[API Reference](/docs/API/Deliverable-API)** - Full REST API documentation for Deliverable endpoints - ---- - -## Resources - -- [GitHub Repository](https://github.com/TurboDocx/SDK/tree/main/packages/ruby-sdk) -- [RubyGems Package](https://rubygems.org/gems/turbodocx-sdk) -- [API Reference](/docs/API/Deliverable-API) diff --git a/docs/SDKs/deliverable.md b/docs/SDKs/deliverable.md index ae988101..d8c2d4dd 100644 --- a/docs/SDKs/deliverable.md +++ b/docs/SDKs/deliverable.md @@ -2,7 +2,7 @@ title: Deliverable SDK sidebar_position: 8 sidebar_label: Deliverable -description: 'Deliverable SDK for JavaScript, TypeScript, Python, PHP, Go and Java: generate, list, update and download documents from templates.' +description: 'Deliverable SDK for JavaScript, TypeScript, Python, PHP, Go, Java and Ruby: generate, list, update and download documents from templates.' keywords: - turbodocx deliverable javascript - turbodocx deliverable typescript @@ -36,6 +36,18 @@ keywords: - maven turbodocx - gradle turbodocx - java sdk + +- turbodocx deliverable ruby + +- document generation ruby + +- template api ruby + +- deliverable sdk ruby + +- rails document generation + +- gem turbodocx --- import Tabs from '@theme/Tabs'; @@ -71,6 +83,11 @@ The official TurboDocx Deliverable SDK for Go applications. Generate documents f The official TurboDocx Deliverable SDK for Java applications. Generate documents from templates with dynamic variable injection, download source files and PDFs, and manage deliverables programmatically with the Builder pattern, comprehensive error handling, and type-safe APIs. Available on Maven Central as `com.turbodocx:turbodocx-sdk`. + + + +The official TurboDocx Deliverable SDK for Ruby applications. Generate documents from templates with dynamic variable injection, download source files and PDFs, and manage deliverables programmatically with a simple synchronous API and comprehensive error handling. Available on RubyGems as `turbodocx-sdk`. + @@ -177,6 +194,34 @@ implementation 'com.turbodocx:turbodocx-sdk:0.7.0' + + + + + + +```bash +gem install turbodocx-sdk +``` + + + + +Add to your `Gemfile`: + +```ruby +gem "turbodocx-sdk" +``` + +Then run: + +```bash +bundle install +``` + + + + @@ -218,6 +263,12 @@ This SDK leverages PHP 8.1+ features including enums, named parameters, readonly - OkHttp 4.x (included) - Gson 2.x (included) + + + +- Ruby 2.7+ +- No runtime dependencies (uses the standard library's `net/http`) + @@ -412,6 +463,24 @@ public class Main { Use `buildDeliverableClient()` when you only need document generation: it skips the `senderEmail` validation required by TurboSign. ::: + + + +```ruby +require "turbodocx_sdk" + +# Configure globally (recommended) +TurboDocxSdk::Deliverable.configure( + api_key: ENV["TURBODOCX_API_KEY"], # Required: Your TurboDocx API key + org_id: ENV["TURBODOCX_ORG_ID"] # Required: Your organization ID + # base_url: "https://api.turbodocx.com" # Optional: Override base URL +) +``` + +:::tip No Sender Email Required +Unlike TurboSign, the Deliverable module only requires `api_key` and `org_id`: no sender email or name is needed. +::: + @@ -472,6 +541,19 @@ export TURBODOCX_ORG_ID=your_org_id_here Both `apiKey` and `orgId` parameters are **required** for all API requests. To get your credentials, follow the **[Get Your Credentials](/docs/SDKs#1-get-your-credentials)** steps from the SDKs main page. ::: + + + +```bash +# .env +TURBODOCX_API_KEY=your_api_key_here +TURBODOCX_ORG_ID=your_org_id_here +``` + +:::caution API Credentials Required +Both `api_key` and `org_id` parameters are **required** for all API requests. To get your credentials, follow the **[Get Your Credentials](/docs/SDKs#1-get-your-credentials)** steps from the SDKs main page. +::: + @@ -693,6 +775,33 @@ public class Main { } ``` + + + +```ruby +require "turbodocx_sdk" + +TurboDocxSdk::Deliverable.configure( + api_key: ENV["TURBODOCX_API_KEY"], + org_id: ENV["TURBODOCX_ORG_ID"] +) + +# Generate a document from a template with variables +# Request-hash keys are camelCase — the SDK forwards them to the API verbatim +result = TurboDocxSdk::Deliverable.generate_deliverable( + "name" => "Q1 Report", + "templateId" => "your-template-id", + "variables" => [ + { "placeholder" => "{CompanyName}", "text" => "Acme Corporation", "mimeType" => "text" }, + { "placeholder" => "{Date}", "text" => "2026-03-12", "mimeType" => "text" } + ], + "description" => "Quarterly business report", + "tags" => ["reports", "quarterly"] +) + +puts JSON.pretty_generate(result) +``` + @@ -988,6 +1097,44 @@ public class Main { } ``` + + + +```ruby +require "turbodocx_sdk" + +TurboDocxSdk::Deliverable.configure( + api_key: ENV["TURBODOCX_API_KEY"], + org_id: ENV["TURBODOCX_ORG_ID"] +) + +# List deliverables with pagination +items = TurboDocxSdk::Deliverable.list_deliverables(limit: 10, show_tags: true) +puts "Total: #{items['totalRecords']}" + +# Get deliverable details +details = TurboDocxSdk::Deliverable.get_deliverable_details("deliverable-uuid") +puts "Name: #{details['name']}" + +# Download source file (DOCX/PPTX) +source_bytes = TurboDocxSdk::Deliverable.download_source_file("deliverable-uuid") +File.binwrite("report.docx", source_bytes) + +# Download PDF +pdf_bytes = TurboDocxSdk::Deliverable.download_pdf("deliverable-uuid") +File.binwrite("report.pdf", pdf_bytes) + +# Update deliverable +TurboDocxSdk::Deliverable.update_deliverable_info( + "deliverable-uuid", + "name" => "Q1 Report - Final", + "description" => "Final quarterly business report" +) + +# Delete deliverable +TurboDocxSdk::Deliverable.delete_deliverable("deliverable-uuid") +``` + @@ -1067,6 +1214,16 @@ var.setText("Acme Corporation"); var.setMimeType("text"); ``` + + + +```ruby +variables = [ + { "placeholder" => "{CompanyName}", "text" => "Acme Corporation", "mimeType" => "text" }, + { "placeholder" => "{Date}", "text" => "2026-03-12", "mimeType" => "text" } +] +``` + @@ -1136,6 +1293,19 @@ var.setText("

This is a formatted summary with rich text< var.setMimeType("html"); ``` + + + +```ruby +variables = [ + { + "placeholder" => "{Summary}", + "text" => "

This is a formatted summary with rich text.

", + "mimeType" => "html" + } +] +``` + @@ -1205,6 +1375,19 @@ var.setText("https://example.com/logo.png"); var.setMimeType("image"); ``` + + + +```ruby +variables = [ + { + "placeholder" => "{Logo}", + "text" => "https://example.com/logo.png", + "mimeType" => "image" + } +] +``` + @@ -1294,6 +1477,23 @@ var.setMimeType("markdown"); For repeating content (e.g., table rows), use `setVariableStack()` instead of `setText()` to provide multiple values for the same placeholder. See the [Types section](#createdeliverablerequest) for details. ::: + + + +```ruby +variables = [ + { + "placeholder" => "{Notes}", + "text" => "## Key Points\n- First item\n- Second item\n\n**Important:** Review before submission.", + "mimeType" => "markdown" + } +] +``` + +:::info Variable Stack +For repeating content (e.g., table rows), use `variableStack` instead of `text` to provide multiple values for the same placeholder. See the [Types section](#createdeliverablerequest) for details. +::: + @@ -1308,6 +1508,13 @@ For repeating content (e.g., table rows), use `setVariableStack()` instead of `s The snippets below are partial and run inside an `async` function. They assume you have already called `Deliverable.configure(...)` and that `asyncio` and `json` are imported (`import asyncio, json`). For a complete runnable script, wrap the calls in `async def main(): ...` and run with `asyncio.run(main())`, as shown in [Quick Start](#quick-start). ::: + + + +:::note Runnable snippets +The snippets below assume you have already called `TurboDocxSdk::Deliverable.configure(...)` and added `require "turbodocx_sdk"` (plus `require "json"` if the snippet calls `JSON.pretty_generate`), as shown in [Quick Start](#quick-start). All methods are synchronous. +::: + @@ -1459,6 +1666,24 @@ DeliverableClient deliverable = new TurboDocxClient.Builder() `DeliverableClient` also has a public constructor, `new DeliverableClient(HttpClient)`, if you already hold a configured `HttpClient` and want the deliverable module to reuse it. Most applications should use the builder instead. ::: + + + +Configure the SDK with your API credentials and organization settings. + +```ruby +TurboDocxSdk::Deliverable.configure( + api_key: nil, # API key (or use access_token) + access_token: nil, # OAuth2 access token (alternative to api_key) + org_id: nil, # Required: Your organization ID + base_url: "https://api.turbodocx.com" # Optional: API base URL +) +``` + +:::caution API Credentials Required +All keyword arguments are optional and fall back to environment variables. Either `api_key` or `access_token` must be provided for authentication, and `org_id` is **required** for all Deliverable operations (enforced at runtime). To get your credentials, follow the **[Get Your Credentials](/docs/SDKs#1-get-your-credentials)** steps from the SDKs main page. +::: + @@ -1586,6 +1811,24 @@ CreateDeliverableResponse result = deliverable.generateDeliverable(request); System.out.println("Result: " + gson.toJson(result)); ``` + + + +```ruby +result = TurboDocxSdk::Deliverable.generate_deliverable( + "name" => "Q1 Report", + "templateId" => "your-template-id", + "variables" => [ + { "placeholder" => "{CompanyName}", "text" => "Acme Corp", "mimeType" => "text" }, + { "placeholder" => "{Date}", "text" => "2026-03-12", "mimeType" => "text" } + ], + "description" => "Quarterly business report", + "tags" => ["reports", "quarterly"] +) + +puts JSON.pretty_generate(result) +``` + @@ -1690,6 +1933,20 @@ DeliverableListResponse list = deliverable.listDeliverables(request); System.out.println("Result: " + gson.toJson(list)); ``` + + + +```ruby +items = TurboDocxSdk::Deliverable.list_deliverables( + limit: 10, + offset: 0, + query: "report", + show_tags: true +) + +puts JSON.pretty_generate(items) +``` + @@ -1768,6 +2025,15 @@ DeliverableRecord details = deliverable.getDeliverableDetails("deliverable-uuid" System.out.println("Result: " + gson.toJson(details)); ``` + + + +```ruby +details = TurboDocxSdk::Deliverable.get_deliverable_details("deliverable-uuid", show_tags: true) + +puts JSON.pretty_generate(details) +``` + @@ -1864,6 +2130,20 @@ UpdateDeliverableResponse result = deliverable.updateDeliverableInfo("deliverabl System.out.println("Result: " + gson.toJson(result)); ``` + + + +```ruby +result = TurboDocxSdk::Deliverable.update_deliverable_info( + "deliverable-uuid", + "name" => "Q1 Report - Final", + "description" => "Final quarterly business report", + "tags" => ["reports", "final"] +) + +puts JSON.pretty_generate(result) +``` + @@ -1935,6 +2215,15 @@ DeleteDeliverableResponse result = deliverable.deleteDeliverable("deliverable-uu System.out.println("Result: " + gson.toJson(result)); ``` + + + +```ruby +result = TurboDocxSdk::Deliverable.delete_deliverable("deliverable-uuid") + +puts JSON.pretty_generate(result) +``` + @@ -2022,6 +2311,16 @@ byte[] sourceData = deliverable.downloadSourceFile("deliverable-uuid"); Files.write(Paths.get("report.docx"), sourceData); ``` + + + +```ruby +source_bytes = TurboDocxSdk::Deliverable.download_source_file("deliverable-uuid") + +# Save to file +File.binwrite("report.docx", source_bytes) +``` + @@ -2109,6 +2408,16 @@ byte[] pdfData = deliverable.downloadPDF("deliverable-uuid"); Files.write(Paths.get("report.pdf"), pdfData); ``` + + + +```ruby +pdf_bytes = TurboDocxSdk::Deliverable.download_pdf("deliverable-uuid") + +# Save to file +File.binwrite("report.pdf", pdf_bytes) +``` + @@ -2141,6 +2450,11 @@ Files.write(Paths.get("report.pdf"), pdfData); `deliverable.generateDeliverable()` throws `TurboDocxException.NotFoundException` when `templateId` doesn't match a template in the org, and `TurboDocxException.ValidationException` when a variable in the request is missing a required field: + + + +`TurboDocxSdk::Deliverable.generate_deliverable` raises `NotFoundError` when `templateId` doesn't match a template in the org, and `ValidationError` for invalid request parameters, most commonly a variable hash missing `text` (required unless it sets `variableStack` or `isDisabled: true`) or specifying an unsupported `mimeType`. Both extend the base `TurboDocxSdk::TurboDocxError`: + @@ -2425,6 +2739,48 @@ try { The full typed-exception table (`AuthenticationException`, `AuthorizationException`, `ConflictException`, `RateLimitException`, `NetworkException`, HTTP status mapping) and the `getMessage()`/`getStatusCode()`/`getCode()` methods shared by every exception are documented once in the [Java SDK's Error Handling reference](/docs/SDKs/turbosign?language=java#error-handling). + + + +```ruby +require "turbodocx_sdk" + +begin + result = TurboDocxSdk::Deliverable.generate_deliverable( + "name" => "Q1 Report", + "templateId" => "your-template-id", + "variables" => [ + { "placeholder" => "{CompanyName}", "text" => "Acme Corp", "mimeType" => "text" } + ] + ) +rescue TurboDocxSdk::AuthenticationError => e + puts "Authentication failed: #{e.message}" + # Check your API key and org ID +rescue TurboDocxSdk::AuthorizationError => e + puts "Not authorized: #{e.message}" + # Authenticated, but lacks permission for this operation +rescue TurboDocxSdk::ValidationError => e + puts "Validation error: #{e.message}" + # Check request parameters +rescue TurboDocxSdk::NotFoundError => e + puts "Resource not found: #{e.message}" + # Template or deliverable doesn't exist +rescue TurboDocxSdk::ConflictError => e + puts "Conflict: #{e.message}" + # Request conflicts with the current resource state +rescue TurboDocxSdk::RateLimitError => e + puts "Rate limited: #{e.message}" + # Wait and retry +rescue TurboDocxSdk::NetworkError => e + puts "Network error: #{e.message}" + # Check connectivity +rescue TurboDocxSdk::TurboDocxError => e + puts "SDK error: #{e.message}, status_code=#{e.status_code}, code=#{e.code}" +end +``` + +The full typed-error table (`AuthenticationError`, `AuthorizationError`, `ConflictError`, `RateLimitError`, `NetworkError`, HTTP status mapping) and the `message`/`status_code`/`code` attributes shared by every error are documented once in the [Ruby SDK's Error Handling reference](/docs/SDKs/turbosign?language=ruby#error-handling). + @@ -2446,6 +2802,11 @@ The SDK exports TypeScript types for full type safety. Import them directly from The SDK uses Python type hints with `Dict[str, Any]` for flexible JSON-like structures. + + + +The SDK uses plain Ruby `Hash` objects for flexible JSON-like structures. Request-body keys stay **camelCase** (the SDK forwards them verbatim); only the method keyword arguments (`api_key:`, `show_tags:`, …) are snake_case. + @@ -2611,6 +2972,25 @@ Variable configuration for template injection: \*Required unless `variableStack` is provided or `isDisabled` is true. + + + +Variable configuration for template injection: + +  + +| Property | Type | Required | Description | +| ------------------------ | ----------------- | -------- | ---------------------------------------------------- | +| `placeholder` | `String` | Yes | Template placeholder (e.g., `{CompanyName}`) | +| `text` | `String` | No\* | Value to inject | +| `mimeType` | `String` | Yes | `"text"`, `"html"`, `"image"`, or `"markdown"` | +| `isDisabled` | `Boolean` | No | Skip this variable during generation | +| `subvariables` | `Array` | No | Nested sub-variables for HTML content | +| `variableStack` | `Hash \| Array` | No | Multiple instances for repeating content | +| `aiPrompt` | `String` | No | AI prompt for content generation (max 16,000 chars) | + +\*Required unless `variableStack` is provided or `isDisabled` is true. + @@ -2685,6 +3065,21 @@ Request configuration for `generateDeliverable`: | `description` | `String` | No | Description (up to 65,535 characters) | | `tags` | `List` | No | Tag strings to associate | + + + +Request hash for `generate_deliverable`: + +  + +| Property | Type | Required | Description | +| --------------- | --------------- | -------- | ------------------------------------------ | +| `name` | `String` | Yes | Deliverable name (3-255 characters) | +| `templateId` | `String` | Yes | Template ID to generate from | +| `variables` | `Array` | Yes | Variables for template substitution | +| `description` | `String` | No | Description (up to 65,535 characters) | +| `tags` | `Array` | No | Tag strings to associate | + @@ -2749,6 +3144,19 @@ Request configuration for `updateDeliverableInfo`: | `description` | `String` | No | Updated description | | `tags` | `List` | No | Replace all tags (empty list to remove) | + + + +Request hash for `update_deliverable_info`: + +  + +| Property | Type | Required | Description | +| ------------- | --------------- | -------- | ---------------------------------------- | +| `name` | `String` | No | Updated name (3-255 characters) | +| `description` | `String` | No | Updated description | +| `tags` | `Array` | No | Replace all tags (empty array to remove) | + @@ -2821,6 +3229,20 @@ Options for `listDeliverables`: | `query` | `String` | No | Search query to filter by name | | `showTags` | `Boolean` | No | Include tags in the response | + + + +Options hash for `list_deliverables` (these are query parameters — `show_tags` is accepted as snake_case or camelCase and sent as `showTags`): + +  + +| Property | Type | Required | Description | +| --------------- | --------- | -------- | ------------------------------------ | +| `limit` | `Integer` | No | Results per page (1-100, default 6) | +| `offset` | `Integer` | No | Results to skip (default 0) | +| `query` | `String` | No | Search query to filter by name | +| `show_tags` | `Boolean` | No | Include tags in the response | + @@ -2950,6 +3372,30 @@ The deliverable object returned by both `listDeliverables` and `getDeliverableDe | `variables` | `List` | Parsed variable objects with values | | `tags` | `List` | Associated tags (when `showTags=true`) | + + + +The deliverable hash returned by `list_deliverables`: + +  + +| Property | Type | Description | +| ----------------- | --------- | ------------------------------------- | +| `id` | `String` | Unique deliverable ID (UUID) | +| `name` | `String` | Deliverable name | +| `description` | `String` | Description text | +| `templateId` | `String` | Source template ID | +| `createdBy` | `String` | User ID of the creator | +| `email` | `String` | Creator's email address | +| `fileSize` | `Integer` | File size in bytes | +| `fileType` | `String` | MIME type of the generated file | +| `defaultFont` | `String` | Default font used | +| `fonts` | `Array` | Fonts used in the document | +| `isActive` | `Boolean` | Whether the deliverable is active | +| `createdOn` | `String` | ISO 8601 creation timestamp | +| `updatedOn` | `String` | ISO 8601 last update timestamp | +| `tags` | `Array` | Associated tags (when `show_tags: true`) | + @@ -2981,6 +3427,19 @@ The deliverable record returned by `getDeliverableDetails`. Includes all fields | `templateNotDeleted` | `bool` | Whether the source template still exists | | `variables` | `array` | Parsed variable objects with values | + + + +The deliverable hash returned by `get_deliverable_details`. Includes all fields from [DeliverableRecord](#deliverablerecord) **except `fileSize`**, plus: + +  + +| Property | Type | Description | +| -------------------- | ------------- | ---------------------------------------- | +| `templateName` | `String` | Source template name | +| `templateNotDeleted` | `Boolean` | Whether the source template still exists | +| `variables` | `Array` | Parsed variable objects with values | + @@ -3063,6 +3522,21 @@ Tag object included when `showTags` is enabled: | `createdBy` | `String` | User ID of the tag creator | | `orgId` | `String` | Organization ID | + + + +Tag object included when `show_tags` is enabled. Each tag is a `Hash` with: + +| Key | Type | Description | +| ----------- | --------- | ------------------------------------ | +| `id` | `String` | Tag unique identifier (UUID) | +| `label` | `String` | Tag display name | +| `isActive` | `Boolean` | Whether the tag is active | +| `updatedOn` | `String` | ISO 8601 last update timestamp | +| `createdOn` | `String` | ISO 8601 creation timestamp | +| `createdBy` | `String` | User ID of the tag creator | +| `orgId` | `String` | Organization ID | + @@ -3117,5 +3591,12 @@ For detailed information about advanced configuration and API concepts, see: - [Maven Central](https://search.maven.org/artifact/com.turbodocx/turbodocx-sdk) - [API Reference](/docs/API/Deliverable-API) + + + +- [GitHub Repository](https://github.com/TurboDocx/SDK/tree/main/packages/ruby-sdk) +- [RubyGems Package](https://rubygems.org/gems/turbodocx-sdk) +- [API Reference](/docs/API/Deliverable-API) + diff --git a/docs/SDKs/index.md b/docs/SDKs/index.md index abff76ab..acd99a7a 100644 --- a/docs/SDKs/index.md +++ b/docs/SDKs/index.md @@ -2,7 +2,7 @@ title: SDKs Overview sidebar_position: 1 sidebar_label: Overview -description: Official TurboDocx SDKs for JavaScript, Python, PHP, Go, and Java. Get started with document generation, deliverables, digital signatures, and quoting. +description: Official TurboDocx SDKs for JavaScript, Python, PHP, Go, Java, and Ruby. Get started with document generation, deliverables, digital signatures, and quoting. keywords: - turbodocx sdk - turbosign sdk @@ -11,6 +11,7 @@ keywords: - php sdk - go sdk - java sdk + - ruby sdk - document api - esignature sdk - api client library @@ -55,6 +56,7 @@ Send documents for legally-binding eSignatures with full audit trails. | **PHP** | `turbodocx/sdk` | `composer require turbodocx/sdk` | [Docs](/docs/SDKs/turbosign?language=php) [GitHub](https://github.com/TurboDocx/SDK/tree/main/packages/php-sdk) | | **Go** | `github.com/TurboDocx/SDK/packages/go-sdk` | `go get github.com/TurboDocx/SDK/packages/go-sdk` | [Docs](/docs/SDKs/turbosign?language=go) [GitHub](https://github.com/TurboDocx/SDK/tree/main/packages/go-sdk) | | **Java** | `com.turbodocx:turbodocx-sdk` | [Maven Central](https://search.maven.org/artifact/com.turbodocx/turbodocx-sdk) | [Docs](/docs/SDKs/turbosign?language=java) [GitHub](https://github.com/TurboDocx/SDK/tree/main/packages/java-sdk) | +| **Ruby** | `turbodocx-sdk` | `gem install turbodocx-sdk` | [Docs](/docs/SDKs/turbosign?language=ruby) [GitHub](https://github.com/TurboDocx/SDK/tree/main/packages/ruby-sdk) | ## TurboWebhooks SDKs @@ -67,6 +69,7 @@ Subscribe to all 7 TurboSign signature events (`sent`, `viewed`, `recipient_sign | **Python** | `turbodocx-sdk` | `pip install turbodocx-sdk` | [Docs](/docs/SDKs/webhooks?language=python) [GitHub](https://github.com/TurboDocx/SDK/tree/main/packages/py-sdk) | | **Go** | `github.com/TurboDocx/SDK/packages/go-sdk` | `go get github.com/TurboDocx/SDK/packages/go-sdk` | [Docs](/docs/SDKs/webhooks?language=go) [GitHub](https://github.com/TurboDocx/SDK/tree/main/packages/go-sdk) | | **Java** | `com.turbodocx:turbodocx-sdk` | `mvn` / `gradle` (see [docs](/docs/SDKs/webhooks?language=java)) | [Docs](/docs/SDKs/webhooks?language=java) [GitHub](https://github.com/TurboDocx/SDK/tree/main/packages/java-sdk) | +| **Ruby** | `turbodocx-sdk` | `gem install turbodocx-sdk` | [Docs](/docs/SDKs/webhooks?language=ruby) [GitHub](https://github.com/TurboDocx/SDK/tree/main/packages/ruby-sdk) | For the conceptual overview (delivery retries, payload schema, dashboard configuration), see [TurboSign → Webhooks](/docs/TurboSign/Webhooks). @@ -81,6 +84,7 @@ Generate documents from templates with dynamic variable injection, download sour | **PHP** | `turbodocx/sdk` | `composer require turbodocx/sdk` | [Docs](/docs/SDKs/deliverable?language=php) [GitHub](https://github.com/TurboDocx/SDK/tree/main/packages/php-sdk) | | **Go** | `github.com/TurboDocx/SDK/packages/go-sdk` | `go get github.com/TurboDocx/SDK/packages/go-sdk` | [Docs](/docs/SDKs/deliverable?language=go) [GitHub](https://github.com/TurboDocx/SDK/tree/main/packages/go-sdk) | | **Java** | `com.turbodocx:turbodocx-sdk` | [Maven Central](https://search.maven.org/artifact/com.turbodocx/turbodocx-sdk) | [Docs](/docs/SDKs/deliverable?language=java) [GitHub](https://github.com/TurboDocx/SDK/tree/main/packages/java-sdk) | +| **Ruby** | `turbodocx-sdk` | `gem install turbodocx-sdk` | [Docs](/docs/SDKs/deliverable?language=ruby) [GitHub](https://github.com/TurboDocx/SDK/tree/main/packages/ruby-sdk) | ## TurboQuote SDKs @@ -93,6 +97,7 @@ Build sales quotes and proposals programmatically: quotes and line items, a prod | **PHP** | `turbodocx/sdk` | `composer require turbodocx/sdk` | [Docs](/docs/SDKs/quote?language=php) [GitHub](https://github.com/TurboDocx/SDK/tree/main/packages/php-sdk) | | **Go** | `github.com/TurboDocx/SDK/packages/go-sdk` | `go get github.com/TurboDocx/SDK/packages/go-sdk` | [Docs](/docs/SDKs/quote?language=go) [GitHub](https://github.com/TurboDocx/SDK/tree/main/packages/go-sdk) | | **Java** | `com.turbodocx:turbodocx-sdk` | [Maven Central](https://search.maven.org/artifact/com.turbodocx/turbodocx-sdk) | [Docs](/docs/SDKs/quote?language=java) [GitHub](https://github.com/TurboDocx/SDK/tree/main/packages/java-sdk) | +| **Ruby** | `turbodocx-sdk` | `gem install turbodocx-sdk` | [Docs](/docs/SDKs/quote?language=ruby) [GitHub](https://github.com/TurboDocx/SDK/tree/main/packages/ruby-sdk) | :::tip Low-code or No-code? Check out our [n8n community node](https://www.npmjs.com/package/@turbodocx/n8n-nodes-turbodocx) for workflow automation, or get [TurboDocx Writer](https://appsource.microsoft.com/en-us/product/office/WA200007397) for Microsoft Word. @@ -203,6 +208,15 @@ go get github.com/TurboDocx/SDK/packages/go-sdk ``` + + + +```bash +gem install turbodocx-sdk +# or add to your Gemfile: +# gem "turbodocx-sdk" +``` + @@ -438,6 +452,33 @@ public class Main { } ``` + + + +```ruby +require "turbodocx_sdk" + +# Configure with your API key +TurboDocxSdk::TurboSign.configure( + api_key: ENV["TURBODOCX_API_KEY"], + org_id: ENV["TURBODOCX_ORG_ID"], + sender_email: ENV["TURBODOCX_SENDER_EMAIL"] # required for TurboSign +) + +# Send a document for signature +result = TurboDocxSdk::TurboSign.send_signature( + fileLink: "https://www.turbodocx.com/examples/turbodocx.pdf", + recipients: [ + { name: "John Doe", email: "john@example.com", signingOrder: 1 } + ], + fields: [ + { type: "signature", page: 1, x: 100, y: 500, width: 200, height: 50, recipientEmail: "john@example.com" } + ] +) + +puts "Document sent! ID: #{result['documentId']}" +``` + @@ -662,6 +703,25 @@ try { } ``` + + + +```ruby +require "turbodocx_sdk" + +begin + result = TurboDocxSdk::TurboSign.send_signature( + # ... + ) +rescue TurboDocxSdk::ValidationError => e + puts "Validation error: #{e.message}" + # Handle validation error +rescue TurboDocxSdk::TurboDocxError => e + puts "Error #{e.code}: #{e.message}" + puts "Status code: #{e.status_code}" +end +``` + diff --git a/docs/SDKs/partner-ruby.md b/docs/SDKs/partner-ruby.md index 27e3c193..40713b95 100644 --- a/docs/SDKs/partner-ruby.md +++ b/docs/SDKs/partner-ruby.md @@ -1,8 +1,6 @@ --- -# Hidden from the published site: the turbodocx-sdk gem is not on RubyGems yet. -# Remove `draft: true` when the gem is published (TurboDocx/SDK issue). -draft: true title: TurboPartner Ruby SDK +unlisted: true sidebar_position: 13 sidebar_label: "TurboPartner: Ruby" description: Official TurboDocx Partner SDK for Ruby. Manage organizations, users, API keys, and entitlements programmatically from plain Ruby, Rails, or Sinatra. @@ -34,7 +32,7 @@ The official TurboDocx Partner SDK for Ruby applications. Build multi-tenant Saa
:::info What is TurboPartner? -TurboPartner is the partner management API for TurboDocx. It allows you to programmatically create and manage organizations, users, API keys, and feature entitlements — perfect for building white-label or multi-tenant applications on top of TurboDocx. +TurboPartner is the partner management API for TurboDocx. It allows you to programmatically create and manage organizations, users, API keys, and feature entitlements, perfect for building white-label or multi-tenant applications on top of TurboDocx. ::: ## TLDR @@ -71,7 +69,7 @@ key = TurboDocxSdk::TurboPartner.create_organization_api_key(org_id, "name" => "Production Key", "role" => "admin" ) -puts "API Key: #{key['data']['key']}" # Save this — only shown once! +puts "API Key: #{key['data']['key']}" # Save this, only shown once! ``` --- @@ -413,7 +411,7 @@ puts "Full Key: #{result['data']['key']}" # Only shown once! ``` :::caution Save Your API Key -The full API key is only returned once during creation. Store it securely — you won't be able to retrieve it again. +The full API key is only returned once during creation. Store it securely: you won't be able to retrieve it again. ::: ### `list_organization_api_keys(organization_id, request = nil)` @@ -525,11 +523,11 @@ result = TurboDocxSdk::TurboPartner.revoke_partner_api_key("partner-key-uuid-her ## Partner User Management :::danger Partner users use a different role enum -Partner portal users take `"admin"`, `"member"`, or `"viewer"`. **Organization** users and organization API keys take `"admin"`, `"contributor"`, `"user"`, or `"viewer"`. The two enums do not overlap beyond `admin`/`viewer` — `"member"` is rejected on an org call, and `"contributor"`/`"user"` are rejected on a partner call. See [Role Enums](#organization-user-roles). +Partner portal users take `"admin"`, `"member"`, or `"viewer"`. **Organization** users and organization API keys take `"admin"`, `"contributor"`, `"user"`, or `"viewer"`. The two enums do not overlap beyond `admin`/`viewer`: `"member"` is rejected on an org call, and `"contributor"`/`"user"` are rejected on a partner call. See [Role Enums](#organization-user-roles). ::: :::caution `permissions` is all-or-nothing -The `"permissions"` hash itself is optional on both `add_user_to_partner_portal` and `update_partner_user_permissions`, and the Ruby SDK forwards your hash verbatim without client-side validation. But if you send `"permissions"`, **all seven keys are required** — there is no partial permissions update. Omitting even one key raises `TurboDocxSdk::ValidationError` (400). Always send the complete hash: read the current values first and re-send them with your change applied. +The `"permissions"` hash itself is optional on both `add_user_to_partner_portal` and `update_partner_user_permissions`, and the Ruby SDK forwards your hash verbatim without client-side validation. But if you send `"permissions"`, **all seven keys are required**: there is no partial permissions update. Omitting even one key raises `TurboDocxSdk::ValidationError` (400). Always send the complete hash: read the current values first and re-send them with your change applied. ::: ### `add_user_to_partner_portal(request)` @@ -573,7 +571,7 @@ end ### `update_partner_user_permissions(user_id, request)` -Update a partner user's role and permissions. If you pass `"permissions"`, send **all seven keys** — a partial hash is a 400. +Update a partner user's role and permissions. If you pass `"permissions"`, send **all seven keys**: a partial hash is a 400. ```ruby result = TurboDocxSdk::TurboPartner.update_partner_user_permissions("partner-user-uuid-here", @@ -686,7 +684,7 @@ Pass features as a plain Hash with camelCase string keys. The SDK sends them str ### Tracking (Usage Counters) -Current consumption against the limits above. TurboDocx maintains these automatically, but `update_organization_entitlements` **accepts a `tracking` hash** — useful for seeding counters when migrating an existing customer: +Current consumption against the limits above. TurboDocx maintains these automatically, but `update_organization_entitlements` **accepts a `tracking` hash**, useful for seeding counters when migrating an existing customer: | Field | Type | Description | |-------|------|-------------| @@ -705,7 +703,7 @@ Every counter except `currentAICredits` floors at `0`. Only `currentAICredits` a ## Preferences Reference -TurboSign display preferences you can read and set per organization. Every key is a boolean and is validated strictly — the strings `"true"` / `"false"` are rejected with a 400, so pass real booleans. The API returns only these keys and never any of the organization's other settings. +TurboSign display preferences you can read and set per organization. Every key is a boolean and is validated strictly: the strings `"true"` / `"false"` are rejected with a 400, so pass real booleans. The API returns only these keys and never any of the organization's other settings. | Field | Type | Default | Description | |-------|------|---------|-------------| @@ -812,6 +810,8 @@ permissions = { ## Error Handling +`TurboDocxSdk::TurboPartner.create_organization` and the other partner calls raise `AuthorizationError` when the partner API key lacks the scope for the route, since partner keys are scoped separately from organization keys: + ```ruby begin result = TurboDocxSdk::TurboPartner.create_organization("name" => "Acme Corp") @@ -842,20 +842,7 @@ rescue TurboDocxSdk::TurboDocxError => e end ``` -All errors inherit from `TurboDocxSdk::TurboDocxError` and carry `status_code` and `code` readers. - -### Error Classes - -| Error Class | Status | When | -|---|---|---| -| `TurboDocxSdk::TurboDocxError` | varies | Base class for all SDK errors | -| `TurboDocxSdk::AuthenticationError` | 401 | Invalid or missing partner credentials | -| `TurboDocxSdk::AuthorizationError` | 403 | Valid credentials without permission for this operation | -| `TurboDocxSdk::ValidationError` | 400 | Invalid request parameters, or TurboPartner not configured | -| `TurboDocxSdk::NotFoundError` | 404 | Resource not found | -| `TurboDocxSdk::ConflictError` | 409 | Request conflicts with current resource state | -| `TurboDocxSdk::RateLimitError` | 429 | Too many requests — back off | -| `TurboDocxSdk::NetworkError` | — | Network connectivity issues | +The full typed-error table and HTTP status mapping is documented once in the [Ruby SDK's Error Handling reference](/docs/SDKs/turbosign?language=ruby#error-handling); partner calls use the same `AuthenticationError`/`AuthorizationError`/`ValidationError`/`NotFoundError`/`ConflictError`/`RateLimitError`/`NetworkError` types. --- @@ -925,5 +912,5 @@ It creates an organization with entitlements, adds a user, mints an org API key, - [GitHub Repository](https://github.com/TurboDocx/SDK/tree/main/packages/ruby-sdk) - [RubyGems Package](https://rubygems.org/gems/turbodocx-sdk) - [TurboSign Ruby SDK](/docs/SDKs/ruby) — For digital signature operations -- [TurboQuote Ruby SDK](/docs/SDKs/quote-ruby) — For quotes and proposals +- [TurboQuote Ruby SDK](/docs/SDKs/quote?language=ruby) — For quotes and proposals - [SDKs Overview](/docs/SDKs/) — All TurboDocx SDKs diff --git a/docs/SDKs/quote-ruby.md b/docs/SDKs/quote-ruby.md deleted file mode 100644 index a5d7427d..00000000 --- a/docs/SDKs/quote-ruby.md +++ /dev/null @@ -1,985 +0,0 @@ ---- -# Hidden from the published site: the turbodocx-sdk gem is not on RubyGems yet. -# Remove `draft: true` when the gem is published (TurboDocx/SDK issue). -draft: true -title: TurboQuote Ruby SDK -sidebar_position: 23 -sidebar_label: "TurboQuote: Ruby" -description: Official TurboDocx TurboQuote SDK for Ruby. Create, manage, and send quotes/proposals with full CPQ capabilities — line items, products, bundles, price books, companies, contacts, and quote templates, all from plain Ruby. -keywords: - - turboquote ruby - - quote sdk ruby - - proposal sdk ruby - - cpq ruby - - turbodocx quote ruby - - gem turbodocx - - quote line items ruby - - price book ruby ---- - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; -import QuickstartSkillNudge from '@site/src/components/QuickstartSkillNudge'; - -# TurboQuote Ruby SDK - - - -The official TurboDocx TurboQuote SDK for Ruby applications. Build full CPQ (configure, price, quote) workflows: create quotes, add product and bundle line items, apply price books, send proposals to contacts, and download PDF exports — all from plain Ruby 2.7+. Distributed on RubyGems as `turbodocx-sdk` (same gem as TurboSign, TurboWebhooks, and Deliverable). - -
- -:::info What is TurboQuote? -TurboQuote is TurboDocx's quoting and proposal engine. It covers the full quote lifecycle — draft, send, accept/decline/void — with a product catalog, bundle groupings, price books, company/contact CRM, and customizable quote templates. A draft can also be marked declined directly, for a deal that dies before the quote is ever sent. Quotes can be sent with an attached Deliverable document for a branded proposal experience. -::: - -## Installation - - - - -```bash -gem install turbodocx-sdk -``` - - - - -```ruby -# Gemfile -gem "turbodocx-sdk" -``` - -```bash -bundle install -``` - - - - -## Requirements - -- Ruby 2.7 or higher -- No runtime dependencies (uses the standard library's `net/http`) -- A TurboDocx API key (`TDX-` prefix) — generate one in **Settings → API Keys** -- All SDK methods are synchronous — no async wrapper needed - -## Configuration - -```ruby -require "turbodocx_sdk" - -TurboDocxSdk::TurboQuote.configure( - api_key: ENV["TURBODOCX_API_KEY"], - org_id: ENV["TURBODOCX_ORG_ID"] # optional — auto-reads env var -) -``` - -:::tip No sender email on the client — but set one on your quote template -`TurboQuote.configure` does **not** take `sender_email` or `sender_name`. Quotes are not signature emails. Only `api_key` and, optionally, `org_id` are needed. If you skip the explicit call, the SDK lazily auto-configures from `TURBODOCX_API_KEY` and `TURBODOCX_ORG_ID` on first use. - -The quote's **"Prepared by"** sender comes from your **org quote template** instead. Because an API key has no mailbox of its own, every sender-resolving call — `create_quote`, `duplicate_quote`, `send_quote` / `send_quote_with_deliverable`, and `handle_expired_quote` — fails with a `ValidationError` (`400 SenderEmailRequired`) when the org's quote template has no sender email set. A companion `400 SenderNameRequired` is returned when no sender **name** resolves. Configure both **Sender Name** and **Sender Email** once (`TurboQuote.update_template`) and all of them resolve cleanly. -::: - -:::note camelCase request keys -Method names are snake_case, but the keys **inside** every request hash (`companyId`, `validUntil`, `unitPrice`, …) are **camelCase** — the SDK forwards them to the API verbatim and does not convert snake_case hash keys. -::: - -### Environment Variables - -```bash -TURBODOCX_API_KEY=your_api_key_here -TURBODOCX_ORG_ID=your_org_id_here -# optional — defaults to https://api.turbodocx.com -TURBODOCX_BASE_URL=https://api.turbodocx.com -``` - -## Quick Start - -### Create a quote, add line items, send, and download the PDF - -```ruby -require "turbodocx_sdk" - -TurboDocxSdk::TurboQuote.configure( - api_key: ENV["TURBODOCX_API_KEY"], - org_id: ENV["TURBODOCX_ORG_ID"] -) - -# 1. Create a draft quote -quote = TurboDocxSdk::TurboQuote.create_quote( - "name" => "Acme Corp — Annual Plan Q3", - "companyId" => "company-uuid", - "contactId" => "contact-uuid", - "validUntil" => "2026-09-30", - "currency" => "USD" -) -quote_id = quote["id"] -puts "Created quote #{quote_id}" - -# 2. Add product line items -items = TurboDocxSdk::TurboQuote.add_line_items(quote_id, [ - { - "productId" => "product-uuid-1", - "productName" => "Platform License", - "quantity" => 5, - "unitPrice" => "199.00", - "billingFrequency" => "annual" - }, - { - "productId" => "product-uuid-2", - "productName" => "Onboarding Package", - "quantity" => 1, - "unitPrice" => "499.00", - "billingFrequency" => "one-time" - } -]) -puts "Added #{items.length} line items" - -# 3. Apply a price book (optional) -result = TurboDocxSdk::TurboQuote.apply_price_book(quote_id, "pricebook-uuid") -puts "Price book applied: #{result['updatedCount']} items updated" - -# 4. Send the quote -sent = TurboDocxSdk::TurboQuote.send_quote(quote_id, - "ccEmails" => ["manager@acme.com"], - "validUntil" => "2026-09-30" -) -puts "Sent: #{sent['message']}" - -# 5. Download the PDF -pdf_bytes = TurboDocxSdk::TurboQuote.download_quote_pdf(quote_id) -File.binwrite("acme-quote.pdf", pdf_bytes) -puts "PDF saved (#{pdf_bytes.bytesize} bytes)" -``` - -### Convenience: create, add items, and send in one call - -```ruby -result = TurboDocxSdk::TurboQuote.create_and_send( - "name" => "Acme Corp — Quick Proposal", - "companyId" => "company-uuid", - "contactId" => "contact-uuid", - "currency" => "USD", - "items" => [ - { "productId" => "product-uuid-1", "productName" => "Platform License", "quantity" => 3, "unitPrice" => "299.00", "billingFrequency" => "monthly" } - ], - "bundleItems" => [ - { "bundleId" => "bundle-uuid-1", "bundleName" => "Starter Pack", "quantity" => 1 } - ], - "send" => { - "ccEmails" => ["cc@example.com"], - "validUntil" => "2026-09-30" - } -) -puts "Quote sent: #{result['quote']['id']}" -``` - ---- - -## Method Reference - -All methods are class-level on `TurboDocxSdk::TurboQuote`; configure once, then call on the class. Responses are plain Ruby `Hash`es with string keys. - -### Quotes - -#### `list_quotes` - -```ruby -page = TurboDocxSdk::TurboQuote.list_quotes( - "limit" => 20, - "offset" => 0, - "query" => "acme", - "statuses" => ["draft", "sent"] # repeated-key filter -) -# page["results"], page["totalRecords"], page["stats"] - -page["results"].each do |q| - puts "#{q["name"]} — #{q["status"]}" -end -``` - -#### `create_quote` - -```ruby -# Fixed-term quote — termDays is -1 or 0–3650; omit it to get the default of 60. -quote = TurboDocxSdk::TurboQuote.create_quote( - "name" => "Q3 Proposal", - "companyId" => "company-uuid", # required - "contactId" => "contact-uuid", # required - "currency" => "USD", - "termDays" => 30, # fixed term — do NOT send renewalPeriod with this - "validUntil" => "2026-09-30", - "notes" => "Includes implementation services", - "taxRate" => "8.5" -) -# returns Quote hash - -# Auto-renewal quote — termDays -1 REQUIRES renewalPeriod. -subscription = TurboDocxSdk::TurboQuote.create_quote( - "name" => "Annual Subscription", - "companyId" => "company-uuid", - "contactId" => "contact-uuid", - "currency" => "USD", - "termDays" => -1, # -1 = auto-renewal - "renewalPeriod" => "annually" # "weekly" | "monthly" | "quarterly" | "annually" -) -``` - -:::caution `termDays` and `renewalPeriod` are coupled -`termDays` defaults to **60** when omitted. Valid values are `-1` (auto-renewal) or `0`–`3650` (`0` = one-time). - -`renewalPeriod` is **required** when `termDays` is `-1`, and must be **`nil` or absent** for every other `termDays` value — sending it alongside a fixed term returns a `400`. The same rule applies on `update_quote`. -::: - -#### `get_quote` - -Returns the quote with `statusInfo` and `preparedBy` merged in when present. `preparedBy` is the resolved "Prepared by" identity shown on the quote PDF. - -```ruby -quote = TurboDocxSdk::TurboQuote.get_quote("quote-uuid") -# quote["status"], quote["grandTotal"], quote["statusInfo"] -prepared = quote["preparedBy"] || {} -puts prepared["name"] # e.g. "Acme Billing Integration" or the template sender -puts prepared["email"] # may be nil for an API-created quote — render a placeholder -``` - -`preparedBy` is resolved server-side (org template first, then the quote's creator). **Prefer it over `creator`** for any customer-facing display — `creator` may be the internal API service account. For an API-created quote the resolved name is the **API key's name** (never a generic "API Service User"), and the email comes from the org quote template. `preparedBy` is returned by the **single-quote fetch only** — it is not present on create, duplicate, or list responses. - -#### `update_quote` - -All fields are optional — pass only what changes. Send an explicit `nil` to clear a nullable field. - -```ruby -updated = TurboDocxSdk::TurboQuote.update_quote("quote-uuid", - "name" => "Q3 Proposal — Revised", - "validUntil" => "2026-10-15", - "taxRate" => nil # clears the field -) -``` - -:::info `name` is trimmed, and renaming is draft-only -`name` is trimmed on both `create_quote` and `update_quote` — `" Acme "` is stored as `"Acme"` — and a name that is empty once trimmed returns a `400`. A quote can only be renamed while it is a **draft**; on any other status the update is rejected with `Cannot update quote that is not in draft status` (`templateId` is the only field exempt from that rule). Rename before you send, because **sending snapshots the quote's current name onto the TurboSign document** — that is the name signers see in the request email and on the signed PDF. -::: - -#### `delete_quote` - -```ruby -result = TurboDocxSdk::TurboQuote.delete_quote("quote-uuid") -# result["message"] -``` - -#### `duplicate_quote` - -```ruby -new_quote = TurboDocxSdk::TurboQuote.duplicate_quote("quote-uuid") -# returns new Quote in draft status -``` - -The copy is named **`Copy of `**, truncated to the name column's 255-character limit. Rename it with `update_quote` before sending if that is not what you want signers to see. - -The copy is attributed to **whoever ran the duplicate**, not to the original quote's creator — duplicating with an API key produces a quote whose "Prepared by" resolves through that API key and your org quote template. - -#### `download_quote_pdf` - -Returns raw PDF bytes. - -```ruby -pdf_bytes = TurboDocxSdk::TurboQuote.download_quote_pdf("quote-uuid") -File.binwrite("quote.pdf", pdf_bytes) -``` - ---- - -### Quote Numbering Configuration - -Customize the per-org quote number format: prefix, year/month tokens, separator, zero-padding, suffix, starting number, and reset cadence. Both methods are **admin only**; a non-admin API key receives a `403`. - -#### `get_quote_number_config` - -Fetch the org's current quote numbering format and the current per-period issued floor. - -```ruby -config = TurboDocxSdk::TurboQuote.get_quote_number_config -puts config["format"]["prefix"] # e.g. "Q-" -puts config["currentFloor"] # the current per-period issued floor -``` - -#### `update_quote_number_config` - -Update the numbering format. Pass the full format hash; all eight fields are required. Keys stay camelCase. - -```ruby -config = TurboDocxSdk::TurboQuote.update_quote_number_config( - "prefix" => "INV", - "yearToken" => "none", # "none" | "two" | "four" - "monthToken" => "off", # "off" | "two" - "separator" => "-", - "padWidth" => 4, # 0–12 - "suffix" => "", - "startNumber" => 1000, # >= 0 - "resetCadence" => "never" # "never" | "yearly" | "monthly" -) -puts config["format"]["startNumber"] # 1000 -``` - -The SDK also exposes constants for the enum values: `TurboDocxSdk::QuoteNumberYearToken`, `TurboDocxSdk::QuoteNumberMonthToken`, and `TurboDocxSdk::QuoteNumberResetCadence`. - -#### Field reference, defaults & validation - -All eight `format` keys are sent on every update. The API enforces these caps and allowed values — a violation returns `400`: - -| Field | Type | Allowed / range | Default | -|-------|------|-----------------|---------| -| `prefix` | string | ≤ 12 characters | `"Q"` | -| `yearToken` | enum | `none` \| `two` \| `four` | `four` | -| `monthToken` | enum | `off` \| `two` | `off` | -| `separator` | string | ≤ 4 characters | `"-"` | -| `padWidth` | integer | `0`–`12` (`0` = no padding) | `5` | -| `suffix` | string | ≤ 12 characters | `""` | -| `startNumber` | integer | `0`–`1000000000` | `1` | -| `resetCadence` | enum | `never` \| `yearly` \| `monthly` | `yearly` | - -An org that has never configured numbering uses the **default format** above, which renders like `Q-2026-00001`. - -Beyond the per-field caps, the API rejects self-inconsistent formats with a `400`: - -- `resetCadence: "yearly"` requires a year token (`yearToken` other than `none`) — otherwise numbers repeat across years. -- `resetCadence: "monthly"` requires **both** a year token and a month token (`monthToken: "two"`). -- The rendered quote number must be ≤ 256 characters. - -`currentFloor` (returned by both methods) is read-only — the sequence the next quote will use for the current period — and is never sent on update. - ---- - -### Quote Status Transitions - -:::caution Send preconditions - -Both send methods share the same server-side checks. Each is rejected with **HTTP 400** and a -specific error `code` before anything is created or emailed: - -| Condition | Code | -| :--- | :--- | -| Quote is not a draft | `QuoteNotSendable` | -| No `validUntil` date set | `QuoteValidUntilRequired` | -| `validUntil` is in the past | `QuoteExpired` | -| No line items | `QuoteHasNoLineItems` | -| Contact missing a name or email | `QuoteContactRequired` | -| Company or contact deleted/deactivated | `QuoteCustomerInactive` | -| No sender email resolvable (API-key callers) | `SenderEmailRequired` | - -A quote with **no line items cannot be sent** — add at least one product, bundle, or custom -line item first. Likewise an **expired quote is rejected**; update `validUntil`, or use the -handle-expired flow to void it and create a fresh draft. - -::: - -#### `send_quote` - -```ruby -sent = TurboDocxSdk::TurboQuote.send_quote("quote-uuid", - "ccEmails" => ["manager@example.com"], - "validUntil" => "2026-09-30" -) -# sent["quote"], sent["message"] -``` - -#### `send_quote_with_deliverable` - -Attach a TurboDocx-generated document to the sent quote. - -```ruby -result = TurboDocxSdk::TurboQuote.send_quote_with_deliverable("quote-uuid", - "deliverableId" => "deliverable-uuid", - "ccEmails" => ["manager@example.com"] -) -# result["quote"], result["message"], result["documentId"] -``` - -#### Reminders & expiration on a sent quote - -`send_quote` and `send_quote_with_deliverable` accept the same reminder/expiration schedule as a TurboSign send — the eight `remindersEnabled` / `reminderDelay` / `reminderInterval` / `maxReminders` / `expirationEnabled` / `expireAfter` / `expirationWarning` / `expirationWarningInterval` keys, each duration a `{ "value" =>, "unit" => }` hash whose `"unit"` is `"days"` or `"hours"`. Both features are off by default. `maxReminders` is `-1` unlimited, `0` none, **max `50`**; `expirationWarning` may be `0` to never warn. - -```ruby -sent = TurboDocxSdk::TurboQuote.send_quote("quote-uuid", - "validUntil" => "2026-09-30", - "remindersEnabled" => true, - "reminderDelay" => { "value" => 3, "unit" => "days" }, - "reminderInterval" => { "value" => 3, "unit" => "days" }, - "maxReminders" => 5, - "expirationEnabled" => true, - "expirationWarning" => { "value" => 2, "unit" => "days" }, - "expirationWarningInterval" => { "value" => 1, "unit" => "days" } -) -``` - -:::warning Quote expiry is pinned to `validUntil` -Unlike a plain TurboSign send, a quote's signing deadline is **hard-pinned to the quote's `validUntil` date**. When expiration is on, `expireAfter` is **ignored** — the deadline is always `validUntil`. `expirationEnabled` still toggles expiry on or off. The reminder and expiry-warning cadence still applies, but every reminder and warning must fall **inside** the `validUntil` window; a cadence that would outlive it is rejected with a `400`. -::: - -#### `decline_quote` - -Declines a **sent** quote or a **draft**. `reason` (max 190 characters) is required once a quote has been sent. A draft is declined **without** a reason — a draft never reached the customer, and because the reason is stored on the linked signature document, a draft has nowhere to keep one, so anything passed is ignored. - -```ruby -quote = TurboDocxSdk::TurboQuote.decline_quote("quote-uuid", - "reason" => "Customer selected a competitor" -) - -# A draft is declined with no reason — one passed here would not be recorded. -closed_out = TurboDocxSdk::TurboQuote.decline_quote("draft-quote-uuid", {}) -``` - -#### `void_quote` - -Voids a **sent** quote; a **draft cannot be voided**, since voiding an unsent quote is meaningless. - -```ruby -quote = TurboDocxSdk::TurboQuote.void_quote("quote-uuid", - "reason" => "Terms expired before acceptance" -) -``` - -#### `handle_expired_quote` - -Handles a quote that has passed its `validUntil` date. The endpoint **closes out the original quote** — voiding or declining it depending on `action` — and then **creates a duplicate carrying `newValidUntil`** as its new validity date. The returned quote is the new duplicate; the original stays terminal. - -`action` (`"void"`, `"decline"` or `"renew"`) and `newValidUntil` (ISO date) are **required**. `reason` (max 190 characters) is required for `"void"` and `"decline"`, and optional for `"renew"` — a renewal closes nothing out, so there is nothing to give a reason for. Use `"renew"` when the quote's signature request has already expired on its own; use `"void"` or `"decline"` when the quote is merely past its `validUntil` and you are closing it yourself. - -```ruby -quote = TurboDocxSdk::TurboQuote.handle_expired_quote("quote-uuid", - "action" => "void", # required — "void", "decline" or "renew" - "reason" => "Quote expired", # required for void/decline, optional for renew - "newValidUntil" => "2026-12-31" # required — ISO date, carried onto the duplicate -) -``` - -:::warning There is no `extend` or `resend` action -`action` accepts **only** `"void"`, `"decline"` and `"renew"`. `"extend"` and `"resend"` do not exist in the API and return a `400`. Extending is what the endpoint already does — pass `newValidUntil` and it lands on the duplicate it creates. -::: - -:::info The replacement draft keeps the original name -Unlike `duplicate_quote`, the draft this endpoint creates is **not** prefixed with `Copy of ` — re-issuing the same deal keeps the original quote's name, so repeated renewals cannot compound into `Copy of Copy of …`. That matters because the next send snapshots the name onto the TurboSign document. -::: - -:::note Terminal statuses -`accepted`, `declined`, and `voided` are **terminal** — a quote in one of these states cannot be transitioned out of it, and any further status call returns a `400`. Check `quote["statusInfo"]` before attempting a transition, and use `duplicate_quote` when you need to revive a closed-out quote. -::: - ---- - -### Price Books (on a Quote) - -#### `apply_price_book` - -Apply a price book to an existing quote; updates matching line item prices. - -```ruby -result = TurboDocxSdk::TurboQuote.apply_price_book("quote-uuid", "pricebook-uuid") -# result["quote"] — updated Quote -# result["updatedCount"] — Integer, items that were re-priced -# result["skippedCount"] — Integer, items that had no pricebook match -# result["message"] -``` - -#### `remove_price_book` - -```ruby -quote = TurboDocxSdk::TurboQuote.remove_price_book("quote-uuid") -``` - ---- - -### Line Items - -#### `list_line_items` - -```ruby -page = TurboDocxSdk::TurboQuote.list_line_items("quote-uuid", "limit" => 50) -# page["results"], page["totalRecords"] -``` - -#### `add_line_items` - -Accepts a single item hash **or** an array of up to **50** items. Returns an array of created line item hashes. - -`productId`, `productName`, `unitPrice`, and `billingFrequency` are all **required** on every row. `productId` is special: the key must be **present**, but its value may be `nil` for a custom (freeform) line item — omitting the key entirely returns a `400`. `quantity` is optional and defaults to `1`. - -```ruby -items = TurboDocxSdk::TurboQuote.add_line_items("quote-uuid", [ - { - "productId" => "product-uuid", # required key — nil for a custom line item - "productName" => "Platform License", - "quantity" => 2, - "unitPrice" => "199.00", - "billingFrequency" => "annual", - "discountPercent" => "10.0" - }, - { - "productId" => nil, # custom (freeform) line item — key still required - "productName" => "Implementation Credit", - "unitPrice" => "-250.00", - "billingFrequency" => "one-time" - } -]) -``` - -:::note Array caps -`add_line_items` accepts a single hash **or** an array of 1–**50** items. A reorder request accepts up to **200** items. Exceeding either cap returns a `400`. -::: - -#### `add_bundle_line_items` - -`bundleId` and `bundleName` are both **required**; the server expands the bundle's child products for you. Accepts a single hash or an array of up to **50** items. - -```ruby -items = TurboDocxSdk::TurboQuote.add_bundle_line_items("quote-uuid", [ - { - "bundleId" => "bundle-uuid", - "bundleName" => "Starter Bundle", # required - "quantity" => 1 - } -]) -``` - -#### `update_line_item` - -```ruby -item = TurboDocxSdk::TurboQuote.update_line_item("quote-uuid", "item-uuid", - "quantity" => 5, - "unitPrice" => "179.00" -) -``` - -#### `remove_line_item` - -```ruby -result = TurboDocxSdk::TurboQuote.remove_line_item("quote-uuid", "item-uuid") -# result["message"] -``` - ---- - -### Products - -| Method | Signature | Returns | -|---|---|---| -| `list_products` | `(options = nil)` | paginated list | -| `create_product` | `(request)` | `Product` | -| `bulk_create_products` | `(rows)` | [bulk report](#bulk-create) | -| `get_product` | `(id)` | `Product` | -| `update_product` | `(id, request)` | `Product` | -| `delete_product` | `(id)` | `{"message" => ...}` | -| `duplicate_product` | `(id)` | `Product` | -| `get_product_primary_images` | `(product_ids)` | `{id => image or nil}` | - -:::caution `categoryId` is required on create -`create_product` **requires** `name`, `categoryId`, `listPrice`, and `billingFrequency`. `categoryId` must be the **UUID** of an existing type (`categoryType` `"product_category"`) — resolve or create it first with `list_types` / `create_type`. It is optional on `update_product`, so you only need to pass it when creating. -::: - -```ruby -# Resolve the product category first — create_product needs its UUID. -page = TurboDocxSdk::TurboQuote.list_types("categoryType" => "product_category") -category = page["results"].find { |t| t["name"] == "Software" } -category ||= TurboDocxSdk::TurboQuote.create_type( - "name" => "Software", - "categoryType" => "product_category" -) - -# Create a product with images (multipart upload auto-detected) -product = TurboDocxSdk::TurboQuote.create_product( - "name" => "Enterprise License", - "categoryId" => category["id"], # required - "listPrice" => "499.00", - "cost" => "200.00", - "billingFrequency" => "annual", - "showInCatalog" => true, - "images" => ["/path/to/product-photo.png"] # file path(s) or IO objects -) - -# List products with filters -page = TurboDocxSdk::TurboQuote.list_products( - "limit" => 20, - "query" => "enterprise", - "showInCatalog" => true -) - -# Bulk fetch primary images for a set of product IDs -images = TurboDocxSdk::TurboQuote.get_product_primary_images(["id-1", "id-2", "id-3"]) -# images["id-1"] → ProductImage hash, or nil -``` - ---- - -### Bundles - -| Method | Signature | Returns | -|---|---|---| -| `list_bundles` | `(options = nil)` | paginated list | -| `create_bundle` | `(request)` | `Bundle` | -| `bulk_create_bundles` | `(rows)` | [bulk report](#bulk-create) | -| `get_bundle` | `(id)` | `Bundle` | -| `update_bundle` | `(id, request)` | `Bundle` | -| `delete_bundle` | `(id)` | `{"message" => ...}` | -| `duplicate_bundle` | `(id)` | `Bundle` | - -Each entry in `items` **requires** `productId`, `unitPrice`, and `billingFrequency`. `quantity` is optional and defaults to `1`. - -```ruby -bundle = TurboDocxSdk::TurboQuote.create_bundle( - "name" => "Starter Pack", - "categoryId" => "bundle-category-uuid", # required - "items" => [ - { - "productId" => "product-uuid-1", - "unitPrice" => "199.00", - "billingFrequency" => "monthly", - "quantity" => 1 - }, - { - "productId" => "product-uuid-2", - "unitPrice" => "49.00", - "billingFrequency" => "monthly", - "quantity" => 2 - } - ], - "bundleDiscountType" => "percent", - "bundleDiscountAmount" => 5 -) -``` - ---- - -### Price Books - -| Method | Signature | Returns | -|---|---|---| -| `list_price_books` | `(options = nil)` | paginated list | -| `create_price_book` | `(request)` | `PriceBook` | -| `bulk_create_price_books` | `(rows)` | [bulk report](#bulk-create) | -| `get_price_book` | `(id)` | `PriceBook` | -| `update_price_book` | `(id, request)` | `PriceBook` | -| `delete_price_book` | `(id)` | `{"message" => ...}` | -| `duplicate_price_book` | `(id)` | `PriceBook` | -| `list_price_book_products` | `(id, options = nil)` | paginated list | - -```ruby -# name, priceBookTypeId, and validFrom are REQUIRED. -# discountPercent is optional and defaults to 0 if not provided. -# priceBookTypeId comes from a create_type with categoryType "pricebook_type". -pricebook = TurboDocxSdk::TurboQuote.create_price_book( - "name" => "Partner Tier A", - "priceBookTypeId" => "pricebook-type-uuid", - "validFrom" => "2026-01-01", - "discountPercent" => 15, - "isDefault" => false, - "productPricing" => [ - { "productId" => "product-uuid-1", "discountType" => "percent", "discountPercent" => 25 }, - { "productId" => "product-uuid-2", "discountType" => "percent", "discountPercent" => 30 } - ] -) - -# List products attached to a price book -page = TurboDocxSdk::TurboQuote.list_price_book_products("pricebook-uuid", "limit" => 50) -``` - ---- - -### Companies - -| Method | Signature | Returns | -|---|---|---| -| `list_companies` | `(options = nil)` | paginated list | -| `create_company` | `(request)` | `Company` | -| `bulk_create_companies` | `(rows)` | [bulk report](#bulk-create) | -| `get_company` | `(id)` | `Company` | -| `update_company` | `(id, request)` | `Company` | -| `delete_company` | `(id)` | `{"message" => ...}` | -| `list_company_contacts` | `(company_id, options = nil)` | paginated list | - -```ruby -company = TurboDocxSdk::TurboQuote.create_company( - "name" => "Acme Corporation", - "phone" => "+1-555-0100", - "city" => "San Francisco", - "state" => "CA", - "country" => "US", - "contacts" => [ # at least one contact required; each needs name + email - { - "name" => "Jane Doe", - "email" => "jane@acme.com", - "title" => "VP of Engineering" - } - ] -) - -# List contacts for a company -contacts = TurboDocxSdk::TurboQuote.list_company_contacts(company["id"]) -``` - ---- - -### Contacts - -| Method | Signature | Returns | -|---|---|---| -| `list_contacts` | `(options = nil)` | paginated list | -| `create_contact` | `(request)` | `Contact` | -| `bulk_create_contacts` | `(rows)` | [bulk report](#bulk-create) | -| `update_contact` | `(id, request)` | `Contact` | -| `delete_contact` | `(id)` | `{"message" => ...}` | - -:::note No `get_contact` by design -The backend has no `GET /v1/contacts/:id` endpoint. Fetch individual contacts via `list_company_contacts` or `list_contacts` with a query filter. -::: - -```ruby -contact = TurboDocxSdk::TurboQuote.create_contact( - "name" => "John Smith", - "email" => "john@acme.com", - "companyId" => "company-uuid" -) -``` - ---- - -### Quote Templates - -| Method | Signature | Returns | -|---|---|---| -| `list_templates` | `(options = nil)` | paginated list | -| `get_template` | `()` | singleton `QuoteTemplate` — auto-created if none exists | -| `get_template_by_id` | `(id)` | `QuoteTemplate` | -| `create_template` | `(request)` | `QuoteTemplate` — `400` if one already exists | -| `update_template` | `(id, request)` | `QuoteTemplate` | -| `delete_template` | `(id)` | `{"message" => ...}` — resets to org branding defaults | - -:::warning Templates are auto-provisioned — use `get_template` → `update_template` -`get_template` **self-heals**: if the org has no template, the API creates one from your org branding and returns it. Every established org therefore already has a template, which means: - -- `create_template` returns **400 `TEMPLATE_ALREADY_EXISTS`** and is effectively unreachable. Do not build a get-then-create flow. -- `delete_template` is really "reset to org branding defaults" — it soft-deletes, and the next `get_template` regenerates a fresh one. - -The correct flow is **`get_template` → `update_template`**. -::: - -```ruby -# 1. Get the org's quote template (created from org branding on first read) -template = TurboDocxSdk::TurboQuote.get_template - -# 2. Brand it by updating the template you just fetched -branded = TurboDocxSdk::TurboQuote.update_template(template["id"], - "logoUrl" => "https://cdn.example.com/logo.png", - "primaryColor" => "#0057b8", - "senderName" => "TurboDocx Sales" -) - -# Get a specific named template by ID -other = TurboDocxSdk::TurboQuote.get_template_by_id("template-uuid") -``` - ---- - -### Types / Categories - -| Method | Signature | Returns | -|---|---|---| -| `list_types` | `(options = nil)` | paginated list | -| `create_type` | `(request)` | `QuoteType` | -| `bulk_create_types` | `(rows)` | [bulk report](#bulk-create) | -| `update_type` | `(id, request)` | `QuoteType` | -| `delete_type` | `(id)` | `{"message" => ...}` | - -:::note No `get_type` by design -The backend has no `GET /v1/types/:id` endpoint. Use `list_types` to retrieve individual type records. -::: - -```ruby -quote_type = TurboDocxSdk::TurboQuote.create_type("name" => "New Business") - -TurboDocxSdk::TurboQuote.update_type(quote_type["id"], "name" => "New Logo Business") -``` - ---- - -### Bulk Create - -Six methods import many records in one request — ideal for CSV-style migrations: - -| Method | Endpoint | Row shape | -|---|---|---| -| `bulk_create_products` | `POST /v1/products/bulk` | same fields as `create_product` | -| `bulk_create_price_books` | `POST /v1/pricebooks/bulk` | same fields as `create_price_book` | -| `bulk_create_bundles` | `POST /v1/bundles/bulk` | same fields as `create_bundle` | -| `bulk_create_companies` | `POST /v1/companies/bulk` | same fields as `create_company` — each row **requires a `contacts` array with at least one contact** | -| `bulk_create_contacts` | `POST /v1/contacts/bulk` | same fields as `create_contact` — each row **requires a `companyId`** | -| `bulk_create_types` | `POST /v1/types/bulk` | same fields as `create_type` | - -Each method takes an array of row hashes; the SDK wraps them in the `{ "rows" => [...] }` envelope the endpoint expects. Rows use the exact request shape of the corresponding single-create method (camelCase keys). - -:::caution Product rows require a real `categoryId` -Every `bulk_create_products` row **requires** `name`, `categoryId`, `listPrice`, and `billingFrequency`. `categoryId` must be the **UUID** of an existing type (`categoryType` `"product_category"`) — there is no `categoryName` key on the bulk row schema, and the API rejects unknown keys, so passing one returns a `400`. Resolve or create the category first with `list_types` / `create_type`, then pass its `"id"`. -::: - -```ruby -# 1. Resolve the product category first — bulk rows need its UUID, not its name. -page = TurboDocxSdk::TurboQuote.list_types("categoryType" => "product_category") -category = page["results"].find { |t| t["name"] == "Software" } -category ||= TurboDocxSdk::TurboQuote.create_type( - "name" => "Software", - "categoryType" => "product_category" -) -category_id = category["id"] - -# 2. Import, passing the resolved UUID on every row. -report = TurboDocxSdk::TurboQuote.bulk_create_products([ - { "name" => "Starter License", "categoryId" => category_id, "listPrice" => "99.00", "billingFrequency" => "monthly" }, - { "name" => "Pro License", "categoryId" => category_id, "listPrice" => "299.00", "billingFrequency" => "monthly" }, - { "name" => "Enterprise License", "categoryId" => category_id, "listPrice" => "499.00", "billingFrequency" => "annual" } -]) - -puts "Imported #{report['imported']} rows" -report["failed"].each do |failure| - puts "Row #{failure['row']} failed: #{failure['reason']}" # "row" is 1-indexed -end -report["adjusted"].each do |adjustment| - puts "Row #{adjustment['row']} adjusted: #{adjustment['reason']}" -end -``` - -**Partial-success semantics** — every bulk method returns the same report hash instead of raising for bad rows: - -| Key | Type | Meaning | -|---|---|---| -| `imported` | Integer | Rows created successfully | -| `failed` | Array of `{"row", "reason"}` | Rows the server rejected — `row` is the **1-indexed** position in your input array | -| `adjusted` | Array of `{"row", "reason"}` | Rows the server imported after modifying them (e.g. a bundle item whose product wasn't found was dropped) | - -Rules and limits: - -- **A failed row does not raise** and does not roll back earlier rows — always check `report["failed"]` after the call. -- **Max 500 rows per request.** Exceeding the cap fails the whole request with a `400` (`TurboDocxSdk::ValidationError`); an invalid envelope (e.g. non-array input) also raises `ValidationError`. -- **Roles:** available to **administrator and contributor** API keys. -- The SDK performs no client-side row validation — errors come back per-row in the report. - -```ruby -# Companies need >= 1 contact per row; contacts need a companyId per row -TurboDocxSdk::TurboQuote.bulk_create_companies([ - { - "name" => "Acme Corporation", - "contacts" => [{ "name" => "Jane Doe", "email" => "jane@acme.com" }] - } -]) - -TurboDocxSdk::TurboQuote.bulk_create_contacts([ - { "name" => "John Smith", "email" => "john@acme.com", "companyId" => "company-uuid" } -]) -``` - ---- - -### Convenience - -#### `create_and_send` - -Orchestrates multiple API calls: create quote → add product items → add bundle items → send. Returns `{ "quote" => }`. - -```ruby -result = TurboDocxSdk::TurboQuote.create_and_send( - # CreateQuote fields - "name" => "Year-End Renewal", - "companyId" => "company-uuid", - "contactId" => "contact-uuid", - "currency" => "USD", - # optional line items added before send - "items" => [ - { "productId" => "product-uuid-1", "productName" => "Platform License", "quantity" => 10, "unitPrice" => "99.00", "billingFrequency" => "monthly" } - ], - # optional bundle items added before send - "bundleItems" => [ - { "bundleId" => "bundle-uuid-1", "bundleName" => "Starter Pack", "quantity" => 1 } - ], - # send options (ccEmails, validUntil) - "send" => { - "ccEmails" => ["finance@example.com"], - "validUntil" => "2026-12-31" - } -) -puts result["quote"]["id"] -``` - ---- - -## Constants - -The gem exposes constants so you can avoid hard-coding string literals: - -```ruby -TurboDocxSdk::QuoteStatus::DRAFT # "draft" -TurboDocxSdk::QuoteStatus::SENT # "sent" -TurboDocxSdk::BillingFrequency::MONTHLY # "monthly" -TurboDocxSdk::BillingFrequency::ANNUAL # "annual" -TurboDocxSdk::DiscountType::PERCENT # "percent" -TurboDocxSdk::DiscountType::AMOUNT # "amount" -TurboDocxSdk::Currency::USD # "USD" -TurboDocxSdk::LineItemType::PRODUCT # "product" -TurboDocxSdk::CategoryType::PRICEBOOK_TYPE # "pricebook_type" -``` - ---- - -## Error Handling - -```ruby -require "turbodocx_sdk" - -begin - quote = TurboDocxSdk::TurboQuote.create_quote( - "name" => "Q3 Proposal", - "companyId" => "company-uuid", - "contactId" => "contact-uuid" - ) -rescue TurboDocxSdk::ValidationError => e - # 400 — missing required fields, invalid enum value, etc. - puts "Validation failed: #{e.message}" -rescue TurboDocxSdk::AuthenticationError - # 401 — bad or revoked API key -rescue TurboDocxSdk::AuthorizationError - # 403 — key valid but lacks permission for this org/action -rescue TurboDocxSdk::NotFoundError => e - # 404 — company, contact, or product not found - puts "Not found: #{e.message}" -rescue TurboDocxSdk::RateLimitError - # 429 — back off and retry -rescue TurboDocxSdk::NetworkError - # request never reached the server (DNS, refused, timeout) -rescue TurboDocxSdk::TurboDocxError => e - # catch-all for any other typed SDK error (raw 5xx, etc.) - puts "Error #{e.status_code}: #{e.message}" -end -``` - -### Error Code Reference - -| Status | Class | When | -|---|---|---| -| 400 | `ValidationError` | Invalid fields, missing required keys, bad enum value | -| 401 | `AuthenticationError` | Missing or invalid API key | -| 403 | `AuthorizationError` | Valid key without permission for this operation | -| 404 | `NotFoundError` | Quote, product, company, or other resource not found | -| 409 | `ConflictError` | Duplicate resource (e.g., company domain conflict) | -| 429 | `RateLimitError` | Rate limit exceeded — back off | - ---- - -## See Also - -- [TurboQuote JavaScript / TypeScript SDK](/docs/SDKs/quote-javascript) — same API, JS idioms -- [TurboQuote Python SDK](/docs/SDKs/quote-python) — same API, Python idioms -- [TurboSign Ruby SDK](/docs/SDKs/ruby) — send documents for e-signature -- [TurboWebhooks Ruby SDK](/docs/SDKs/webhooks-ruby) — receive real-time signature events -- [Deliverable Ruby SDK](/docs/SDKs/deliverable-ruby) — generate documents from templates -- [SDKs Overview](/docs/SDKs) — all SDKs across all languages -- [turbodocx-sdk on RubyGems](https://rubygems.org/gems/turbodocx-sdk) -- [TurboDocx SDK on GitHub](https://github.com/TurboDocx/SDK/tree/main/packages/ruby-sdk) diff --git a/docs/SDKs/quote.md b/docs/SDKs/quote.md index 43ee63ae..7dc5713b 100644 --- a/docs/SDKs/quote.md +++ b/docs/SDKs/quote.md @@ -2,7 +2,7 @@ title: TurboQuote SDK sidebar_position: 16 sidebar_label: TurboQuote -description: 'TurboQuote SDK for JavaScript, TypeScript, Python, PHP, Go and Java: create quotes, add line items, apply price books, send and download PDFs.' +description: 'TurboQuote SDK for JavaScript, TypeScript, Python, PHP, Go, Java and Ruby: create quotes, add line items, apply price books, send and download PDFs.' keywords: - turboquote javascript - turboquote typescript @@ -51,6 +51,22 @@ keywords: - gradle turboquote - line items java - pricebook java + +- turboquote ruby + +- quote sdk ruby + +- proposal sdk ruby + +- cpq ruby + +- turbodocx quote ruby + +- gem turbodocx + +- quote line items ruby + +- price book ruby --- import Tabs from '@theme/Tabs'; @@ -118,6 +134,17 @@ The official TurboDocx TurboQuote SDK for Java applications. Create and send sal TurboQuote is TurboDocx's CPQ (Configure, Price, Quote) module. Build a product catalog, assemble quotes with line items, apply price book discounts, and send branded proposals to contacts — with optional TurboSign e-signature delivery via `sendQuoteWithDeliverable`. A `draft` can also be marked `declined` directly, for a deal that dies before the quote is ever sent. The client config takes no `senderEmail`; the quote's **"Prepared by"** sender comes from your org quote template (see the note below `createQuote`). ::: + + + +The official TurboDocx TurboQuote SDK for Ruby applications. Build full CPQ (configure, price, quote) workflows: create quotes, add product and bundle line items, apply price books, send proposals to contacts, and download PDF exports — all from plain Ruby 2.7+. Distributed on RubyGems as `turbodocx-sdk` (same gem as TurboSign, TurboWebhooks, and Deliverable). + +
+ +:::info What is TurboQuote? +TurboQuote is TurboDocx's quoting and proposal engine. It covers the full quote lifecycle — draft, send, accept/decline/void — with a product catalog, bundle groupings, price books, company/contact CRM, and customizable quote templates. A draft can also be marked declined directly, for a deal that dies before the quote is ever sent. Quotes can be sent with an attached Deliverable document for a branded proposal experience. +::: +
@@ -237,6 +264,31 @@ import com.turbodocx.TurboDocxException; import com.turbodocx.models.quote.*; ``` + + + + + + +```bash +gem install turbodocx-sdk +``` + + + + +```ruby +# Gemfile +gem "turbodocx-sdk" +``` + +```bash +bundle install +``` + + + + @@ -280,6 +332,14 @@ import com.turbodocx.models.quote.*; - Gson 2.x (included transitively) - A TurboDocx API key (`TDX-` prefix) — no administrator role required + + + +- Ruby 2.7 or higher +- No runtime dependencies (uses the standard library's `net/http`) +- A TurboDocx API key (`TDX-` prefix) — generate one in **Settings → API Keys** +- All SDK methods are synchronous — no async wrapper needed + @@ -424,6 +484,28 @@ TurboQuote tq = client.turboQuote(); The quote's **"Prepared by"** sender comes from your **org quote template** instead. Because an API key has no mailbox of its own, every sender-resolving call — `createQuote`, `duplicateQuote`, `sendQuote` / `sendQuoteWithDeliverable`, and `handleExpiredQuote` — fails with a `ValidationException` (`400 SenderEmailRequired`) when the org's quote template has no sender email set. A companion `400 SenderNameRequired` is returned when no sender **name** resolves. Configure both **Sender Name** and **Sender Email** once (`updateTemplate`) and all of them resolve cleanly. + + + +```ruby +require "turbodocx_sdk" + +TurboDocxSdk::TurboQuote.configure( + api_key: ENV["TURBODOCX_API_KEY"], + org_id: ENV["TURBODOCX_ORG_ID"] # optional — auto-reads env var +) +``` + +:::tip No sender email on the client — but set one on your quote template +`TurboQuote.configure` does **not** take `sender_email` or `sender_name`. Quotes are not signature emails. Only `api_key` and, optionally, `org_id` are needed. If you skip the explicit call, the SDK lazily auto-configures from `TURBODOCX_API_KEY` and `TURBODOCX_ORG_ID` on first use. + +The quote's **"Prepared by"** sender comes from your **org quote template** instead. Because an API key has no mailbox of its own, every sender-resolving call — `create_quote`, `duplicate_quote`, `send_quote` / `send_quote_with_deliverable`, and `handle_expired_quote` — fails with a `ValidationError` (`400 SenderEmailRequired`) when the org's quote template has no sender email set. A companion `400 SenderNameRequired` is returned when no sender **name** resolves. Configure both **Sender Name** and **Sender Email** once (`TurboQuote.update_template`) and all of them resolve cleanly. +::: + +:::note camelCase request keys +Method names are snake_case, but the keys **inside** every request hash (`companyId`, `validUntil`, `unitPrice`, …) are **camelCase** — the SDK forwards them to the API verbatim and does not convert snake_case hash keys. +::: + @@ -493,6 +575,16 @@ TURBODOCX_BASE_URL=https://api.turbodocx.com Both `apiKey` and `orgId` are required. To get your credentials, follow the [Get Your Credentials](/docs/SDKs#1-get-your-credentials) steps from the SDKs main page. ::: + + + +```bash +TURBODOCX_API_KEY=your_api_key_here +TURBODOCX_ORG_ID=your_org_id_here +# optional — defaults to https://api.turbodocx.com +TURBODOCX_BASE_URL=https://api.turbodocx.com +``` + @@ -920,6 +1012,64 @@ func main() { } ``` + + + +```ruby +require "turbodocx_sdk" + +TurboDocxSdk::TurboQuote.configure( + api_key: ENV["TURBODOCX_API_KEY"], + org_id: ENV["TURBODOCX_ORG_ID"] +) + +# 1. Create a draft quote +quote = TurboDocxSdk::TurboQuote.create_quote( + "name" => "Acme Corp — Annual Plan Q3", + "companyId" => "company-uuid", + "contactId" => "contact-uuid", + "validUntil" => "2026-09-30", + "currency" => "USD" +) +quote_id = quote["id"] +puts "Created quote #{quote_id}" + +# 2. Add product line items +items = TurboDocxSdk::TurboQuote.add_line_items(quote_id, [ + { + "productId" => "product-uuid-1", + "productName" => "Platform License", + "quantity" => 5, + "unitPrice" => "199.00", + "billingFrequency" => "annual" + }, + { + "productId" => "product-uuid-2", + "productName" => "Onboarding Package", + "quantity" => 1, + "unitPrice" => "499.00", + "billingFrequency" => "one-time" + } +]) +puts "Added #{items.length} line items" + +# 3. Apply a price book (optional) +result = TurboDocxSdk::TurboQuote.apply_price_book(quote_id, "pricebook-uuid") +puts "Price book applied: #{result['updatedCount']} items updated" + +# 4. Send the quote +sent = TurboDocxSdk::TurboQuote.send_quote(quote_id, + "ccEmails" => ["manager@acme.com"], + "validUntil" => "2026-09-30" +) +puts "Sent: #{sent['message']}" + +# 5. Download the PDF +pdf_bytes = TurboDocxSdk::TurboQuote.download_quote_pdf(quote_id) +File.binwrite("acme-quote.pdf", pdf_bytes) +puts "PDF saved (#{pdf_bytes.bytesize} bytes)" +``` + @@ -1036,6 +1186,29 @@ if err != nil { fmt.Printf("Quote %s sent\n", resp.Quote.QuoteNumber) ``` + + + +```ruby +result = TurboDocxSdk::TurboQuote.create_and_send( + "name" => "Acme Corp — Quick Proposal", + "companyId" => "company-uuid", + "contactId" => "contact-uuid", + "currency" => "USD", + "items" => [ + { "productId" => "product-uuid-1", "productName" => "Platform License", "quantity" => 3, "unitPrice" => "299.00", "billingFrequency" => "monthly" } + ], + "bundleItems" => [ + { "bundleId" => "bundle-uuid-1", "bundleName" => "Starter Pack", "quantity" => 1 } + ], + "send" => { + "ccEmails" => ["cc@example.com"], + "validUntil" => "2026-09-30" + } +) +puts "Quote sent: #{result['quote']['id']}" +``` + @@ -1070,6 +1243,11 @@ All methods are instance methods on `com.turbodocx.TurboQuote`. Obtain the insta --- + + + +All methods are class-level on `TurboDocxSdk::TurboQuote`; configure once, then call on the class. Responses are plain Ruby `Hash`es with string keys. + @@ -1187,6 +1365,23 @@ list.getResults().forEach(q -> System.out.println(q.getId() + " " + q.getStatus())); ``` + + + +```ruby +page = TurboDocxSdk::TurboQuote.list_quotes( + "limit" => 20, + "offset" => 0, + "query" => "acme", + "statuses" => ["draft", "sent"] # repeated-key filter +) +# page["results"], page["totalRecords"], page["stats"] + +page["results"].each do |q| + puts "#{q["name"]} — #{q["status"]}" +end +``` + @@ -1368,6 +1563,40 @@ Quote subscription = tq.createQuote(subReq); `renewalPeriod` is **required** when `termDays` is `-1`, and must be **null or unset** for every other `termDays` value — sending it alongside a fixed term returns a `400`. The same rule applies on `updateQuote`. ::: + + + +```ruby +# Fixed-term quote — termDays is -1 or 0–3650; omit it to get the default of 60. +quote = TurboDocxSdk::TurboQuote.create_quote( + "name" => "Q3 Proposal", + "companyId" => "company-uuid", # required + "contactId" => "contact-uuid", # required + "currency" => "USD", + "termDays" => 30, # fixed term — do NOT send renewalPeriod with this + "validUntil" => "2026-09-30", + "notes" => "Includes implementation services", + "taxRate" => "8.5" +) +# returns Quote hash + +# Auto-renewal quote — termDays -1 REQUIRES renewalPeriod. +subscription = TurboDocxSdk::TurboQuote.create_quote( + "name" => "Annual Subscription", + "companyId" => "company-uuid", + "contactId" => "contact-uuid", + "currency" => "USD", + "termDays" => -1, # -1 = auto-renewal + "renewalPeriod" => "annually" # "weekly" | "monthly" | "quarterly" | "annually" +) +``` + +:::caution `termDays` and `renewalPeriod` are coupled +`termDays` defaults to **60** when omitted. Valid values are `-1` (auto-renewal) or `0`–`3650` (`0` = one-time). + +`renewalPeriod` is **required** when `termDays` is `-1`, and must be **`nil` or absent** for every other `termDays` value — sending it alongside a fixed term returns a `400`. The same rule applies on `update_quote`. +::: + @@ -1458,6 +1687,21 @@ if (quote.getPreparedBy() != null) { `preparedBy` is resolved server-side (org template first, then the quote's creator). **Prefer it over `getCreator()`** for any customer-facing display — the creator may be the internal API service account. For an API-created quote the resolved name is the **API key's name** (never a generic "API Service User"), and the email comes from the org quote template. `preparedBy` is returned by the **single-quote fetch only** — it is not present on create, duplicate, or list responses. + + + +Returns the quote with `statusInfo` and `preparedBy` merged in when present. `preparedBy` is the resolved "Prepared by" identity shown on the quote PDF. + +```ruby +quote = TurboDocxSdk::TurboQuote.get_quote("quote-uuid") +# quote["status"], quote["grandTotal"], quote["statusInfo"] +prepared = quote["preparedBy"] || {} +puts prepared["name"] # e.g. "Acme Billing Integration" or the template sender +puts prepared["email"] # may be nil for an API-created quote — render a placeholder +``` + +`preparedBy` is resolved server-side (org template first, then the quote's creator). **Prefer it over `creator`** for any customer-facing display — `creator` may be the internal API service account. For an API-created quote the resolved name is the **API key's name** (never a generic "API Service User"), and the email comes from the org quote template. `preparedBy` is returned by the **single-quote fetch only** — it is not present on create, duplicate, or list responses. + @@ -1554,6 +1798,23 @@ Quote updated = tq.updateQuote(quoteId, req); `name` is trimmed on both `createQuote` and `updateQuote` — `" Acme "` is stored as `"Acme"` — and a name that is empty once trimmed returns a `400`. A quote can only be renamed while it is a **draft**; on any other status the update is rejected with `Cannot update quote that is not in draft status` (`templateId` is the only field exempt from that rule). Rename before you send, because **sending snapshots the quote's current name onto the TurboSign document** — that is the name signers see in the request email and on the signed PDF. ::: + + + +All fields are optional — pass only what changes. Send an explicit `nil` to clear a nullable field. + +```ruby +updated = TurboDocxSdk::TurboQuote.update_quote("quote-uuid", + "name" => "Q3 Proposal — Revised", + "validUntil" => "2026-10-15", + "taxRate" => nil # clears the field +) +``` + +:::info `name` is trimmed, and renaming is draft-only +`name` is trimmed on both `create_quote` and `update_quote` — `" Acme "` is stored as `"Acme"` — and a name that is empty once trimmed returns a `400`. A quote can only be renamed while it is a **draft**; on any other status the update is rejected with `Cannot update quote that is not in draft status` (`templateId` is the only field exempt from that rule). Rename before you send, because **sending snapshots the quote's current name onto the TurboSign document** — that is the name signers see in the request email and on the signed PDF. +::: + @@ -1608,6 +1869,14 @@ SuccessResponse resp = tq.deleteQuote(quoteId); System.out.println(resp.getMessage()); ``` + + + +```ruby +result = TurboDocxSdk::TurboQuote.delete_quote("quote-uuid") +# result["message"] +``` + @@ -1673,6 +1942,16 @@ System.out.println("New quote: " + copy.getId()); The copy is named **`Copy of `**, truncated to the name column's 255-character limit. Rename it with `updateQuote` before sending if that is not what you want signers to see. + + + +```ruby +new_quote = TurboDocxSdk::TurboQuote.duplicate_quote("quote-uuid") +# returns new Quote in draft status +``` + +The copy is named **`Copy of `**, truncated to the name column's 255-character limit. Rename it with `update_quote` before sending if that is not what you want signers to see. + @@ -1746,6 +2025,19 @@ ApplyPriceBookResponse resp = tq.applyPriceBook(quoteId, priceBookId); System.out.println("Updated " + resp.getUpdatedCount() + " items."); ``` + + + +Apply a price book to an existing quote; updates matching line item prices. + +```ruby +result = TurboDocxSdk::TurboQuote.apply_price_book("quote-uuid", "pricebook-uuid") +# result["quote"] — updated Quote +# result["updatedCount"] — Integer, items that were re-priced +# result["skippedCount"] — Integer, items that had no pricebook match +# result["message"] +``` + @@ -1802,6 +2094,13 @@ Remove the applied price book from a quote, restoring original line item pricing Quote quote = tq.removePriceBook(quoteId); ``` + + + +```ruby +quote = TurboDocxSdk::TurboQuote.remove_price_book("quote-uuid") +``` + @@ -1880,6 +2179,16 @@ Files.write(Paths.get("quote.pdf"), pdf); --- + + + +Returns raw PDF bytes. + +```ruby +pdf_bytes = TurboDocxSdk::TurboQuote.download_quote_pdf("quote-uuid") +File.binwrite("quote.pdf", pdf_bytes) +``` + @@ -1953,6 +2262,17 @@ System.out.println(config.getFormat().getPrefix()); // e.g. "Q-" System.out.println(config.getCurrentFloor()); // the current per-period issued floor ``` + + + +Fetch the org's current quote numbering format and the current per-period issued floor. + +```ruby +config = TurboDocxSdk::TurboQuote.get_quote_number_config +puts config["format"]["prefix"] # e.g. "Q-" +puts config["currentFloor"] # the current per-period issued floor +``` + @@ -2065,6 +2385,27 @@ QuoteNumberConfig config = tq.updateQuoteNumberConfig(format); System.out.println(config.getFormat().getStartNumber()); // 1000 ``` + + + +Update the numbering format. Pass the full format hash; all eight fields are required. Keys stay camelCase. + +```ruby +config = TurboDocxSdk::TurboQuote.update_quote_number_config( + "prefix" => "INV", + "yearToken" => "none", # "none" | "two" | "four" + "monthToken" => "off", # "off" | "two" + "separator" => "-", + "padWidth" => 4, # 0–12 + "suffix" => "", + "startNumber" => 1000, # >= 0 + "resetCadence" => "never" # "never" | "yearly" | "monthly" +) +puts config["format"]["startNumber"] # 1000 +``` + +The SDK also exposes constants for the enum values: `TurboDocxSdk::QuoteNumberYearToken`, `TurboDocxSdk::QuoteNumberMonthToken`, and `TurboDocxSdk::QuoteNumberResetCadence`. + @@ -2208,6 +2549,32 @@ Beyond the per-field caps, the API rejects self-inconsistent formats with a `400 --- + + + +All eight `format` keys are sent on every update. The API enforces these caps and allowed values — a violation returns `400`: + +| Field | Type | Allowed / range | Default | +|-------|------|-----------------|---------| +| `prefix` | string | ≤ 12 characters | `"Q"` | +| `yearToken` | enum | `none` \| `two` \| `four` | `four` | +| `monthToken` | enum | `off` \| `two` | `off` | +| `separator` | string | ≤ 4 characters | `"-"` | +| `padWidth` | integer | `0`–`12` (`0` = no padding) | `5` | +| `suffix` | string | ≤ 12 characters | `""` | +| `startNumber` | integer | `0`–`1000000000` | `1` | +| `resetCadence` | enum | `never` \| `yearly` \| `monthly` | `yearly` | + +An org that has never configured numbering uses the **default format** above, which renders like `Q-2026-00001`. + +Beyond the per-field caps, the API rejects self-inconsistent formats with a `400`: + +- `resetCadence: "yearly"` requires a year token (`yearToken` other than `none`) — otherwise numbers repeat across years. +- `resetCadence: "monthly"` requires **both** a year token and a month token (`monthToken: "two"`). +- The rendered quote number must be ≤ 256 characters. + +`currentFloor` (returned by both methods) is read-only — the sequence the next quote will use for the current period — and is never sent on update. + @@ -2334,6 +2701,30 @@ handle-expired flow to void it and create a fresh draft. ::: + + + +:::caution Send preconditions + +Both send methods share the same server-side checks. Each is rejected with **HTTP 400** and a +specific error `code` before anything is created or emailed: + +| Condition | Code | +| :--- | :--- | +| Quote is not a draft | `QuoteNotSendable` | +| No `validUntil` date set | `QuoteValidUntilRequired` | +| `validUntil` is in the past | `QuoteExpired` | +| No line items | `QuoteHasNoLineItems` | +| Contact missing a name or email | `QuoteContactRequired` | +| Company or contact deleted/deactivated | `QuoteCustomerInactive` | +| No sender email resolvable (API-key callers) | `SenderEmailRequired` | + +A quote with **no line items cannot be sent** — add at least one product, bundle, or custom +line item first. Likewise an **expired quote is rejected**; update `validUntil`, or use the +handle-expired flow to void it and create a fresh draft. + +::: + @@ -2419,6 +2810,17 @@ SendQuoteResponse resp = tq.sendQuote(quoteId); System.out.println("Status: " + resp.getQuote().getStatus()); ``` + + + +```ruby +sent = TurboDocxSdk::TurboQuote.send_quote("quote-uuid", + "ccEmails" => ["manager@example.com"], + "validUntil" => "2026-09-30" +) +# sent["quote"], sent["message"] +``` + @@ -2510,6 +2912,19 @@ SendQuoteWithDeliverableResponse resp = tq.sendQuoteWithDeliverable(quoteId, req System.out.println("Document ID: " + resp.getDocumentId()); ``` + + + +Attach a TurboDocx-generated document to the sent quote. + +```ruby +result = TurboDocxSdk::TurboQuote.send_quote_with_deliverable("quote-uuid", + "deliverableId" => "deliverable-uuid", + "ccEmails" => ["manager@example.com"] +) +# result["quote"], result["message"], result["documentId"] +``` + @@ -2623,6 +3038,28 @@ tq.sendQuoteWithDeliverable(quoteId, scheduledReq); Each `Duration` is a `{value, unit}` pair (`unit` is `"hours"` or `"days"`, `value` a whole number from 1 up to 999 days / 23976 hours). + + + +`send_quote` and `send_quote_with_deliverable` accept the same reminder/expiration schedule as a TurboSign send — the eight `remindersEnabled` / `reminderDelay` / `reminderInterval` / `maxReminders` / `expirationEnabled` / `expireAfter` / `expirationWarning` / `expirationWarningInterval` keys, each duration a `{ "value" =>, "unit" => }` hash whose `"unit"` is `"days"` or `"hours"`. Both features are off by default. `maxReminders` is `-1` unlimited, `0` none, **max `50`**; `expirationWarning` may be `0` to never warn. + +```ruby +sent = TurboDocxSdk::TurboQuote.send_quote("quote-uuid", + "validUntil" => "2026-09-30", + "remindersEnabled" => true, + "reminderDelay" => { "value" => 3, "unit" => "days" }, + "reminderInterval" => { "value" => 3, "unit" => "days" }, + "maxReminders" => 5, + "expirationEnabled" => true, + "expirationWarning" => { "value" => 2, "unit" => "days" }, + "expirationWarningInterval" => { "value" => 1, "unit" => "days" } +) +``` + +:::warning Quote expiry is pinned to `validUntil` +Unlike a plain TurboSign send, a quote's signing deadline is **hard-pinned to the quote's `validUntil` date**. When expiration is on, `expireAfter` is **ignored** — the deadline is always `validUntil`. `expirationEnabled` still toggles expiry on or off. The reminder and expiry-warning cadence still applies, but every reminder and warning must fall **inside** the `validUntil` window; a cadence that would outlive it is rejected with a `400`. +::: + @@ -2711,6 +3148,20 @@ Quote declined = tq.declineQuote(quoteId, req); Quote closedOut = tq.declineQuote(draftQuoteId, new DeclineQuoteRequest()); ``` + + + +Declines a **sent** quote or a **draft**. `reason` (max 190 characters) is required once a quote has been sent. A draft is declined **without** a reason — a draft never reached the customer, and because the reason is stored on the linked signature document, a draft has nowhere to keep one, so anything passed is ignored. + +```ruby +quote = TurboDocxSdk::TurboQuote.decline_quote("quote-uuid", + "reason" => "Customer selected a competitor" +) + +# A draft is declined with no reason — one passed here would not be recorded. +closed_out = TurboDocxSdk::TurboQuote.decline_quote("draft-quote-uuid", {}) +``` + @@ -2780,6 +3231,17 @@ req.setReason("Replaced by new proposal"); Quote voided = tq.voidQuote(quoteId, req); ``` + + + +Voids a **sent** quote; a **draft cannot be voided**, since voiding an unsent quote is meaningless. + +```ruby +quote = TurboDocxSdk::TurboQuote.void_quote("quote-uuid", + "reason" => "Terms expired before acceptance" +) +``` + @@ -2927,6 +3389,33 @@ Unlike `duplicateQuote`, the draft this endpoint creates is **not** prefixed wit --- + + + +Handles a quote that has passed its `validUntil` date. The endpoint **closes out the original quote** — voiding or declining it depending on `action` — and then **creates a duplicate carrying `newValidUntil`** as its new validity date. The returned quote is the new duplicate; the original stays terminal. + +`action` (`"void"`, `"decline"` or `"renew"`) and `newValidUntil` (ISO date) are **required**. `reason` (max 190 characters) is required for `"void"` and `"decline"`, and optional for `"renew"` — a renewal closes nothing out, so there is nothing to give a reason for. Use `"renew"` when the quote's signature request has already expired on its own; use `"void"` or `"decline"` when the quote is merely past its `validUntil` and you are closing it yourself. + +```ruby +quote = TurboDocxSdk::TurboQuote.handle_expired_quote("quote-uuid", + "action" => "void", # required — "void", "decline" or "renew" + "reason" => "Quote expired", # required for void/decline, optional for renew + "newValidUntil" => "2026-12-31" # required — ISO date, carried onto the duplicate +) +``` + +:::warning There is no `extend` or `resend` action +`action` accepts **only** `"void"`, `"decline"` and `"renew"`. `"extend"` and `"resend"` do not exist in the API and return a `400`. Extending is what the endpoint already does — pass `newValidUntil` and it lands on the duplicate it creates. +::: + +:::info The replacement draft keeps the original name +Unlike `duplicate_quote`, the draft this endpoint creates is **not** prefixed with `Copy of ` — re-issuing the same deal keeps the original quote's name, so repeated renewals cannot compound into `Copy of Copy of …`. That matters because the next send snapshots the name onto the TurboSign document. +::: + +:::note Terminal statuses +`accepted`, `declined`, and `voided` are **terminal** — a quote in one of these states cannot be transitioned out of it, and any further status call returns a `400`. Check `quote["statusInfo"]` before attempting a transition, and use `duplicate_quote` when you need to revive a closed-out quote. +::: + @@ -3015,6 +3504,14 @@ items.getResults().forEach(i -> System.out.println(i.getProductName() + " x" + i.getQuantity())); ``` + + + +```ruby +page = TurboDocxSdk::TurboQuote.list_line_items("quote-uuid", "limit" => 50) +# page["results"], page["totalRecords"] +``` + @@ -3182,6 +3679,36 @@ List added = tq.addLineItems(quoteId, Arrays.asList(item, custom)); `addLineItems` accepts a single request **or** a list of 1–**50** items. A reorder request accepts up to **200** items. Exceeding either cap returns a `400`. ::: + + + +Accepts a single item hash **or** an array of up to **50** items. Returns an array of created line item hashes. + +`productId`, `productName`, `unitPrice`, and `billingFrequency` are all **required** on every row. `productId` is special: the key must be **present**, but its value may be `nil` for a custom (freeform) line item — omitting the key entirely returns a `400`. `quantity` is optional and defaults to `1`. + +```ruby +items = TurboDocxSdk::TurboQuote.add_line_items("quote-uuid", [ + { + "productId" => "product-uuid", # required key — nil for a custom line item + "productName" => "Platform License", + "quantity" => 2, + "unitPrice" => "199.00", + "billingFrequency" => "annual", + "discountPercent" => "10.0" + }, + { + "productId" => nil, # custom (freeform) line item — key still required + "productName" => "Implementation Credit", + "unitPrice" => "-250.00", + "billingFrequency" => "one-time" + } +]) +``` + +:::note Array caps +`add_line_items` accepts a single hash **or** an array of 1–**50** items. A reorder request accepts up to **200** items. Exceeding either cap returns a `400`. +::: + @@ -3271,6 +3798,21 @@ bundleItem.setQuantity(2.0); List added = tq.addBundleLineItems(quoteId, bundleItem); ``` + + + +`bundleId` and `bundleName` are both **required**; the server expands the bundle's child products for you. Accepts a single hash or an array of up to **50** items. + +```ruby +items = TurboDocxSdk::TurboQuote.add_bundle_line_items("quote-uuid", [ + { + "bundleId" => "bundle-uuid", + "bundleName" => "Starter Bundle", # required + "quantity" => 1 + } +]) +``` + @@ -3342,6 +3884,16 @@ req.setDiscountPercent(15.0); LineItem updated = tq.updateLineItem(quoteId, itemId, req); ``` + + + +```ruby +item = TurboDocxSdk::TurboQuote.update_line_item("quote-uuid", "item-uuid", + "quantity" => 5, + "unitPrice" => "179.00" +) +``` + @@ -3402,6 +3954,14 @@ tq.removeLineItem(quoteId, itemId); --- + + + +```ruby +result = TurboDocxSdk::TurboQuote.remove_line_item("quote-uuid", "item-uuid") +# result["message"] +``` + @@ -3603,6 +4163,56 @@ When `CreateProductRequest.getImages()` is non-empty, the SDK automatically swit --- + + + +| Method | Signature | Returns | +|---|---|---| +| `list_products` | `(options = nil)` | paginated list | +| `create_product` | `(request)` | `Product` | +| `bulk_create_products` | `(rows)` | [bulk report](#bulk-imports) | +| `get_product` | `(id)` | `Product` | +| `update_product` | `(id, request)` | `Product` | +| `delete_product` | `(id)` | `{"message" => ...}` | +| `duplicate_product` | `(id)` | `Product` | +| `get_product_primary_images` | `(product_ids)` | `{id => image or nil}` | + +:::caution `categoryId` is required on create +`create_product` **requires** `name`, `categoryId`, `listPrice`, and `billingFrequency`. `categoryId` must be the **UUID** of an existing type (`categoryType` `"product_category"`) — resolve or create it first with `list_types` / `create_type`. It is optional on `update_product`, so you only need to pass it when creating. +::: + +```ruby +# Resolve the product category first — create_product needs its UUID. +page = TurboDocxSdk::TurboQuote.list_types("categoryType" => "product_category") +category = page["results"].find { |t| t["name"] == "Software" } +category ||= TurboDocxSdk::TurboQuote.create_type( + "name" => "Software", + "categoryType" => "product_category" +) + +# Create a product with images (multipart upload auto-detected) +product = TurboDocxSdk::TurboQuote.create_product( + "name" => "Enterprise License", + "categoryId" => category["id"], # required + "listPrice" => "499.00", + "cost" => "200.00", + "billingFrequency" => "annual", + "showInCatalog" => true, + "images" => ["/path/to/product-photo.png"] # file path(s) or IO objects +) + +# List products with filters +page = TurboDocxSdk::TurboQuote.list_products( + "limit" => 20, + "query" => "enterprise", + "showInCatalog" => true +) + +# Bulk fetch primary images for a set of product IDs +images = TurboDocxSdk::TurboQuote.get_product_primary_images(["id-1", "id-2", "id-3"]) +# images["id-1"] → ProductImage hash, or nil +``` + @@ -3931,6 +4541,44 @@ Bundle bundle = tq.createBundle(req); --- + + + +| Method | Signature | Returns | +|---|---|---| +| `list_bundles` | `(options = nil)` | paginated list | +| `create_bundle` | `(request)` | `Bundle` | +| `bulk_create_bundles` | `(rows)` | [bulk report](#bulk-imports) | +| `get_bundle` | `(id)` | `Bundle` | +| `update_bundle` | `(id, request)` | `Bundle` | +| `delete_bundle` | `(id)` | `{"message" => ...}` | +| `duplicate_bundle` | `(id)` | `Bundle` | + +Each entry in `items` **requires** `productId`, `unitPrice`, and `billingFrequency`. `quantity` is optional and defaults to `1`. + +```ruby +bundle = TurboDocxSdk::TurboQuote.create_bundle( + "name" => "Starter Pack", + "categoryId" => "bundle-category-uuid", # required + "items" => [ + { + "productId" => "product-uuid-1", + "unitPrice" => "199.00", + "billingFrequency" => "monthly", + "quantity" => 1 + }, + { + "productId" => "product-uuid-2", + "unitPrice" => "49.00", + "billingFrequency" => "monthly", + "quantity" => 2 + } + ], + "bundleDiscountType" => "percent", + "bundleDiscountAmount" => 5 +) +``` + @@ -4130,6 +4778,40 @@ System.out.println("Products: " + pbProducts.getTotalRecords()); --- + + + +| Method | Signature | Returns | +|---|---|---| +| `list_price_books` | `(options = nil)` | paginated list | +| `create_price_book` | `(request)` | `PriceBook` | +| `bulk_create_price_books` | `(rows)` | [bulk report](#bulk-imports) | +| `get_price_book` | `(id)` | `PriceBook` | +| `update_price_book` | `(id, request)` | `PriceBook` | +| `delete_price_book` | `(id)` | `{"message" => ...}` | +| `duplicate_price_book` | `(id)` | `PriceBook` | +| `list_price_book_products` | `(id, options = nil)` | paginated list | + +```ruby +# name, priceBookTypeId, and validFrom are REQUIRED. +# discountPercent is optional and defaults to 0 if not provided. +# priceBookTypeId comes from a create_type with categoryType "pricebook_type". +pricebook = TurboDocxSdk::TurboQuote.create_price_book( + "name" => "Partner Tier A", + "priceBookTypeId" => "pricebook-type-uuid", + "validFrom" => "2026-01-01", + "discountPercent" => 15, + "isDefault" => false, + "productPricing" => [ + { "productId" => "product-uuid-1", "discountType" => "percent", "discountPercent" => 25 }, + { "productId" => "product-uuid-2", "discountType" => "percent", "discountPercent" => 30 } + ] +) + +# List products attached to a price book +page = TurboDocxSdk::TurboQuote.list_price_book_products("pricebook-uuid", "limit" => 50) +``` + @@ -4303,6 +4985,39 @@ String contactId = contacts.getResults().get(0).getId(); --- + + + +| Method | Signature | Returns | +|---|---|---| +| `list_companies` | `(options = nil)` | paginated list | +| `create_company` | `(request)` | `Company` | +| `bulk_create_companies` | `(rows)` | [bulk report](#bulk-imports) | +| `get_company` | `(id)` | `Company` | +| `update_company` | `(id, request)` | `Company` | +| `delete_company` | `(id)` | `{"message" => ...}` | +| `list_company_contacts` | `(company_id, options = nil)` | paginated list | + +```ruby +company = TurboDocxSdk::TurboQuote.create_company( + "name" => "Acme Corporation", + "phone" => "+1-555-0100", + "city" => "San Francisco", + "state" => "CA", + "country" => "US", + "contacts" => [ # at least one contact required; each needs name + email + { + "name" => "Jane Doe", + "email" => "jane@acme.com", + "title" => "VP of Engineering" + } + ] +) + +# List contacts for a company +contacts = TurboDocxSdk::TurboQuote.list_company_contacts(company["id"]) +``` + @@ -4445,6 +5160,29 @@ Contact contact = tq.createContact(req); --- + + + +| Method | Signature | Returns | +|---|---|---| +| `list_contacts` | `(options = nil)` | paginated list | +| `create_contact` | `(request)` | `Contact` | +| `bulk_create_contacts` | `(rows)` | [bulk report](#bulk-imports) | +| `update_contact` | `(id, request)` | `Contact` | +| `delete_contact` | `(id)` | `{"message" => ...}` | + +:::note No `get_contact` by design +The backend has no `GET /v1/contacts/:id` endpoint. Fetch individual contacts via `list_company_contacts` or `list_contacts` with a query filter. +::: + +```ruby +contact = TurboDocxSdk::TurboQuote.create_contact( + "name" => "John Smith", + "email" => "john@acme.com", + "companyId" => "company-uuid" +) +``` + @@ -4637,6 +5375,42 @@ QuoteTemplateListResponse templates = tq.listTemplates(); --- + + + +| Method | Signature | Returns | +|---|---|---| +| `list_templates` | `(options = nil)` | paginated list | +| `get_template` | `()` | singleton `QuoteTemplate` — auto-created if none exists | +| `get_template_by_id` | `(id)` | `QuoteTemplate` | +| `create_template` | `(request)` | `QuoteTemplate` — `400` if one already exists | +| `update_template` | `(id, request)` | `QuoteTemplate` | +| `delete_template` | `(id)` | `{"message" => ...}` — resets to org branding defaults | + +:::warning Templates are auto-provisioned — use `get_template` → `update_template` +`get_template` **self-heals**: if the org has no template, the API creates one from your org branding and returns it. Every established org therefore already has a template, which means: + +- `create_template` returns **400 `TEMPLATE_ALREADY_EXISTS`** and is effectively unreachable. Do not build a get-then-create flow. +- `delete_template` is really "reset to org branding defaults" — it soft-deletes, and the next `get_template` regenerates a fresh one. + +The correct flow is **`get_template` → `update_template`**. +::: + +```ruby +# 1. Get the org's quote template (created from org branding on first read) +template = TurboDocxSdk::TurboQuote.get_template + +# 2. Brand it by updating the template you just fetched +branded = TurboDocxSdk::TurboQuote.update_template(template["id"], + "logoUrl" => "https://cdn.example.com/logo.png", + "primaryColor" => "#0057b8", + "senderName" => "TurboDocx Sales" +) + +# Get a specific named template by ID +other = TurboDocxSdk::TurboQuote.get_template_by_id("template-uuid") +``` + @@ -4850,6 +5624,27 @@ There is no `getType(id)` method — the backend has no `GET /v1/types/:id` endp --- + + + +| Method | Signature | Returns | +|---|---|---| +| `list_types` | `(options = nil)` | paginated list | +| `create_type` | `(request)` | `QuoteType` | +| `bulk_create_types` | `(rows)` | [bulk report](#bulk-imports) | +| `update_type` | `(id, request)` | `QuoteType` | +| `delete_type` | `(id)` | `{"message" => ...}` | + +:::note No `get_type` by design +The backend has no `GET /v1/types/:id` endpoint. Use `list_types` to retrieve individual type records. +::: + +```ruby +quote_type = TurboDocxSdk::TurboQuote.create_type("name" => "New Business") + +TurboDocxSdk::TurboQuote.update_type(quote_type["id"], "name" => "New Logo Business") +``` + @@ -5128,6 +5923,81 @@ Rows process sequentially with **partial success** — a failed row does not thr Requests are capped at **500 rows** — anything above the cap returns a `400`. Available to admin and contributor API keys. + + + +Six methods import many records in one request — ideal for CSV-style migrations: + +| Method | Endpoint | Row shape | +|---|---|---| +| `bulk_create_products` | `POST /v1/products/bulk` | same fields as `create_product` | +| `bulk_create_price_books` | `POST /v1/pricebooks/bulk` | same fields as `create_price_book` | +| `bulk_create_bundles` | `POST /v1/bundles/bulk` | same fields as `create_bundle` | +| `bulk_create_companies` | `POST /v1/companies/bulk` | same fields as `create_company` — each row **requires a `contacts` array with at least one contact** | +| `bulk_create_contacts` | `POST /v1/contacts/bulk` | same fields as `create_contact` — each row **requires a `companyId`** | +| `bulk_create_types` | `POST /v1/types/bulk` | same fields as `create_type` | + +Each method takes an array of row hashes; the SDK wraps them in the `{ "rows" => [...] }` envelope the endpoint expects. Rows use the exact request shape of the corresponding single-create method (camelCase keys). + +:::caution Product rows require a real `categoryId` +Every `bulk_create_products` row **requires** `name`, `categoryId`, `listPrice`, and `billingFrequency`. `categoryId` must be the **UUID** of an existing type (`categoryType` `"product_category"`) — there is no `categoryName` key on the bulk row schema, and the API rejects unknown keys, so passing one returns a `400`. Resolve or create the category first with `list_types` / `create_type`, then pass its `"id"`. +::: + +```ruby +# 1. Resolve the product category first — bulk rows need its UUID, not its name. +page = TurboDocxSdk::TurboQuote.list_types("categoryType" => "product_category") +category = page["results"].find { |t| t["name"] == "Software" } +category ||= TurboDocxSdk::TurboQuote.create_type( + "name" => "Software", + "categoryType" => "product_category" +) +category_id = category["id"] + +# 2. Import, passing the resolved UUID on every row. +report = TurboDocxSdk::TurboQuote.bulk_create_products([ + { "name" => "Starter License", "categoryId" => category_id, "listPrice" => "99.00", "billingFrequency" => "monthly" }, + { "name" => "Pro License", "categoryId" => category_id, "listPrice" => "299.00", "billingFrequency" => "monthly" }, + { "name" => "Enterprise License", "categoryId" => category_id, "listPrice" => "499.00", "billingFrequency" => "annual" } +]) + +puts "Imported #{report['imported']} rows" +report["failed"].each do |failure| + puts "Row #{failure['row']} failed: #{failure['reason']}" # "row" is 1-indexed +end +report["adjusted"].each do |adjustment| + puts "Row #{adjustment['row']} adjusted: #{adjustment['reason']}" +end +``` + +**Partial-success semantics** — every bulk method returns the same report hash instead of raising for bad rows: + +| Key | Type | Meaning | +|---|---|---| +| `imported` | Integer | Rows created successfully | +| `failed` | Array of `{"row", "reason"}` | Rows the server rejected — `row` is the **1-indexed** position in your input array | +| `adjusted` | Array of `{"row", "reason"}` | Rows the server imported after modifying them (e.g. a bundle item whose product wasn't found was dropped) | + +Rules and limits: + +- **A failed row does not raise** and does not roll back earlier rows — always check `report["failed"]` after the call. +- **Max 500 rows per request.** Exceeding the cap fails the whole request with a `400` (`TurboDocxSdk::ValidationError`); an invalid envelope (e.g. non-array input) also raises `ValidationError`. +- **Roles:** available to **administrator and contributor** API keys. +- The SDK performs no client-side row validation — errors come back per-row in the report. + +```ruby +# Companies need >= 1 contact per row; contacts need a companyId per row +TurboDocxSdk::TurboQuote.bulk_create_companies([ + { + "name" => "Acme Corporation", + "contacts" => [{ "name" => "Jane Doe", "email" => "jane@acme.com" }] + } +]) + +TurboDocxSdk::TurboQuote.bulk_create_contacts([ + { "name" => "John Smith", "email" => "john@acme.com", "companyId" => "company-uuid" } +]) +``` + @@ -5226,6 +6096,23 @@ The other five bulk methods follow the exact same pattern: --- + + + +The gem exposes constants so you can avoid hard-coding string literals: + +```ruby +TurboDocxSdk::QuoteStatus::DRAFT # "draft" +TurboDocxSdk::QuoteStatus::SENT # "sent" +TurboDocxSdk::BillingFrequency::MONTHLY # "monthly" +TurboDocxSdk::BillingFrequency::ANNUAL # "annual" +TurboDocxSdk::DiscountType::PERCENT # "percent" +TurboDocxSdk::DiscountType::AMOUNT # "amount" +TurboDocxSdk::Currency::USD # "USD" +TurboDocxSdk::LineItemType::PRODUCT # "product" +TurboDocxSdk::CategoryType::PRICEBOOK_TYPE # "pricebook_type" +``` + @@ -5371,6 +6258,35 @@ System.out.println("Quote: " + result.getQuote().getId()); --- + + + +Orchestrates multiple API calls: create quote → add product items → add bundle items → send. Returns `{ "quote" => }`. + +```ruby +result = TurboDocxSdk::TurboQuote.create_and_send( + # CreateQuote fields + "name" => "Year-End Renewal", + "companyId" => "company-uuid", + "contactId" => "contact-uuid", + "currency" => "USD", + # optional line items added before send + "items" => [ + { "productId" => "product-uuid-1", "productName" => "Platform License", "quantity" => 10, "unitPrice" => "99.00", "billingFrequency" => "monthly" } + ], + # optional bundle items added before send + "bundleItems" => [ + { "bundleId" => "bundle-uuid-1", "bundleName" => "Starter Pack", "quantity" => 1 } + ], + # send options (ccEmails, validUntil) + "send" => { + "ccEmails" => ["finance@example.com"], + "validUntil" => "2026-12-31" + } +) +puts result["quote"]["id"] +``` + @@ -5665,6 +6581,38 @@ try { } ``` + + + +```ruby +require "turbodocx_sdk" + +begin + quote = TurboDocxSdk::TurboQuote.create_quote( + "name" => "Q3 Proposal", + "companyId" => "company-uuid", + "contactId" => "contact-uuid" + ) +rescue TurboDocxSdk::ValidationError => e + # 400 — missing required fields, invalid enum value, etc. + puts "Validation failed: #{e.message}" +rescue TurboDocxSdk::AuthenticationError + # 401 — bad or revoked API key +rescue TurboDocxSdk::AuthorizationError + # 403 — key valid but lacks permission for this org/action +rescue TurboDocxSdk::NotFoundError => e + # 404 — company, contact, or product not found + puts "Not found: #{e.message}" +rescue TurboDocxSdk::RateLimitError + # 429 — back off and retry +rescue TurboDocxSdk::NetworkError + # request never reached the server (DNS, refused, timeout) +rescue TurboDocxSdk::TurboDocxError => e + # catch-all for any other typed SDK error (raw 5xx, etc.) + puts "Error #{e.status_code}: #{e.message}" +end +``` + @@ -5739,6 +6687,18 @@ try { | 404 | `TurboDocxException.NotFoundException` | Quote, product, company, contact, etc. not found | | 429 | `TurboDocxException.RateLimitException` | Rate limit exceeded — back off and retry | + + + +| Status | Class | When | +|---|---|---| +| 400 | `ValidationError` | Invalid fields, missing required keys, bad enum value | +| 401 | `AuthenticationError` | Missing or invalid API key | +| 403 | `AuthorizationError` | Valid key without permission for this operation | +| 404 | `NotFoundError` | Quote, product, company, or other resource not found | +| 409 | `ConflictError` | Duplicate resource (e.g., company domain conflict) | +| 429 | `RateLimitError` | Rate limit exceeded — back off | + @@ -5776,6 +6736,23 @@ Three fully runnable examples live in the SDK repo: Run any example after exporting `TURBODOCX_API_KEY` and `TURBODOCX_ORG_ID`. + + + +Three runnable examples live in the SDK repo: + +- **[`turboquote_basic.rb`](https://github.com/TurboDocx/SDK/blob/main/packages/ruby-sdk/examples/turboquote_basic.rb)** — full quote lifecycle: create a company and contact, create a quote, add line items, download the PDF, send, clean up. +- **[`turboquote_products.rb`](https://github.com/TurboDocx/SDK/blob/main/packages/ruby-sdk/examples/turboquote_products.rb)** — product and bundle catalog management. +- **[`turboquote_pricebooks.rb`](https://github.com/TurboDocx/SDK/blob/main/packages/ruby-sdk/examples/turboquote_pricebooks.rb)** — price book CRUD, `apply_price_book`, and optional `send_quote_with_deliverable` (set the `DELIVERABLE_ID` env var). + +Run any example with: + +```bash +export TURBODOCX_API_KEY=your_key +export TURBODOCX_ORG_ID=your_org_id +ruby examples/turboquote_basic.rb +``` + @@ -5835,5 +6812,17 @@ Run any example after exporting `TURBODOCX_API_KEY` and `TURBODOCX_ORG_ID`. - [SDKs Overview](/docs/SDKs) — all SDKs across all languages - [TurboDocx SDK on GitHub](https://github.com/TurboDocx/SDK/tree/main/packages/java-sdk) + + + +- [TurboQuote JavaScript / TypeScript SDK](/docs/SDKs/quote?language=js) — same API, JS idioms +- [TurboQuote Python SDK](/docs/SDKs/quote?language=python) — same API, Python idioms +- [TurboSign Ruby SDK](/docs/SDKs/turbosign?language=ruby) — send documents for e-signature +- [TurboWebhooks Ruby SDK](/docs/SDKs/webhooks?language=ruby) — receive real-time signature events +- [Deliverable Ruby SDK](/docs/SDKs/deliverable?language=ruby) — generate documents from templates +- [SDKs Overview](/docs/SDKs) — all SDKs across all languages +- [turbodocx-sdk on RubyGems](https://rubygems.org/gems/turbodocx-sdk) +- [TurboDocx SDK on GitHub](https://github.com/TurboDocx/SDK/tree/main/packages/ruby-sdk) + diff --git a/docs/SDKs/ruby.md b/docs/SDKs/ruby.md index 14714059..155435bd 100644 --- a/docs/SDKs/ruby.md +++ b/docs/SDKs/ruby.md @@ -1,26 +1,23 @@ --- -# Hidden from the published site: the turbodocx-sdk gem is not on RubyGems yet. -# Remove `draft: true` when the gem is published (TurboDocx/SDK issue). -draft: true -title: TurboSign Ruby SDK +title: TurboDocx Ruby SDK sidebar_position: 7 -sidebar_label: "TurboSign: Ruby" -description: Official TurboDocx Ruby SDK. Simple synchronous API for document generation and digital signatures from Ruby, Rails, and Sinatra. +sidebar_label: Ruby +description: Install and configure the TurboDocx Ruby SDK, then open the TurboSign, Deliverable, TurboWebhooks or TurboQuote guide. keywords: - - turbodocx ruby - - turbosign ruby - - ruby sdk - - gem turbodocx - - rails turbodocx - - sinatra turbodocx - - document api ruby +- turbodocx ruby +- turbosign ruby +- ruby sdk +- gem turbodocx +- rails turbodocx +- sinatra turbodocx +- document api ruby --- import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; import QuickstartSkillNudge from '@site/src/components/QuickstartSkillNudge'; -# TurboSign Ruby SDK +# TurboDocx Ruby SDK @@ -90,658 +87,19 @@ TURBODOCX_SENDER_NAME=Your Company ``` :::warning API Credentials Required -`api_key` and `org_id` are **required** for all API requests. TurboSign additionally **requires `sender_email`** (set it on `configure`, per call, or via the `TURBODOCX_SENDER_EMAIL` environment variable) — `configure` raises a `TurboDocxSdk::ValidationError` without it. `sender_name` is optional but strongly recommended. To get your credentials, follow the **[Get Your Credentials](/docs/SDKs#1-get-your-credentials)** steps from the SDKs main page. +`api_key` and `org_id` are **required** for all API requests. TurboSign additionally **requires `sender_email`** (set it on `configure`, per call, or via the `TURBODOCX_SENDER_EMAIL` environment variable): `configure` raises a `TurboDocxSdk::ValidationError` without it. `sender_name` is optional but strongly recommended. To get your credentials, follow the **[Get Your Credentials](/docs/SDKs#1-get-your-credentials)** steps from the SDKs main page. ::: --- -## Quick Start +## Product guides -### Send a Document for Signature +Each product guide opens on the Ruby tab: -```ruby -require "turbodocx_sdk" - -TurboDocxSdk::TurboSign.configure( - api_key: ENV["TURBODOCX_API_KEY"], - org_id: ENV["TURBODOCX_ORG_ID"], - sender_email: "contracts@acme.com", - sender_name: "Acme Corp" -) - -result = TurboDocxSdk::TurboSign.send_signature( - # Request-hash keys are camelCase — the SDK forwards them to the API verbatim - recipients: [ - { name: "Alice Smith", email: "alice@example.com", signingOrder: 1 }, - { name: "Bob Johnson", email: "bob@example.com", signingOrder: 2 } - ], - fields: [ - # Alice's signature - { type: "signature", page: 1, x: 100, y: 650, width: 200, height: 50, recipientEmail: "alice@example.com" }, - { type: "date", page: 1, x: 320, y: 650, width: 100, height: 30, recipientEmail: "alice@example.com" }, - # Bob's signature - { type: "signature", page: 1, x: 100, y: 720, width: 200, height: 50, recipientEmail: "bob@example.com" }, - { type: "date", page: 1, x: 320, y: 720, width: 100, height: 30, recipientEmail: "bob@example.com" } - ], - fileLink: "https://www.turbodocx.com/examples/turbodocx.pdf", - documentName: "Service Agreement", - senderName: "Acme Corp", - senderEmail: "contracts@acme.com" -) - -puts JSON.pretty_generate(result) -``` - -### Using Template-Based Fields - -```ruby -result = TurboDocxSdk::TurboSign.send_signature( - recipients: [{ name: "Alice Smith", email: "alice@example.com", signingOrder: 1 }], - fields: [ - { - type: "signature", - recipientEmail: "alice@example.com", - template: { - anchor: "{SIGNATURE_ALICE}", - placement: "replace", - size: { width: 200, height: 50 } - } - }, - { - type: "date", - recipientEmail: "alice@example.com", - # Pins a fixed date in MM/DD/YYYY; omit to auto-fill the signing date - defaultValue: "12/31/2026", - template: { - anchor: "{DATE_ALICE}", - placement: "replace", - size: { width: 100, height: 30 } - } - } - ], - fileLink: "https://www.turbodocx.com/examples/turbodocx.pdf" -) - -puts JSON.pretty_generate(result) -``` - -:::info Template Anchors Required -**Important:** The document file must contain the anchor text (e.g., `{SIGNATURE_ALICE}`, `{DATE_ALICE}`) that you reference in your fields. If the anchors don't exist in the document, the API will return an error. -::: - ---- - -## File Input Methods - -TurboSign supports four different ways to provide document files: - -:::note camelCase request keys -The keys inside the request hash (`fileLink`, `deliverableId`, `templateId`, `documentName`, `recipientEmail`, `signingOrder`, …) are **camelCase** — the SDK passes them to the API verbatim and does **not** convert snake_case hash keys. Only the method keyword arguments on `configure` (`api_key:`, `sender_email:`, …) are snake_case. -::: - -### 1. File Upload (path or IO) - -Pass a local file path (`String`) or any IO object (e.g., `File.open`, `StringIO`) — the SDK uploads it as multipart form data and detects the file type from magic bytes. - -```ruby -result = TurboDocxSdk::TurboSign.send_signature( - file: "./contract.pdf", # local path — or an IO: File.open("./contract.pdf", "rb") - recipients: [ - { name: "John Doe", email: "john@example.com", signingOrder: 1 } - ], - fields: [ - { - type: "signature", - page: 1, - x: 100, - y: 650, - width: 200, - height: 50, - recipientEmail: "john@example.com" - } - ] -) -``` - -### 2. File URL (fileLink) - -```ruby -result = TurboDocxSdk::TurboSign.send_signature( - fileLink: "https://www.turbodocx.com/examples/turbodocx.pdf", - recipients: [ - { name: "John Doe", email: "john@example.com", signingOrder: 1 } - ], - fields: [ - { - type: "signature", - page: 1, - x: 100, - y: 650, - width: 200, - height: 50, - recipientEmail: "john@example.com" - } - ] -) -``` - -:::tip When to use fileLink -Use `fileLink` when your documents are already hosted on cloud storage (S3, Google Cloud Storage, etc.). This is more efficient than downloading and re-uploading files. -::: - -### 3. TurboDocx Deliverable ID - -```ruby -# Use a previously generated TurboDocx document -result = TurboDocxSdk::TurboSign.send_signature( - deliverableId: "deliverable-uuid-from-turbodocx", - recipients: [ - { name: "John Doe", email: "john@example.com", signingOrder: 1 } - ], - fields: [ - { - type: "signature", - page: 1, - x: 100, - y: 650, - width: 200, - height: 50, - recipientEmail: "john@example.com" - } - ] -) -``` - -:::info Integration with TurboDocx -`deliverableId` references documents generated using TurboDocx's document generation API. This creates a seamless workflow: generate → sign. -::: - -### 4. TurboDocx Template ID - -```ruby -# Use a pre-configured TurboSign template -result = TurboDocxSdk::TurboSign.send_signature( - templateId: "template-uuid-from-turbodocx", # Template already contains anchors - recipients: [ - { name: "Alice Smith", email: "alice@example.com", signingOrder: 1 } - ], - fields: [ - { - type: "signature", - recipientEmail: "alice@example.com", - template: { - anchor: "{SIGNATURE_ALICE}", - placement: "replace", - size: { width: 200, height: 50 } - } - } - ] -) -``` - -:::info Integration with TurboDocx -`templateId` references pre-configured TurboSign templates created in the TurboDocx dashboard. These templates come with built-in anchors and field positioning, making it easy to reuse signature workflows across multiple documents. -::: - -### 5. Send a template set up in TurboDocx - -Upload a PDF as a template in TurboDocx, add its signers as roles (for example "Client" and "Countersigner"), drag their fields onto the page and save the signature setup. Then send it by naming each recipient's `role`. The fields saved for that role come with it, so `fields` can be left out, and a recipient with a `role` needs no `signingOrder`. - -```ruby -# The role keys come from the template (also shown under "Use via API" on the template page) -setup = TurboDocxSdk::TurboSign.get_template_signature_setup("your-template-id") -setup["roles"].each { |r| puts "#{r['key']} (saved signer: #{r['hasSavedSigner']})" } -# client (saved signer: false) -# countersigner (saved signer: true) - -TurboDocxSdk::TurboSign.send_signature( - templateId: "your-template-id", - recipients: [ - { role: "client", name: "Jane Doe", email: "jane@client.com" } - # "countersigner" left out: the signer saved on the template is used - ] -) -``` - -- Roles sign in the order saved on the template; recipients without a `role` sign after them. -- A role left out uses the template's saved signer. If it has none, the API returns a 400 naming the role. -- An unknown role raises `TurboDocxSdk::ValidationError` listing the template's roles (`e.code == "UnknownSignerRole"`). -- Any `fields` you pass are added to the template's (for example an extra witness signature). -- `role` works the same way on `create_signature_review_link` and `create_embedded_signature`. - -See [Sending with signer roles](/docs/TurboSign/API-Signatures#sending-with-signer-roles) for every rule and error. - ---- - -## API Reference - -All methods are class-level: call `TurboDocxSdk::TurboSign.configure` once, then invoke any method directly on the class. Every method is synchronous and returns a plain `Hash` (or raw bytes for downloads). - -### Configure - -Configure the SDK with your API credentials and organization settings. - -```ruby -TurboDocxSdk::TurboSign.configure( - api_key: "your-api-key", # Required: Your TurboDocx API key - org_id: "your-org-id", # Required: Your organization ID - sender_email: "you@company.com", # Required: Reply-to address for signature emails - sender_name: "Your Company", # Recommended: Sender name shown in emails - base_url: "https://api.turbodocx.com" # Optional: API base URL -) -``` - -### Prepare for review - -Upload a document for preview without sending signature request emails. - -```ruby -result = TurboDocxSdk::TurboSign.create_signature_review_link( - recipients: [{ name: "John Doe", email: "john@example.com", signingOrder: 1 }], - fields: [{ type: "signature", page: 1, x: 100, y: 500, width: 200, height: 50, recipientEmail: "john@example.com" }], - fileLink: "https://www.turbodocx.com/examples/turbodocx.pdf", - documentName: "Contract Draft" -) - -puts result["documentId"] -puts result["previewUrl"] -``` - -### Prepare for signing - -Upload a document and immediately send signature requests to all recipients. - -```ruby -result = TurboDocxSdk::TurboSign.send_signature( - recipients: [{ name: "Recipient Name", email: "recipient@example.com", signingOrder: 1 }], - fields: [{ type: "signature", page: 1, x: 100, y: 500, width: 200, height: 50, recipientEmail: "recipient@example.com" }], - fileLink: "https://www.turbodocx.com/examples/turbodocx.pdf", - documentName: "Service Agreement", - senderName: "Your Company", - senderEmail: "sender@company.com" -) - -puts result["documentId"] -``` - -### Reminders and expiration - -`send_signature` accepts an optional per-document schedule. Both reminders and expiration are **off by default**, so omitting these keys preserves the original send behavior. Keys are camelCase like every other send key, and each duration is a `{ value:, unit: }` hash whose `unit` is `"days"` or `"hours"`. - -```ruby -result = TurboDocxSdk::TurboSign.send_signature( - recipients: [{ name: "Recipient Name", email: "recipient@example.com", signingOrder: 1 }], - fields: [{ type: "signature", page: 1, x: 100, y: 500, width: 200, height: 50, recipientEmail: "recipient@example.com" }], - fileLink: "https://www.turbodocx.com/examples/turbodocx.pdf", - documentName: "Service Agreement", - - # Reminders — chase signers who haven't signed yet - remindersEnabled: true, - reminderDelay: { value: 3, unit: "days" }, # time to the FIRST reminder - reminderInterval: { value: 3, unit: "days" }, # gap between later reminders - maxReminders: 5, # -1 unlimited, 0 none, max 50 (default 5) - - # Expiration — close the signing window - expirationEnabled: true, - expireAfter: { value: 14, unit: "days" }, # how long it stays signable - expirationWarning: { value: 3, unit: "days" }, # lead time before warnings (0 = never warn) - expirationWarningInterval: { value: 1, unit: "days" } -) -``` - -| Field | Bounds | -| --- | --- | -| `maxReminders` | Cap per signer: `-1` unlimited, `0` none, **max `50`** (default `5`). | -| any duration `value` | Whole number, **min 1**, **max 999 days (23976 hours)**. | -| `expirationWarning` | May be `0` to never warn. | - -The resolved deadline is **frozen onto the document at send time** and is then readable via `get_status(...)["expiresAt"]`. - -### Get status - -Retrieve the current status of a document. The `status` reaches the terminal value `"expired"` once the signing window closes, and `expiresAt` carries the deadline (ISO 8601, `nil` when expiration is off). For per-signer detail, use [Get recipients](#get-recipients). - -```ruby -result = TurboDocxSdk::TurboSign.get_status("document-uuid") - -puts result["status"] # "under_review" | "completed" | "voided" | "expired" | ... -puts result["expiresAt"] # ISO 8601 deadline, or nil when expiration is off - -puts JSON.pretty_generate(result) -``` - -### Get recipients - -See who the document went to, who has signed, who you are still waiting on, -and who sent it. - -```ruby -result = TurboDocxSdk::TurboSign.get_recipients("document-uuid") - -summary = result["summary"] -puts "#{summary['completed']}/#{summary['total']} signed, waiting on #{summary['waitingOn']}" - -result["recipients"].each do |r| - puts "#{r['name']} <#{r['email']}>: #{r['effectiveStatus']} " \ - "(emailed #{r['delivery']['totalSent']}x)" -end -``` - -:::tip Two status fields, and they differ on purpose - -`status` is the raw database value and is only ever `pending`, `viewed` or `completed`. -`effectiveStatus` layers the document's outcome on top, adding `voided` and `expired` — that -is the one to display. - -On a voided or expired document an unsigned signer still reads `pending` in `status`, so -branching on it would show someone as "still to sign" when their signing link is already dead. -A completed signature is never revoked: someone who signed before the document was voided -still reads `completed`. - -`summary` counts by `effectiveStatus`, and `waitingOn` (pending + viewed) drops to zero once -the document is terminal. - -::: - -Each recipient also carries a `delivery` block — `firstSentOn`, `lastSentOn`, `totalSent`, -`reminderCount`, `lastRemindedAt`, `warningCount`, `lastWarningAt`. It counts the signature -request, resends, reminders, expiry warnings and terminal notices; CC notifications are -excluded, since a CC address is not a signer. - -:::warning `reminderCount` and `lastRemindedAt` do not mean what their names suggest - -`reminderCount` counts **automatic (scheduled) reminders only** — the counter `maxReminders` -caps. A manual "remind now" is a standalone nudge that must not consume the cap budget, so it -does **not** increment this, even though the email it sends *does* appear in `totalSent`. - -`lastRemindedAt` is a **cadence clock**, not a record of a reminder: the initial -signature-request send, each scheduled reminder, each manual "remind now" and each expiry -warning all stamp it. Only scheduled reminders bump `reminderCount`. - -So a freshly-sent document returns a non-null `lastRemindedAt` equal to the invitation -timestamp alongside `reminderCount: 0` — nobody has been reminded. To answer "have we actually -chased this person", read `totalSent`, not `reminderCount`. - -`warningCount` / `lastWarningAt` have no such caveat. - -::: - -### Download document - -Download the completed signed document as PDF bytes. - -```ruby -pdf_bytes = TurboDocxSdk::TurboSign.download("document-uuid") - -# Save to file -File.binwrite("signed-contract.pdf", pdf_bytes) -``` - -### Void - -Cancel/void a signature request. - -```ruby -result = TurboDocxSdk::TurboSign.void_document("document-uuid", "Contract terms changed") -``` - -### Resend - -Resend signature request emails to specific recipients. - -```ruby -result = TurboDocxSdk::TurboSign.resend_email("document-uuid", ["recipient-uuid-1", "recipient-uuid-2"]) -``` - -### Send a reminder - -`send_reminder` is a standalone nudge, independent of the automatic reminder cadence above: it works even when reminders are disabled or the per-signer cap is spent, does **not** consume that cap, and only emails signers at the **current** signing order. (Distinct from **Resend** above, which re-sends the original invitation — this sends the reminder copy.) Omit `recipient_ids` to remind everyone eligible; do not pass an empty array, which the API rejects. - -```ruby -result = TurboDocxSdk::TurboSign.send_reminder("document-uuid") - -result["results"].each do |r| - # "sent", or a "skipped_*" reason (e.g. "skipped_wrong_order", "skipped_completed") - puts "#{r['recipientId']}: #{r['status']}" -end - -# Or limit the reminder to specific recipients: -TurboDocxSdk::TurboSign.send_reminder("document-uuid", ["recipient-uuid-1"]) -``` - -Calls `POST /turbosign/documents/:id/send-reminder`. - -### Get audit trail - -Retrieve the complete audit trail for a document, including all events and actions. - -```ruby -result = TurboDocxSdk::TurboSign.get_audit_trail("document-uuid") - -result["auditTrail"].each do |entry| - puts "#{entry['actionType']} at #{entry['timestamp']}" -end -``` - ---- - -### Get template signature setup - -List a template's signer roles, in signing order, to [send it with signer roles](#5-send-a-template-set-up-in-turbodocx). Each role carries `key` (the value for a recipient's `role`), `label`, `order`, `hasSavedSigner`, `fieldCount`, and `defaultName` / `defaultEmail` when it has a saved signer. - -```ruby -setup = TurboDocxSdk::TurboSign.get_template_signature_setup("template-uuid") - -setup["roles"].each do |role| - puts "#{role['key']} saved signer: #{role['hasSavedSigner']}" -end -``` - -Calls `GET /turbosign/templates/:templateId/signature-setup`. A template with no saved signature setup returns a 404 (`SignatureSetupNotFound`). - ---- - -## Error Handling - -The SDK provides typed error classes for different failure scenarios. All errors extend the base `TurboDocxSdk::TurboDocxError` class. - -### Error Classes - -| Error Class | Status Code | Description | -| --------------------- | ----------- | ----------------------------------- | -| `TurboDocxError` | varies | Base error class for all SDK errors | -| `AuthenticationError` | 401 | Invalid or missing API credentials | -| `AuthorizationError` | 403 | Authenticated but lacks required permissions | -| `ValidationError` | 400 | Invalid request parameters | -| `NotFoundError` | 404 | Document or resource not found | -| `ConflictError` | 409 | Request conflicts with current resource state | -| `RateLimitError` | 429 | Too many requests | -| `NetworkError` | - | Network connectivity issues | - -### Handling Errors - -```ruby -require "turbodocx_sdk" - -begin - result = TurboDocxSdk::TurboSign.send_signature( - recipients: [{ name: "John Doe", email: "john@example.com", signingOrder: 1 }], - fields: [{ - type: "signature", - page: 1, - x: 100, - y: 650, - width: 200, - height: 50, - recipientEmail: "john@example.com" - }], - fileLink: "https://www.turbodocx.com/examples/turbodocx.pdf" - ) -rescue TurboDocxSdk::AuthenticationError => e - puts "Authentication failed: #{e.message}" - # Check your API key and org ID -rescue TurboDocxSdk::ValidationError => e - puts "Validation error: #{e.message}" - # Check request parameters -rescue TurboDocxSdk::NotFoundError => e - puts "Resource not found: #{e.message}" - # Document or recipient doesn't exist -rescue TurboDocxSdk::RateLimitError => e - puts "Rate limited: #{e.message}" - # Wait and retry -rescue TurboDocxSdk::NetworkError => e - puts "Network error: #{e.message}" - # Check connectivity -rescue TurboDocxSdk::TurboDocxError => e - puts "SDK error: #{e.message}, status_code=#{e.status_code}, code=#{e.code}" -end -``` - -### Error Properties - -All errors include these properties: - -| Property | Type | Description | -| ------------- | ---------------- | ------------------------------------ | -| `message` | `String` | Human-readable error description | -| `status_code` | `Integer \| nil` | HTTP status code (if applicable) | -| `code` | `String \| nil` | Machine-readable error code | - ---- - -## Ruby Request Hashes - -The SDK uses plain Ruby `Hash` objects for flexible JSON-like structures. Symbol and string keys are both accepted; the key **spelling stays camelCase** because the SDK forwards the hash to the API verbatim. - -### SignatureFieldType - -String values for field types: - -```ruby -# Available field type values -field_types = [ - "signature", - "initial", - "date", - "text", - "full_name", - "title", - "company", - "first_name", - "last_name", - "email", - "checkbox" -] -``` - -### Recipient - -Recipient configuration for signature requests: - -  - -| Property | Type | Required | Description | -| -------------- | --------- | -------- | ------------------------- | -| `name` | `String` | Yes | Recipient's full name | -| `email` | `String` | Yes | Recipient's email address | -| `signingOrder` | `Integer` | Conditional | Signing order (1-indexed). Not needed when `role` is set | -| `role` | `String` | No | Template signer role to fill (for example `"client"`). Requires `templateId` | - -```ruby -recipient = { - name: "John Doe", - email: "john@example.com", - signingOrder: 1 -} -``` - -### Field - -Field configuration supporting both coordinate-based and template-based positioning: - -  - -| Property | Type | Required | Description | -| ----------------- | --------- | -------- | --------------------------------------------------- | -| `type` | `String` | Yes | Field type (see SignatureFieldType) | -| `recipientEmail` | `String` | Yes | Which recipient fills this field | -| `page` | `Integer` | No\* | Page number (1-indexed) | -| `x` | `Integer` | No\* | X coordinate in pixels | -| `y` | `Integer` | No\* | Y coordinate in pixels | -| `width` | `Integer` | No\* | Field width in pixels | -| `height` | `Integer` | No\* | Field height in pixels | -| `defaultValue` | `String` | No | Default value (checkbox: `"true"`/`"false"`; date: a fixed `MM/DD/YYYY`, omit to auto-fill the signing date) | -| `isMultiline` | `Boolean` | No | Enable multiline text | -| `isReadonly` | `Boolean` | No | Make field read-only (pre-filled) | -| `required` | `Boolean` | No | Whether field is required | -| `backgroundColor` | `String` | No | Background color (hex, rgb, or named) | -| `template` | `Hash` | No | Template anchor configuration | - -\*Required when not using template anchors - -**Template Configuration:** - -| Property | Type | Required | Description | -| --------------- | --------- | -------- | ---------------------------------------------------------------- | -| `anchor` | `String` | Yes | Text anchor pattern like `{TagName}` | -| `placement` | `String` | Yes | `"replace"` \| `"before"` \| `"after"` \| `"above"` \| `"below"` | -| `size` | `Hash` | Yes | `{ width: Integer, height: Integer }` | -| `offset` | `Hash` | No | `{ x: Integer, y: Integer }` | -| `caseSensitive` | `Boolean` | No | Case sensitive search (default: false) | -| `useRegex` | `Boolean` | No | Use regex for anchor/searchText (default: false) | - -```ruby -field = { - type: "signature", - page: 1, - x: 100, - y: 500, - width: 200, - height: 50, - recipientEmail: "john@example.com" -} -``` - -### Request Parameters - -Request configuration for `create_signature_review_link` and `send_signature` methods: - -  - -| Parameter | Type | Required | Description | -| --------------------- | --------------- | ----------- | ------------------------------ | -| `recipients` | `Array` | Yes | Recipients who will sign | -| `fields` | `Array` | Conditional | Signature fields configuration. Optional when a recipient has a `role` | -| `file` | `String \| IO` | Conditional | Local file path or an IO object (multipart upload) | -| `fileLink` | `String` | Conditional | URL to document file | -| `deliverableId` | `String` | Conditional | TurboDocx deliverable ID | -| `templateId` | `String` | Conditional | TurboDocx template ID | -| `documentName` | `String` | No | Document name | -| `documentDescription` | `String` | No | Document description | -| `senderName` | `String` | No | Sender name (overrides the configured value) | -| `senderEmail` | `String` | No\*\* | Sender / reply-to email (overrides the configured value) | -| `ccEmails` | `Array` | No | Array of CC email addresses | - -:::info File Source (Conditional) -Exactly one file source is required: `file`, `fileLink`, `deliverableId`, or `templateId`. -::: - -\*\* `senderEmail` is optional per call but **required at the SDK level** for TurboSign: it must be supplied via `configure`, the `TURBODOCX_SENDER_EMAIL` environment variable, or this per-call parameter, otherwise the SDK raises a `TurboDocxSdk::ValidationError`. - ---- - -## Additional Documentation - -For detailed information about advanced configuration and API concepts, see: - -### Core API References - -- **[Request Body Reference](/docs/TurboSign/API-Signatures#request-body-multipartform-data)** - Complete request body parameters, file sources, and multipart/form-data structure -- **[Recipients Reference](/docs/TurboSign/API-Signatures#recipients-reference)** - Recipient properties, signing order, metadata, and configuration options -- **[Field Types Reference](/docs/TurboSign/API-Signatures#field-types-reference)** - All available field types (signature, date, text, checkbox, etc.) with properties and behaviors -- **[Field Positioning Methods](/docs/TurboSign/API-Signatures#field-positioning-methods)** - Template-based vs coordinate-based positioning, anchor configuration, and best practices - ---- +- [TurboSign](/docs/SDKs/turbosign?language=ruby): send documents for signature, track status, download signed PDFs and audit trails +- [Deliverable](/docs/SDKs/deliverable?language=ruby): generate documents from templates +- [TurboWebhooks](/docs/SDKs/webhooks?language=ruby): receive real-time signature events +- [TurboQuote](/docs/SDKs/quote?language=ruby): create, send and download quotes ## Resources diff --git a/docs/SDKs/turbosign.md b/docs/SDKs/turbosign.md index 653f1a8d..57bec31a 100644 --- a/docs/SDKs/turbosign.md +++ b/docs/SDKs/turbosign.md @@ -2,7 +2,7 @@ title: TurboSign SDK sidebar_position: 2 sidebar_label: TurboSign -description: 'TurboSign SDK for JavaScript, TypeScript, Python, PHP, Go and Java: send documents for signature, track status, download signed PDFs and audit trails.' +description: 'TurboSign SDK for JavaScript, TypeScript, Python, PHP, Go, Java and Ruby: send documents for signature, track status, download signed PDFs and audit trails.' keywords: - turbodocx javascript - turbodocx typescript @@ -42,6 +42,20 @@ keywords: - java sdk - document api java - esignature java + +- turbodocx ruby + +- turbosign ruby + +- ruby sdk + +- gem turbodocx + +- rails turbodocx + +- sinatra turbodocx + +- document api ruby --- import Tabs from '@theme/Tabs'; @@ -77,6 +91,11 @@ The official TurboDocx SDK for Go applications. Build document generation and di The official TurboDocx SDK for Java applications. Build document generation and digital signature workflows with the Builder pattern, comprehensive error handling, and type-safe APIs. Available on Maven Central as `com.turbodocx:turbodocx-sdk`. + + + +The official TurboDocx SDK for Ruby applications. Build document generation and digital signature workflows with a simple synchronous API and comprehensive error handling. Available on RubyGems as `turbodocx-sdk`. + @@ -181,6 +200,34 @@ implementation 'com.turbodocx:turbodocx-sdk:0.7.0' + + + + + + +```bash +gem install turbodocx-sdk +``` + + + + +Add to your `Gemfile`: + +```ruby +gem "turbodocx-sdk" +``` + +Then run: + +```bash +bundle install +``` + + + + @@ -222,6 +269,12 @@ This SDK leverages PHP 8.1+ features including enums, named parameters, readonly - OkHttp 4.x (included) - Gson 2.x (included) + + + +- Ruby 2.7+ +- No runtime dependencies (uses the standard library's `net/http`) + @@ -403,6 +456,26 @@ public class Main { } ``` + + + +```ruby +require "turbodocx_sdk" + +# Configure globally (recommended) +TurboDocxSdk::TurboSign.configure( + api_key: ENV["TURBODOCX_API_KEY"], # Required: Your TurboDocx API key + org_id: ENV["TURBODOCX_ORG_ID"], # Required: Your organization ID + sender_email: "contracts@yourcompany.com", # Required: Reply-to address for signature emails + sender_name: "Your Company" # Recommended: Sender name shown in emails + # base_url: "https://api.turbodocx.com" # Optional: Override base URL +) +``` + +:::tip Authentication +Authenticate using `api_key`. API keys are recommended for server-side applications. +::: + @@ -528,6 +601,21 @@ export TURBODOCX_SENDER_EMAIL=sender@yourcompany.com Three parameters are **required** for TurboSign operations: `apiKey` (or `accessToken`), `orgId`, and `senderEmail`. The `senderEmail` is used as the reply-to address for signature request emails. To get your credentials, follow the **[Get Your Credentials](/docs/SDKs#1-get-your-credentials)** steps from the SDKs main page. ::: + + + +```bash +# .env +TURBODOCX_API_KEY=your_api_key_here +TURBODOCX_ORG_ID=your_org_id_here +TURBODOCX_SENDER_EMAIL=contracts@yourcompany.com +TURBODOCX_SENDER_NAME=Your Company +``` + +:::warning API Credentials Required +`api_key` and `org_id` are **required** for all API requests. TurboSign additionally **requires `sender_email`** (set it on `configure`, per call, or via the `TURBODOCX_SENDER_EMAIL` environment variable): `configure` raises a `TurboDocxSdk::ValidationError` without it. `sender_name` is optional but strongly recommended. To get your credentials, follow the **[Get Your Credentials](/docs/SDKs#1-get-your-credentials)** steps from the SDKs main page. +::: + @@ -901,6 +989,42 @@ public class Main { } ``` + + + +```ruby +require "turbodocx_sdk" + +TurboDocxSdk::TurboSign.configure( + api_key: ENV["TURBODOCX_API_KEY"], + org_id: ENV["TURBODOCX_ORG_ID"], + sender_email: "contracts@acme.com", + sender_name: "Acme Corp" +) + +result = TurboDocxSdk::TurboSign.send_signature( + # Request-hash keys are camelCase — the SDK forwards them to the API verbatim + recipients: [ + { name: "Alice Smith", email: "alice@example.com", signingOrder: 1 }, + { name: "Bob Johnson", email: "bob@example.com", signingOrder: 2 } + ], + fields: [ + # Alice's signature + { type: "signature", page: 1, x: 100, y: 650, width: 200, height: 50, recipientEmail: "alice@example.com" }, + { type: "date", page: 1, x: 320, y: 650, width: 100, height: 30, recipientEmail: "alice@example.com" }, + # Bob's signature + { type: "signature", page: 1, x: 100, y: 720, width: 200, height: 50, recipientEmail: "bob@example.com" }, + { type: "date", page: 1, x: 320, y: 720, width: 100, height: 30, recipientEmail: "bob@example.com" } + ], + fileLink: "https://www.turbodocx.com/examples/turbodocx.pdf", + documentName: "Service Agreement", + senderName: "Acme Corp", + senderEmail: "contracts@acme.com" +) + +puts JSON.pretty_generate(result) +``` + @@ -1191,6 +1315,44 @@ SendSignatureResponse result = client.turboSign().sendSignature( **Important:** The document file must contain the anchor text (e.g., `{SIGNATURE_ALICE}`, `{DATE_ALICE}`) that you reference in your fields. If the anchors don't exist in the document, the API will return an error. ::: + + + +```ruby +result = TurboDocxSdk::TurboSign.send_signature( + recipients: [{ name: "Alice Smith", email: "alice@example.com", signingOrder: 1 }], + fields: [ + { + type: "signature", + recipientEmail: "alice@example.com", + template: { + anchor: "{SIGNATURE_ALICE}", + placement: "replace", + size: { width: 200, height: 50 } + } + }, + { + type: "date", + recipientEmail: "alice@example.com", + # Pins a fixed date in MM/DD/YYYY; omit to auto-fill the signing date + defaultValue: "12/31/2026", + template: { + anchor: "{DATE_ALICE}", + placement: "replace", + size: { width: 100, height: 30 } + } + } + ], + fileLink: "https://www.turbodocx.com/examples/turbodocx.pdf" +) + +puts JSON.pretty_generate(result) +``` + +:::info Template Anchors Required +**Important:** The document file must contain the anchor text (e.g., `{SIGNATURE_ALICE}`, `{DATE_ALICE}`) that you reference in your fields. If the anchors don't exist in the document, the API will return an error. +::: + @@ -1227,6 +1389,15 @@ The SDK supports multiple ways to provide your document: The SDK supports multiple ways to provide your document: + + + +TurboSign supports four different ways to provide document files: + +:::note camelCase request keys +The keys inside the request hash (`fileLink`, `deliverableId`, `templateId`, `documentName`, `recipientEmail`, `signingOrder`, …) are **camelCase** — the SDK passes them to the API verbatim and does **not** convert snake_case hash keys. Only the method keyword arguments on `configure` (`api_key:`, `sender_email:`, …) are snake_case. +::: + @@ -1526,6 +1697,36 @@ await TurboSign.sendSignature({ +### 1. File Upload (path or IO) {#1-file-upload-path-or-io} + + + + +Pass a local file path (`String`) or any IO object (e.g., `File.open`, `StringIO`) — the SDK uploads it as multipart form data and detects the file type from magic bytes. + +```ruby +result = TurboDocxSdk::TurboSign.send_signature( + file: "./contract.pdf", # local path — or an IO: File.open("./contract.pdf", "rb") + recipients: [ + { name: "John Doe", email: "john@example.com", signingOrder: 1 } + ], + fields: [ + { + type: "signature", + page: 1, + x: 100, + y: 650, + width: 200, + height: 50, + recipientEmail: "john@example.com" + } + ] +) +``` + + + + ### 2. File URL (fileLink) / 2. File URL (file_link) {#2-file-url-filelink} @@ -1613,6 +1814,33 @@ result = await TurboSign.send_signature( Use `file_link` when your documents are already hosted on cloud storage (S3, Google Cloud Storage, etc.). This is more efficient than downloading and re-uploading files. ::: + + + +```ruby +result = TurboDocxSdk::TurboSign.send_signature( + fileLink: "https://www.turbodocx.com/examples/turbodocx.pdf", + recipients: [ + { name: "John Doe", email: "john@example.com", signingOrder: 1 } + ], + fields: [ + { + type: "signature", + page: 1, + x: 100, + y: 650, + width: 200, + height: 50, + recipientEmail: "john@example.com" + } + ] +) +``` + +:::tip When to use fileLink +Use `fileLink` when your documents are already hosted on cloud storage (S3, Google Cloud Storage, etc.). This is more efficient than downloading and re-uploading files. +::: + @@ -1786,6 +2014,34 @@ SendSignatureResponse result = client.turboSign().sendSignature( `deliverableId` references documents generated using TurboDocx's document generation API. This creates a seamless workflow: generate → sign. ::: + + + +```ruby +# Use a previously generated TurboDocx document +result = TurboDocxSdk::TurboSign.send_signature( + deliverableId: "deliverable-uuid-from-turbodocx", + recipients: [ + { name: "John Doe", email: "john@example.com", signingOrder: 1 } + ], + fields: [ + { + type: "signature", + page: 1, + x: 100, + y: 650, + width: 200, + height: 50, + recipientEmail: "john@example.com" + } + ] +) +``` + +:::info Integration with TurboDocx +`deliverableId` references documents generated using TurboDocx's document generation API. This creates a seamless workflow: generate → sign. +::: + @@ -1961,6 +2217,34 @@ SendSignatureResponse result = client.turboSign().sendSignature( `templateId` references pre-configured TurboSign templates created in the TurboDocx dashboard. These templates come with built-in anchors and field positioning, making it easy to reuse signature workflows across multiple documents. ::: + + + +```ruby +# Use a pre-configured TurboSign template +result = TurboDocxSdk::TurboSign.send_signature( + templateId: "template-uuid-from-turbodocx", # Template already contains anchors + recipients: [ + { name: "Alice Smith", email: "alice@example.com", signingOrder: 1 } + ], + fields: [ + { + type: "signature", + recipientEmail: "alice@example.com", + template: { + anchor: "{SIGNATURE_ALICE}", + placement: "replace", + size: { width: 200, height: 50 } + } + } + ] +) +``` + +:::info Integration with TurboDocx +`templateId` references pre-configured TurboSign templates created in the TurboDocx dashboard. These templates come with built-in anchors and field positioning, making it easy to reuse signature workflows across multiple documents. +::: + @@ -2106,6 +2390,35 @@ SendSignatureResponse result = client.turboSign().sendSignature( Use `new Recipient.Builder().role("client").name(...).email(...)` when you also need a phone or external id. `role` works the same way on `createSignatureReviewLink` and, through `new EmbeddedSignatureRecipient.Builder().role(...)`, on `createEmbeddedSignature`. + + + +Upload a PDF as a template in TurboDocx, add its signers as roles (for example "Client" and "Countersigner"), drag their fields onto the page and save the signature setup. Then send it by naming each recipient's `role`. The fields saved for that role come with it, so `fields` can be left out, and a recipient with a `role` needs no `signingOrder`. + +```ruby +# The role keys come from the template (also shown under "Use via API" on the template page) +setup = TurboDocxSdk::TurboSign.get_template_signature_setup("your-template-id") +setup["roles"].each { |r| puts "#{r['key']} (saved signer: #{r['hasSavedSigner']})" } +# client (saved signer: false) +# countersigner (saved signer: true) + +TurboDocxSdk::TurboSign.send_signature( + templateId: "your-template-id", + recipients: [ + { role: "client", name: "Jane Doe", email: "jane@client.com" } + # "countersigner" left out: the signer saved on the template is used + ] +) +``` + +- Roles sign in the order saved on the template; recipients without a `role` sign after them. +- A role left out uses the template's saved signer. If it has none, the API returns a 400 naming the role. +- An unknown role raises `TurboDocxSdk::ValidationError` listing the template's roles (`e.code == "UnknownSignerRole"`). +- Any `fields` you pass are added to the template's (for example an extra witness signature). +- `role` works the same way on `create_signature_review_link` and `create_embedded_signature`. + +See [Sending with signer roles](/docs/TurboSign/API-Signatures#sending-with-signer-roles) for every rule and error. + @@ -2145,6 +2458,11 @@ asyncio.run(main()) The snippets below assume a configured `client` and an available `Gson` instance, e.g. `Gson gson = new GsonBuilder().setPrettyPrinting().create();` (as shown in the [Quick Start](#quick-start)). ::: + + + +All methods are class-level: call `TurboDocxSdk::TurboSign.configure` once, then invoke any method directly on the class. Every method is synchronous and returns a plain `Hash` (or raw bytes for downloads). + @@ -2276,6 +2594,21 @@ TurboDocxClient client = new TurboDocxClient.Builder() .build(); ``` + + + +Configure the SDK with your API credentials and organization settings. + +```ruby +TurboDocxSdk::TurboSign.configure( + api_key: "your-api-key", # Required: Your TurboDocx API key + org_id: "your-org-id", # Required: Your organization ID + sender_email: "you@company.com", # Required: Reply-to address for signature emails + sender_name: "Your Company", # Recommended: Sender name shown in emails + base_url: "https://api.turbodocx.com" # Optional: API base URL +) +``` + @@ -2432,6 +2765,23 @@ CreateSignatureReviewLinkResponse result = client.turboSign().createSignatureRev System.out.println("Result: " + gson.toJson(result)); ``` + + + +Upload a document for preview without sending signature request emails. + +```ruby +result = TurboDocxSdk::TurboSign.create_signature_review_link( + recipients: [{ name: "John Doe", email: "john@example.com", signingOrder: 1 }], + fields: [{ type: "signature", page: 1, x: 100, y: 500, width: 200, height: 50, recipientEmail: "john@example.com" }], + fileLink: "https://www.turbodocx.com/examples/turbodocx.pdf", + documentName: "Contract Draft" +) + +puts result["documentId"] +puts result["previewUrl"] +``` + @@ -2594,6 +2944,24 @@ SendSignatureResponse result = client.turboSign().sendSignature( System.out.println("Result: " + gson.toJson(result)); ``` + + + +Upload a document and immediately send signature requests to all recipients. + +```ruby +result = TurboDocxSdk::TurboSign.send_signature( + recipients: [{ name: "Recipient Name", email: "recipient@example.com", signingOrder: 1 }], + fields: [{ type: "signature", page: 1, x: 100, y: 500, width: 200, height: 50, recipientEmail: "recipient@example.com" }], + fileLink: "https://www.turbodocx.com/examples/turbodocx.pdf", + documentName: "Service Agreement", + senderName: "Your Company", + senderEmail: "sender@company.com" +) + +puts result["documentId"] +``` + @@ -2630,6 +2998,40 @@ Durations are `['value' => N, 'unit' => 'hours'|'days']` objects. `value` is a w warnings. `maxReminders` accepts `-1` (unlimited), `0` (none), or any value up to `50`. The resulting deadline is readable afterwards via `getStatus()->expiresAt`. + + + +`send_signature` accepts an optional per-document schedule. Both reminders and expiration are **off by default**, so omitting these keys preserves the original send behavior. Keys are camelCase like every other send key, and each duration is a `{ value:, unit: }` hash whose `unit` is `"days"` or `"hours"`. + +```ruby +result = TurboDocxSdk::TurboSign.send_signature( + recipients: [{ name: "Recipient Name", email: "recipient@example.com", signingOrder: 1 }], + fields: [{ type: "signature", page: 1, x: 100, y: 500, width: 200, height: 50, recipientEmail: "recipient@example.com" }], + fileLink: "https://www.turbodocx.com/examples/turbodocx.pdf", + documentName: "Service Agreement", + + # Reminders — chase signers who haven't signed yet + remindersEnabled: true, + reminderDelay: { value: 3, unit: "days" }, # time to the FIRST reminder + reminderInterval: { value: 3, unit: "days" }, # gap between later reminders + maxReminders: 5, # -1 unlimited, 0 none, max 50 (default 5) + + # Expiration — close the signing window + expirationEnabled: true, + expireAfter: { value: 14, unit: "days" }, # how long it stays signable + expirationWarning: { value: 3, unit: "days" }, # lead time before warnings (0 = never warn) + expirationWarningInterval: { value: 1, unit: "days" } +) +``` + +| Field | Bounds | +| --- | --- | +| `maxReminders` | Cap per signer: `-1` unlimited, `0` none, **max `50`** (default `5`). | +| any duration `value` | Whole number, **min 1**, **max 999 days (23976 hours)**. | +| `expirationWarning` | May be `0` to never warn. | + +The resolved deadline is **frozen onto the document at send time** and is then readable via `get_status(...)["expiresAt"]`. + @@ -2657,6 +3059,25 @@ foreach ($result['results'] as $r) { TurboSign::sendReminder('document-uuid', ['recipient-uuid-1', 'recipient-uuid-2']); ``` + + + +`send_reminder` is a standalone nudge, independent of the automatic reminder cadence above: it works even when reminders are disabled or the per-signer cap is spent, does **not** consume that cap, and only emails signers at the **current** signing order. (Distinct from **Resend** above, which re-sends the original invitation — this sends the reminder copy.) Omit `recipient_ids` to remind everyone eligible; do not pass an empty array, which the API rejects. + +```ruby +result = TurboDocxSdk::TurboSign.send_reminder("document-uuid") + +result["results"].each do |r| + # "sent", or a "skipped_*" reason (e.g. "skipped_wrong_order", "skipped_completed") + puts "#{r['recipientId']}: #{r['status']}" +end + +# Or limit the reminder to specific recipients: +TurboDocxSdk::TurboSign.send_reminder("document-uuid", ["recipient-uuid-1"]) +``` + +Calls `POST /turbosign/documents/:id/send-reminder`. + @@ -3023,6 +3444,24 @@ System.out.println("Expires: " + status.getExpiresAt()); // ISO 8601, or null System.out.println("Result: " + gson.toJson(status)); ``` + + + +Retrieve the current status of a document. The `status` reaches the terminal value `"expired"` once the signing window closes, and `expiresAt` carries the deadline (ISO 8601, `nil` when expiration is off). For per-signer detail, use [Get recipients](#get-recipients). + +```ruby +result = TurboDocxSdk::TurboSign.get_status("document-uuid") + +puts result["status"] # "under_review" | "completed" | "voided" | "expired" | ... +puts result["expiresAt"] # ISO 8601 deadline, or nil when expiration is off + +puts JSON.pretty_generate(result) +``` + +Once a document's deadline passes it moves to the terminal `expired` status and its signing +links stop working. The same `expiresAt` deadline is also returned on the document object from +`get_recipients` (`result["document"]["expiresAt"]`). + @@ -3139,6 +3578,24 @@ for (DocumentRecipientsResponse.RecipientSignatureStatus r : progress.getRecipie } ``` + + + +See who the document went to, who has signed, who you are still waiting on, +and who sent it. + +```ruby +result = TurboDocxSdk::TurboSign.get_recipients("document-uuid") + +summary = result["summary"] +puts "#{summary['completed']}/#{summary['total']} signed, waiting on #{summary['waitingOn']}" + +result["recipients"].each do |r| + puts "#{r['name']} <#{r['email']}>: #{r['effectiveStatus']} " \ + "(emailed #{r['delivery']['totalSent']}x)" +end +``` + @@ -3278,6 +3735,18 @@ byte[] pdfData = client.turboSign().download("document-uuid"); Files.write(Paths.get("signed-contract.pdf"), pdfData); ``` + + + +Download the completed signed document as PDF bytes. + +```ruby +pdf_bytes = TurboDocxSdk::TurboSign.download("document-uuid") + +# Save to file +File.binwrite("signed-contract.pdf", pdf_bytes) +``` + @@ -3347,6 +3816,15 @@ Cancel/void a signature request. VoidDocumentResponse result = client.turboSign().voidDocument("document-uuid", "Contract terms changed"); ``` + + + +Cancel/void a signature request. + +```ruby +result = TurboDocxSdk::TurboSign.void_document("document-uuid", "Contract terms changed") +``` + @@ -3429,6 +3907,15 @@ ResendEmailResponse result = client.turboSign().resendEmail( ); ``` + + + +Resend signature request emails to specific recipients. + +```ruby +result = TurboDocxSdk::TurboSign.resend_email("document-uuid", ["recipient-uuid-1", "recipient-uuid-2"]) +``` + @@ -3520,6 +4007,19 @@ AuditTrailResponse auditTrail = client.turboSign().getAuditTrail("document-uuid" System.out.println("Result: " + gson.toJson(auditTrail)); ``` + + + +Retrieve the complete audit trail for a document, including all events and actions. + +```ruby +result = TurboDocxSdk::TurboSign.get_audit_trail("document-uuid") + +result["auditTrail"].each do |entry| + puts "#{entry['actionType']} at #{entry['timestamp']}" +end +``` + @@ -3611,6 +4111,21 @@ for (TemplateSignatureRole role : setup.getRoles()) { } ``` + + + +List a template's signer roles, in signing order, to [send it with signer roles](#send-a-template-set-up-in-turbodocx). Each role carries `key` (the value for a recipient's `role`), `label`, `order`, `hasSavedSigner`, `fieldCount`, and `defaultName` / `defaultEmail` when it has a saved signer. + +```ruby +setup = TurboDocxSdk::TurboSign.get_template_signature_setup("template-uuid") + +setup["roles"].each do |role| + puts "#{role['key']} saved signer: #{role['hasSavedSigner']}" +end +``` + +Calls `GET /turbosign/templates/:templateId/signature-setup`. A template with no saved signature setup returns a 404 (`SignatureSetupNotFound`). + @@ -3873,6 +4388,11 @@ Every typed error embeds `TurboDocxError` by value, which promotes its `Message Every typed exception is a nested static class of `TurboDocxException` (`TurboDocxException.ValidationException`, not a separate top-level import) and extends `RuntimeException`, so the compiler never forces a catch: + + + +Every error is a `StandardError` subclass; rescue the most specific one first, since `rescue TurboDocxSdk::TurboDocxError` also matches every subclass below it. Each of the 7 named subclasses has its own default `code` (for example `"NOT_FOUND"`), so `e.code` is populated for those even when the API response itself carries none; the base `TurboDocxError` raised for an unmapped status (e.g. an unexpected 5xx) has no default, so `e.code` can be `nil` there. + @@ -3961,6 +4481,20 @@ All exceptions extend `TurboDocxException` and include: --- + + + +| Error Class | Status Code | Description | +| --------------------- | ----------- | ----------------------------------- | +| `TurboDocxError` | varies | Base error class for all SDK errors | +| `AuthenticationError` | 401 | Invalid or missing API credentials | +| `AuthorizationError` | 403 | Authenticated but lacks required permissions | +| `ValidationError` | 400 | Invalid request parameters | +| `NotFoundError` | 404 | Document or resource not found | +| `ConflictError` | 409 | Request conflicts with current resource state | +| `RateLimitError` | 429 | Too many requests | +| `NetworkError` | - | Network connectivity issues | + @@ -4141,6 +4675,52 @@ async def send_with_error_handling(): asyncio.run(send_with_error_handling()) ``` + + + +```ruby +require "turbodocx_sdk" + +begin + result = TurboDocxSdk::TurboSign.send_signature( + recipients: [{ name: "John Doe", email: "john@example.com", signingOrder: 1 }], + fields: [{ + type: "signature", + page: 1, + x: 100, + y: 650, + width: 200, + height: 50, + recipientEmail: "john@example.com" + }], + fileLink: "https://www.turbodocx.com/examples/turbodocx.pdf" + ) +rescue TurboDocxSdk::AuthenticationError => e + puts "Authentication failed: #{e.message}" + # Check your API key and org ID +rescue TurboDocxSdk::AuthorizationError => e + puts "Not authorized: #{e.message}" + # Authenticated, but lacks permission for this operation +rescue TurboDocxSdk::ValidationError => e + puts "Validation error: #{e.message}" + # Check request parameters +rescue TurboDocxSdk::NotFoundError => e + puts "Resource not found: #{e.message}" + # Document or recipient doesn't exist +rescue TurboDocxSdk::ConflictError => e + puts "Conflict: #{e.message}" + # Request conflicts with the current resource state +rescue TurboDocxSdk::RateLimitError => e + puts "Rate limited: #{e.message}" + # Wait and retry +rescue TurboDocxSdk::NetworkError => e + puts "Network error: #{e.message}" + # Check connectivity +rescue TurboDocxSdk::TurboDocxError => e + puts "SDK error: #{e.message}, status_code=#{e.status_code}, code=#{e.code}" +end +``` + @@ -4190,6 +4770,17 @@ All errors include these instance attributes: | `getStatusCode()` | `int` | HTTP status code | | `getCode()` | `String` | Machine-readable code; each of the 7 named subclasses falls back to its own default (e.g. `AuthenticationException`'s `AUTHENTICATION_ERROR`) whenever the API response carries none. The bare `TurboDocxException` thrown for an unmapped status (e.g. an unexpected 5xx) can return `null` | + + + +All errors expose these readers: + +| Property | Type | Description | +| ------------- | ---------------- | ------------------------------------ | +| `message` | `String` | Human-readable error description | +| `status_code` | `Integer \| nil` | HTTP status code (if applicable) | +| `code` | `String \| nil` | Machine-readable error code; the API's code wins when present, otherwise the class's default | + @@ -4295,6 +4886,11 @@ The SDK exports TypeScript types for full type safety. Import them directly from The SDK uses Python type hints with `Dict[str, Any]` for flexible JSON-like structures. + + + +The SDK uses plain Ruby `Hash` objects for flexible JSON-like structures. Symbol and string keys are both accepted; the key **spelling stays camelCase** because the SDK forwards the hash to the API verbatim. + @@ -4558,6 +5154,28 @@ field_types = [ ] ``` + + + +String values for field types: + +```ruby +# Available field type values +field_types = [ + "signature", + "initial", + "date", + "text", + "full_name", + "title", + "company", + "first_name", + "last_name", + "email", + "checkbox" +] +``` + @@ -4617,6 +5235,28 @@ recipient: Dict[str, Any] = { | `signingOrder` | `int` | Conditional | Order in which recipient should sign (1, 2, 3...). Not needed when `role` is set | | `role` | `String` | No | Template signer role to fill (for example `"client"`), set with `Recipient.withRole(...)` or the builder. Requires `templateId`. See [Send a template set up in TurboDocx](#send-a-template-set-up-in-turbodocx) | + + + +Recipient configuration for signature requests: + +  + +| Property | Type | Required | Description | +| -------------- | --------- | -------- | ------------------------- | +| `name` | `String` | Yes | Recipient's full name | +| `email` | `String` | Yes | Recipient's email address | +| `signingOrder` | `Integer` | Conditional | Signing order (1-indexed). Not needed when `role` is set | +| `role` | `String` | No | Template signer role to fill (for example `"client"`). Requires `templateId` | + +```ruby +recipient = { + name: "John Doe", + email: "john@example.com", + signingOrder: 1 +} +``` + @@ -4838,6 +5478,97 @@ The coordinate-based constructor takes positional arguments in this order: `new \*Required when not using template anchors + + + +Field configuration supporting both coordinate-based and template-based positioning: + +  + +| Property | Type | Required | Description | +| ----------------- | --------- | -------- | --------------------------------------------------- | +| `type` | `String` | Yes | Field type (see SignatureFieldType) | +| `recipientEmail` | `String` | Yes | Which recipient fills this field | +| `page` | `Integer` | No\* | Page number (1-indexed) | +| `x` | `Integer` | No\* | X coordinate in pixels | +| `y` | `Integer` | No\* | Y coordinate in pixels | +| `width` | `Integer` | No\* | Field width in pixels | +| `height` | `Integer` | No\* | Field height in pixels | +| `defaultValue` | `String` | No | Default value (checkbox: `"true"`/`"false"`; date: a fixed `MM/DD/YYYY`, omit to auto-fill the signing date) | +| `isMultiline` | `Boolean` | No | Enable multiline text | +| `isReadonly` | `Boolean` | No | Make field read-only (pre-filled) | +| `required` | `Boolean` | No | Whether field is required | +| `backgroundColor` | `String` | No | Background color (hex, rgb, or named) | +| `template` | `Hash` | No | Template anchor configuration | +| `metadata` | `Hash` | No | Conditional (IF/THEN) metadata, see below | + +\*Required when not using template anchors + +**Metadata Configuration (Conditional Fields):** + +The optional `metadata` hash builds IF/THEN relationships between fields. Put a `fieldKey` on a +controlling `checkbox`, then point each dependent field's `conditional.controllingFieldKey` back +at it. + +| Property | Type | Required | Description | +| ----------------------------------- | -------- | -------- | ---------------------------------------------------------------- | +| `fieldKey` | `String` | No | Stable id on a **controlling checkbox** (`type: "checkbox"`). | +| `conditional` | `Hash` | No | Rule on a **dependent field** (see below). | +| `conditional.controllingFieldKey` | `String` | Yes | The controlling checkbox's `fieldKey`. Must be non-empty. | +| `conditional.operator` | `String` | Yes | `"is_checked"` \| `"is_not_checked"`. | +| `conditional.action` | `String` | Yes | `"show"` (hidden until met) \| `"unlock"` (locked until met). | + +```ruby +# Checkbox reveals a text field when checked +fields = [ + { + type: "checkbox", + recipientEmail: "reviewer@company.com", + page: 1, x: 100, y: 400, width: 20, height: 20, + metadata: { fieldKey: "request_changes" } + }, + { + type: "text", + recipientEmail: "reviewer@company.com", + page: 1, x: 130, y: 400, width: 300, height: 60, + metadata: { + conditional: { + controllingFieldKey: "request_changes", + operator: "is_checked", + action: "show" + } + } + } +] +``` + +A malformed rule returns `400 InvalidConditionalRule`; a well-formed rule whose +`controllingFieldKey` matches no checkbox **fails open** (the field stays visible/editable). See +[Conditional (IF/THEN) Fields](/docs/TurboSign/Conditional-Fields). + +**Template Configuration:** + +| Property | Type | Required | Description | +| --------------- | --------- | -------- | ---------------------------------------------------------------- | +| `anchor` | `String` | Yes | Text anchor pattern like `{TagName}` | +| `placement` | `String` | Yes | `"replace"` \| `"before"` \| `"after"` \| `"above"` \| `"below"` | +| `size` | `Hash` | Yes | `{ width: Integer, height: Integer }` | +| `offset` | `Hash` | No | `{ x: Integer, y: Integer }` | +| `caseSensitive` | `Boolean` | No | Case sensitive search (default: false) | +| `useRegex` | `Boolean` | No | Use regex for anchor/searchText (default: false) | + +```ruby +field = { + type: "signature", + page: 1, + x: 100, + y: 500, + width: 200, + height: 50, + recipientEmail: "john@example.com" +} +``` + @@ -5021,6 +5752,48 @@ Exactly one file source is required: `file`, `fileLink`, `deliverableId`, or `te --- + + + +Request configuration for `create_signature_review_link` and `send_signature` methods: + +  + +| Parameter | Type | Required | Description | +| --------------------- | --------------- | ----------- | ------------------------------ | +| `recipients` | `Array` | Yes | Recipients who will sign | +| `fields` | `Array` | Conditional | Signature fields configuration. Optional when a recipient has a `role` | +| `file` | `String \| IO` | Conditional | Local file path or an IO object (multipart upload) | +| `fileName` | `String` | No | File name sent with `file` (a path upload uses the file's own name by default) | +| `fileLink` | `String` | Conditional | URL to document file | +| `deliverableId` | `String` | Conditional | TurboDocx deliverable ID | +| `templateId` | `String` | Conditional | TurboDocx template ID | +| `documentName` | `String` | No | Document name | +| `documentDescription` | `String` | No | Document description | +| `senderName` | `String` | No | Sender name (overrides the configured value) | +| `senderEmail` | `String` | No\*\* | Sender / reply-to email (overrides the configured value) | +| `ccEmails` | `Array` | No | Array of CC email addresses | +| `remindersEnabled` | `Boolean` | No | Send reminder emails to signers who haven't signed. Off by default | +| `reminderDelay` | `Hash` | No | `{ "value" => N, "unit" => "days"\|"hours" }`, time to the FIRST reminder | +| `reminderInterval` | `Hash` | No | `{ "value" => N, "unit" => ... }`, gap between later reminders | +| `maxReminders` | `Integer` | No | Cap per signer. `-1` unlimited, `0` none, max `50`. Default `5` | +| `expirationEnabled` | `Boolean` | No | Close the signing window after `expireAfter`. Off by default | +| `expireAfter` | `Hash` | No | `{ "value" => N, "unit" => ... }`, how long the document stays signable | +| `expirationWarning` | `Hash` | No | `{ "value" => N, "unit" => ... }`, how far before expiry warnings start. `0` = never warn | +| `expirationWarningInterval` | `Hash` | No | `{ "value" => N, "unit" => ... }`, gap between warnings once they start | + +:::info Duration bounds +Each duration `{ "value", "unit" }` uses `"days"` or `"hours"`; `value` is a whole number from `1` +up to **999 days / 23976 hours**. Reminder and expiration are independent and both **off by +default**. See [Reminders and expiration](#reminders-and-expiration). +::: + +:::info File Source (Conditional) +Exactly one file source is required: `file`, `fileLink`, `deliverableId`, or `templateId`. +::: + +\*\* `senderEmail` is optional per call but **required at the SDK level** for TurboSign: it must be supplied via `configure`, the `TURBODOCX_SENDER_EMAIL` environment variable, or this per-call parameter, otherwise the SDK raises a `TurboDocxSdk::ValidationError`. + @@ -5131,5 +5904,13 @@ For detailed information about advanced configuration and API concepts, see: - [API Reference](/docs/TurboSign/API-Signatures) - [Webhook Configuration](/docs/TurboSign/Webhooks) + + + +- [GitHub Repository](https://github.com/TurboDocx/SDK/tree/main/packages/ruby-sdk) +- [RubyGems Package](https://rubygems.org/gems/turbodocx-sdk) +- [API Reference](/docs/TurboSign/API-Signatures) +- [Webhook Configuration](/docs/TurboSign/Webhooks) + diff --git a/docs/SDKs/webhooks-ruby.md b/docs/SDKs/webhooks-ruby.md deleted file mode 100644 index ac4ebd4d..00000000 --- a/docs/SDKs/webhooks-ruby.md +++ /dev/null @@ -1,567 +0,0 @@ ---- -# Hidden from the published site: the turbodocx-sdk gem is not on RubyGems yet. -# Remove `draft: true` when the gem is published (TurboDocx/SDK issue). -draft: true -title: TurboWebhooks Ruby SDK -sidebar_position: 20 -sidebar_label: "TurboWebhooks: Ruby" -description: Official TurboDocx Webhooks SDK for Ruby. Subscribe to all seven TurboSign signature events with the WebhookEvent constants, verify inbound webhook signatures with HMAC-SHA256, and manage delivery history programmatically. -keywords: - - turbodocx webhooks - - turbowebhooks ruby - - webhook ruby - - hmac signature verification ruby - - signature webhook ruby - - webhook receiver rails - - rails webhook - - sinatra webhook - - webhook secret ruby - - webhook events ruby - - webhookevent constants ruby - - signature lifecycle events ---- - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; -import QuickstartSkillNudge from '@site/src/components/QuickstartSkillNudge'; - -# TurboWebhooks Ruby SDK - - - -The official TurboDocx Webhooks SDK for Ruby applications. Subscribe a single per-organization HTTPS endpoint to TurboDocx signature events, verify inbound signatures with HMAC-SHA256, replay delivery attempts, and rotate secrets — all from Ruby 2.7+. Available on RubyGems as `turbodocx-sdk` (same gem as TurboSign). - -
- -:::info What is TurboWebhooks? -TurboWebhooks lets your application receive real-time notifications across the whole signature lifecycle — sent, viewed, each recipient signing, partial progress, completed, voided, and finalization failures — instead of polling the API. Each organization has a single, named webhook (`signature`) that mirrors the **Signature Webhooks** page in the dashboard, so SDK-managed and UI-managed configuration stays in sync. - -For the full conceptual overview of how webhooks work in TurboSign (delivery retries, payload schema, dashboard UI), see [TurboSign → Webhooks](/docs/TurboSign/Webhooks). -::: - -## Installation - -```bash -gem install turbodocx-sdk -``` - -Or add it to your `Gemfile`: - -```ruby -gem "turbodocx-sdk" -``` - -```bash -bundle install -``` - -## Requirements - -- Ruby 2.7 or higher -- An **administrator** TurboDocx API key (the webhook routes are gated on the administrator role — non-admin keys return HTTP 403) - -## Configuration - -```ruby -require "turbodocx_sdk" - -TurboDocxSdk::TurboWebhooks.configure( - api_key: ENV["TURBODOCX_API_KEY"], - org_id: ENV["TURBODOCX_ORG_ID"] -) -``` - -`configure` hardcodes `skip_sender_validation: true` internally — webhook management never sends signature emails, so no `sender_email` is required. - -If you skip `configure`, the first call falls back to the `TURBODOCX_API_KEY` and `TURBODOCX_ORG_ID` environment variables; if either is missing it raises a descriptive `TurboDocxSdk::TurboDocxError`. - -### Environment Variables - -```bash -TURBODOCX_API_KEY=your_admin_api_key -TURBODOCX_ORG_ID=your_org_id -# optional — defaults to https://api.turbodocx.com -TURBODOCX_BASE_URL=https://api.turbodocx.com -# store the secret returned by create_webhook so your receiver can verify signatures -TURBODOCX_WEBHOOK_SECRET=whsec_... -``` - -:::warning Administrator role required -TurboWebhooks endpoints require the **administrator** role on the API key. A valid TDX- key without the role raises `TurboDocxSdk::AuthorizationError` (HTTP 403). Generate or rotate keys in the **Settings → API Keys** page. -::: - -## Webhook Events - -TurboSign dispatches **seven** events. Subscribe to any subset — `events` requires at least one. - -| Event | Constant | Fires when | -|---|---|---| -| `signature.document.sent` | `TurboDocxSdk::WebhookEvent::SENT` | The document is dispatched to recipients | -| `signature.document.viewed` | `TurboDocxSdk::WebhookEvent::VIEWED` | A recipient opens the document for the first time | -| `signature.document.recipient_signed` | `TurboDocxSdk::WebhookEvent::RECIPIENT_SIGNED` | Any individual signer completes their signature — fires **once per signer**, including the last | -| `signature.document.signed` | `TurboDocxSdk::WebhookEvent::SIGNED` | A signer signs and the document is **not yet complete** (document-level partial progress) | -| `signature.document.completed` | `TurboDocxSdk::WebhookEvent::COMPLETED` | All recipients have signed and the signed PDF is finalized | -| `signature.document.finalization_failed` | `TurboDocxSdk::WebhookEvent::FINALIZATION_FAILED` | The signed PDF fails to finalize (e.g. a KMS signing error); the document is **not** completed | -| `signature.document.voided` | `TurboDocxSdk::WebhookEvent::VOIDED` | The document is voided or cancelled | - -:::danger `signed` does not mean "the document is done" -`recipient_signed` is the **per-person** event: it fires once for **every** signer (including the last) and carries the signer's identity plus `is_final_signer` and `remaining_signers`. - -`signed` is a document-level **partial-progress** event. On each signature `recipient_signed` fires first, then exactly one of `signed` (signers still remain), `completed` (that was the final signature and finalization succeeded), or `finalization_failed` (final signature, finalization failed). Two consequences: - -- **`signed` never fires on the final signature.** -- **A single-signer document never emits `signed` at all** — it emits `recipient_signed` (`is_final_signer: true`) then `completed`. - -To detect "the whole document is done", use `completed` (or `recipient_signed` with `is_final_signer: true`) — never `signed`. - -See [TurboSign → Webhooks](/docs/TurboSign/Webhooks) for the full payload schemas and the lifecycle diagram. -::: - -### Event constants - -The events ship as frozen string constants under `TurboDocxSdk::WebhookEvent`, so a typo raises a `NameError` at load time instead of becoming a webhook that silently never fires. - -```ruby -require "turbodocx_sdk" - -# Subscribe to a chosen subset -TurboDocxSdk::TurboWebhooks.create_webhook( - urls: ["https://your-server.example.com/webhooks/turbodocx"], - events: [ - TurboDocxSdk::WebhookEvent::SENT, - TurboDocxSdk::WebhookEvent::VIEWED, - TurboDocxSdk::WebhookEvent::RECIPIENT_SIGNED, - TurboDocxSdk::WebhookEvent::COMPLETED, - TurboDocxSdk::WebhookEvent::FINALIZATION_FAILED, - TurboDocxSdk::WebhookEvent::VOIDED - ] -) - -# ...or to everything TurboSign emits — ALL is the frozen list of all 7, -# in lifecycle order. -TurboDocxSdk::TurboWebhooks.create_webhook( - urls: ["https://your-server.example.com/webhooks/turbodocx"], - events: TurboDocxSdk::WebhookEvent::ALL -) -``` - -:::note Raw strings still work -Nothing was narrowed. `events` still accepts plain strings (`"signature.document.completed"`), so existing code keeps running and the backend can add new events without an SDK release. The constants exist for discoverability. `get_webhook` also returns `availableEvents` — the list the backend advertises at runtime. -::: - -### Delivered payload shape - -Every delivery posts this envelope: - -```json -{ - "event": "signature.document.completed", - "event_id": "evt_a1b2c3…", - "created_at": "2026-01-15T10:30:00.000Z", - "version": "1.0", - "data": { "documentId": "…", "documentName": "…" } -} -``` - -:::warning Dispatch on `event`, not `eventType` - -The event name travels in the top-level **`event`** field. There is no `eventType` key on the -wire — a receiver written against it reads `nil` and silently dispatches nothing, which -looks exactly like "the webhook never fired". - -`eventType` **is** correct in two other places, which is where the confusion comes from: it is -the request parameter name for `test_webhook` and `list_webhook_deliveries`, and it is the column name on -the stored delivery-history rows those return. Those are not the delivered envelope. - -::: - -## Quick Start - -### 1. Create the signature webhook - -```ruby -require "turbodocx_sdk" - -TurboDocxSdk::TurboWebhooks.configure( - api_key: ENV["TURBODOCX_API_KEY"], - org_id: ENV["TURBODOCX_ORG_ID"] -) - -begin - created = TurboDocxSdk::TurboWebhooks.create_webhook( - urls: ["https://your-server.example.com/webhooks/turbodocx"], - events: [ - TurboDocxSdk::WebhookEvent::SENT, - TurboDocxSdk::WebhookEvent::VIEWED, - TurboDocxSdk::WebhookEvent::RECIPIENT_SIGNED, - TurboDocxSdk::WebhookEvent::COMPLETED, - TurboDocxSdk::WebhookEvent::FINALIZATION_FAILED, - TurboDocxSdk::WebhookEvent::VOIDED - ] - ) - - # SAVE THIS SECRET — it is shown ONCE and cannot be retrieved later. - File.write(".secret", created["secret"]) - puts "Created webhook id=#{created['id']}" -rescue TurboDocxSdk::ConflictError - # 409 — the signature webhook already exists for this org. - # Use TurboDocxSdk::TurboWebhooks.update_webhook(...) or .delete_webhook instead. - puts "Webhook already exists. Use update_webhook or delete_webhook." -rescue TurboDocxSdk::ValidationError => e - # 400 — most commonly a non-HTTPS URL or empty events array. - puts "Validation failed: #{e.message}" -end -``` - -:::warning HTTPS only -TurboDocx rejects non-HTTPS webhook URLs with HTTP 400. For local development, expose your receiver via an HTTPS tunnel ([ngrok](https://ngrok.com), [cloudflared](https://github.com/cloudflare/cloudflared), etc.) and pass the tunnel URL to `create_webhook`. -::: - -### 2. Verify inbound webhook signatures - -When TurboDocx POSTs to your receiver, every request carries an `X-TurboDocx-Signature` header. Verify it before trusting the payload — the helper enforces a 300-second timestamp tolerance and uses constant-time comparison. - -```ruby -require "turbodocx_sdk" - -# In your Rack/Rails/Sinatra webhook handler: -raw_body = request.body.read # raw bytes — do NOT JSON.parse first -signature = request.get_header("HTTP_X_TURBODOCX_SIGNATURE") || "" -timestamp = request.get_header("HTTP_X_TURBODOCX_TIMESTAMP") || "" -secret = ENV["TURBODOCX_WEBHOOK_SECRET"] - -unless TurboDocxSdk.verify_webhook_signature( - payload: raw_body, - signature_header: signature, - timestamp_header: timestamp, - secret: secret -) - return [401, {}, ["invalid signature"]] -end - -event = JSON.parse(raw_body) -# process event["event"], event["data"], ... (NOT "eventType" — not on the wire) - -[200, {}, ["ok"]] -``` - -:::danger Use the raw request body -The HMAC is computed over the **exact bytes** that left the TurboDocx server. Never `JSON.parse` and re-serialize before verifying — re-encoded JSON will not byte-match and verification will fail. -::: - -The signature contract: - -| Field | Value | -|---|---| -| Header | `X-TurboDocx-Signature: sha256=` | -| Timestamp header | `X-TurboDocx-Timestamp: ` | -| Signed string | `.` | -| Algorithm | HMAC-SHA256 | -| Tolerance | 300 seconds (configurable) | -| Comparison | constant-time | - -## Method Reference - -All methods are class-level; call `TurboDocxSdk::TurboWebhooks.configure` once, then invoke any method directly on the class. - -### create_webhook - -Subscribe the org to events. Returns `{ "id" => ..., "secret" => ... }` — the **secret is shown once**. - -```ruby -created = TurboDocxSdk::TurboWebhooks.create_webhook( - urls: ["https://your-server.example.com/webhooks/turbodocx"], - events: [ - TurboDocxSdk::WebhookEvent::RECIPIENT_SIGNED, - TurboDocxSdk::WebhookEvent::COMPLETED, - TurboDocxSdk::WebhookEvent::FINALIZATION_FAILED, - TurboDocxSdk::WebhookEvent::VOIDED - ] - # or subscribe to all 7: events: TurboDocxSdk::WebhookEvent::ALL -) -``` - -`urls` accepts **1 to 10** HTTPS URLs. `events` requires **at least 1** of the [seven events](#webhook-events) — raw strings and `TurboDocxSdk::WebhookEvent::*` constants are interchangeable (the constants *are* strings). Both are required on create. - -| Raises | Why | -|---|---| -| `TurboDocxSdk::ConflictError` (409) | The signature webhook already exists for this org. | -| `TurboDocxSdk::ValidationError` (400) | A URL is not HTTPS, `urls` is empty or has more than 10 entries, or `events` is empty. | -| `TurboDocxSdk::AuthorizationError` (403) | API key lacks the administrator role. | - -### get_webhook - -Get the org's signature webhook plus delivery statistics. - -```ruby -webhook = TurboDocxSdk::TurboWebhooks.get_webhook -# webhook["urls"], webhook["events"], webhook["isActive"] -# webhook["deliveryStats"]["totalDeliveries"] -# webhook["deliveryStats"]["successfulDeliveries"] -# webhook["deliveryStats"]["failedDeliveries"] -# webhook["deliveryStats"]["pendingRetries"] -# webhook["availableEvents"] -``` - -### update_webhook - -Patch one or more fields. All parameters are optional — pass only what changes; untouched fields are omitted from the request. - -```ruby -TurboDocxSdk::TurboWebhooks.update_webhook( - urls: ["https://your-server.example.com/webhooks/turbodocx"], - events: ["signature.document.completed"], - is_active: true -) - -# Leaving urls and events alone: just don't pass those keyword arguments. -TurboDocxSdk::TurboWebhooks.update_webhook(is_active: false) -``` - -:::danger Never send an empty array -`urls` and `events` are optional on update, but optional does **not** relax their minimum length. `urls: []` or `events: []` is a **400** — the same as sending an empty array on create. To leave a field unchanged, **omit the keyword argument entirely**. `urls` still caps at 10 entries on update. -::: - -### delete_webhook - -Soft-delete the webhook and its delivery history. - -```ruby -TurboDocxSdk::TurboWebhooks.delete_webhook -``` - -### test_webhook - -Fire a synthetic delivery to every URL configured on the webhook. Useful for CI smoke tests before flipping a new receiver into production. - -```ruby -result = TurboDocxSdk::TurboWebhooks.test_webhook( - event_type: "signature.document.completed", - payload: { "documentId" => "...", "documentName" => "..." } -) - -puts "#{result['summary']['successful']}/#{result['summary']['total']} succeeded" -result["summary"]["errors"].each do |err| - puts " failure: #{err}" # per-URL failure messages -end -``` - -### notify_webhook - -Send a manual notification to every configured URL. Routes through the same backend handler as `test_webhook` and returns the same shape; prefer `test_webhook` in new code. - -```ruby -TurboDocxSdk::TurboWebhooks.notify_webhook( - event_type: "signature.document.voided", - payload: { "documentId" => "..." } -) -``` - -### regenerate_webhook_secret - -Rotate the HMAC secret. The new secret is shown **once**; old signatures fail immediately after rotation. - -```ruby -rotated = TurboDocxSdk::TurboWebhooks.regenerate_webhook_secret -# rotated["secret"] -# rotated["regeneratedAt"] -``` - -### list_webhook_deliveries - -Page through historical delivery attempts with filters. - -```ruby -page = TurboDocxSdk::TurboWebhooks.list_webhook_deliveries( - limit: 20, - offset: 0, - event_type: "signature.document.completed", - is_delivered: false, - http_status: 500 -) -# page["results"]: array of delivery rows -# page["totalRecords"] -``` - -### replay_webhook_delivery - -Manually retry a past delivery by ID. Returns a freshly-created delivery row. - -```ruby -replay = TurboDocxSdk::TurboWebhooks.replay_webhook_delivery("delivery-uuid-here") -# replay["id"], replay["httpStatus"], replay["attemptCount"], ... -``` - -### get_webhook_stats - -Aggregate delivery stats over a sliding window. - -```ruby -stats = TurboDocxSdk::TurboWebhooks.get_webhook_stats(days: 30) -# stats["summary"]["successRate"] -# stats["summary"]["avgResponseTime"] (milliseconds) -# stats["eventBreakdown"] (per-event totals) -``` - -### verify_webhook_signature (free function) - -Verify the `X-TurboDocx-Signature` header on an incoming request. It is a module-level function (`TurboDocxSdk.verify_webhook_signature`) and does **not** require `TurboWebhooks.configure` — receivers commonly run in a different process than the management code. It never raises on bad input; it always returns a boolean. - -```ruby -ok = TurboDocxSdk.verify_webhook_signature( - payload: raw_body, - signature_header: signature_header, - timestamp_header: timestamp_header, - secret: webhook_secret, - tolerance_seconds: 300 # default; pass 0 to disable the timestamp check (NOT recommended) -) -``` - -A negative `tolerance_seconds` **fails closed** (rejects every signature) rather than silently disabling the replay-window check. - -## Rails Integration Example - -Configure TurboWebhooks once in an initializer, then add a controller for the receiver. - -```ruby -# config/initializers/turbodocx.rb -require "turbodocx_sdk" - -TurboDocxSdk::TurboWebhooks.configure( - api_key: Rails.application.credentials.dig(:turbodocx, :api_key), - org_id: Rails.application.credentials.dig(:turbodocx, :org_id) -) -``` - -```ruby -# app/controllers/webhooks_controller.rb -class WebhooksController < ApplicationController - # Webhook receivers are server-to-server — skip CSRF. - skip_before_action :verify_authenticity_token - - def turbodocx - raw_body = request.body.read - signature = request.headers["X-TurboDocx-Signature"].to_s - timestamp = request.headers["X-TurboDocx-Timestamp"].to_s - secret = Rails.application.credentials.dig(:turbodocx, :webhook_secret) - - unless TurboDocxSdk.verify_webhook_signature( - payload: raw_body, signature_header: signature, timestamp_header: timestamp, secret: secret - ) - return head :unauthorized - end - - event = JSON.parse(raw_body) - case event["event"] - # fires once per signer — event.dig("data", "is_final_signer") marks the last - when TurboDocxSdk::WebhookEvent::RECIPIENT_SIGNED then on_recipient_signed(event["data"]) - # partial progress only — NEVER fires on the final signature - when TurboDocxSdk::WebhookEvent::SIGNED then on_partial_progress(event["data"]) - # the document is done - when TurboDocxSdk::WebhookEvent::COMPLETED then on_completed(event["data"]) - when TurboDocxSdk::WebhookEvent::FINALIZATION_FAILED then on_finalization_failed(event["data"]) - when TurboDocxSdk::WebhookEvent::VOIDED then on_voided(event["data"]) - end - - head :ok - end -end -``` - -```ruby -# config/routes.rb -post "/webhooks/turbodocx", to: "webhooks#turbodocx" -``` - -## Sinatra / Rack Integration Example - -```ruby -require "sinatra" -require "turbodocx_sdk" - -post "/webhooks/turbodocx" do - raw_body = request.body.read - signature = request.env["HTTP_X_TURBODOCX_SIGNATURE"].to_s - timestamp = request.env["HTTP_X_TURBODOCX_TIMESTAMP"].to_s - - halt 401 unless TurboDocxSdk.verify_webhook_signature( - payload: raw_body, - signature_header: signature, - timestamp_header: timestamp, - secret: ENV["TURBODOCX_WEBHOOK_SECRET"] - ) - - event = JSON.parse(raw_body) - # process event["event"], event["data"], ... (NOT "eventType" — not on the wire) - status 200 - "ok" -end -``` - -## Error Handling - -```ruby -begin - TurboDocxSdk::TurboWebhooks.create_webhook(urls: urls, events: events) -rescue TurboDocxSdk::ConflictError - # 409 — signature webhook already exists; update or delete it instead -rescue TurboDocxSdk::ValidationError - # 400 — non-HTTPS URL, empty events array, etc. -rescue TurboDocxSdk::AuthorizationError - # 403 — API key lacks the administrator role -rescue TurboDocxSdk::AuthenticationError - # 401 — bad or revoked API key -rescue TurboDocxSdk::NotFoundError - # 404 — read/update/delete against a webhook that doesn't exist -rescue TurboDocxSdk::RateLimitError - # 429 — back off and retry -rescue TurboDocxSdk::NetworkError - # request never reached the server (DNS, refused, timeout) -rescue TurboDocxSdk::TurboDocxError => e - # base class for any other typed SDK error (raw 5xx, etc.) - puts "Error #{e.status_code}: #{e.message}" -end -``` - -All errors inherit from `TurboDocxSdk::TurboDocxError` and carry `status_code` and `code` readers. - -### Common Error Codes - -| Status | Error | When | -|---|---|---| -| 400 | `ValidationError` | Non-HTTPS URL, empty `urls`/`events` array, more than 10 URLs, invalid body | -| 401 | `AuthenticationError` | Missing or invalid API key | -| 403 | `AuthorizationError` | Valid key without administrator role | -| 404 | `NotFoundError` | Operating on a non-existent webhook | -| 409 | `ConflictError` | Creating when the signature webhook already exists | -| 429 | `RateLimitError` | Rate limit exceeded — back off | - -## Runnable End-to-End Example - -A complete, validated CRUD walkthrough lives in the SDK repo: - -**[`packages/ruby-sdk/examples/turbowebhooks_crud.rb`](https://github.com/TurboDocx/SDK/blob/main/packages/ruby-sdk/examples/turbowebhooks_crud.rb)** - -It exercises every CRUD step plus every error branch (400 / 401 / 403 / 404 / 409) against a live backend. - -## Gotchas - -- **One webhook per org.** Every method targets the fixed-name `signature` webhook. Creating it twice raises `ConflictError` (409). To manage multiple webhooks per org, call the REST API directly. -- **Save the secret immediately.** `create_webhook` and `regenerate_webhook_secret` return the HMAC secret **once**. There is no endpoint to retrieve it later. If you lose it, rotate. -- **Use the raw bytes for verification.** The HMAC is over the exact request body received. Never `JSON.parse` first. -- **`verify_webhook_signature` uses keyword arguments** (`payload:`, `signature_header:`, `timestamp_header:`, `secret:`) — not positional args. -- **`verify_webhook_signature` never raises.** Non-String headers, a missing secret, or a malformed timestamp all return `false` rather than raising; a negative `tolerance_seconds` fails closed. -- **`update_webhook` only sends what you pass.** Omitted keyword arguments are excluded from the PATCH body, so you can flip `is_active` without resending `urls`/`events`. -- **An empty array is not "no change".** `urls: []` and `events: []` are 400s on update, not no-ops — omitting the keyword is the only way to leave a field alone. -- **`signature.document.signed` is partial progress, not completion.** It never fires on the final signature, and a single-signer document never emits it at all. Use `TurboDocxSdk::WebhookEvent::COMPLETED` to detect a finished document. See [Webhook Events](#webhook-events). -- **`WebhookEvent::ALL` is frozen.** It's the canonical list of all 7 events — `dup` it before mutating. - -## See Also - -- [TurboSign → Webhooks](/docs/TurboSign/Webhooks) — concepts, dashboard UI, retry behavior -- [TurboWebhooks JavaScript / TypeScript SDK](/docs/SDKs/webhooks-javascript) — same API, JS idioms -- [TurboWebhooks Python SDK](/docs/SDKs/webhooks-python) — same API, Python idioms -- [TurboSign Ruby SDK](/docs/SDKs/ruby) — sending documents for signature -- [SDKs Overview](/docs/SDKs) — all SDKs across all supported languages -- [TurboDocx SDK on RubyGems](https://rubygems.org/gems/turbodocx-sdk) -- [TurboDocx SDK on GitHub](https://github.com/TurboDocx/SDK/tree/main/packages/ruby-sdk) diff --git a/docs/SDKs/webhooks.md b/docs/SDKs/webhooks.md index 7a7efe3b..30bbbaeb 100644 --- a/docs/SDKs/webhooks.md +++ b/docs/SDKs/webhooks.md @@ -2,7 +2,7 @@ title: TurboWebhooks SDK sidebar_position: 15 sidebar_label: TurboWebhooks -description: 'TurboWebhooks SDK for JavaScript, TypeScript, Python, PHP, Go and Java: subscribe to TurboSign events, verify HMAC signatures, replay deliveries.' +description: 'TurboWebhooks SDK for JavaScript, TypeScript, Python, PHP, Go, Java and Ruby: subscribe to TurboSign events, verify HMAC signatures, replay deliveries.' keywords: - turbodocx webhooks - turbowebhooks javascript @@ -56,6 +56,26 @@ keywords: - webhook secret java - webhook events java - webhookevent enum java + +- turbowebhooks ruby + +- webhook ruby + +- hmac signature verification ruby + +- signature webhook ruby + +- webhook receiver rails + +- rails webhook + +- sinatra webhook + +- webhook secret ruby + +- webhook events ruby + +- webhookevent constants ruby --- import Tabs from '@theme/Tabs'; @@ -91,6 +111,11 @@ The official TurboDocx Webhooks SDK for Go applications (net/http, Gin, Echo, Ch The official TurboDocx Webhooks SDK for Java applications (Spring Boot, Servlet, Jakarta EE, etc.). Subscribe a single per-organization HTTPS endpoint to TurboDocx signature events, verify inbound signatures with HMAC-SHA256, replay delivery attempts, and rotate secrets — all from Java 11+. Distributed as `com.turbodocx:turbodocx-sdk` on Maven Central (same artifact as TurboSign). + + + +The official TurboDocx Webhooks SDK for Ruby applications. Subscribe a single per-organization HTTPS endpoint to TurboDocx signature events, verify inbound signatures with HMAC-SHA256, replay delivery attempts, and rotate secrets — all from Ruby 2.7+. Available on RubyGems as `turbodocx-sdk` (same gem as TurboSign). + @@ -218,6 +243,23 @@ import com.turbodocx.TurboDocxException; import com.turbodocx.WebhookSignatureVerifier; ``` + + + +```bash +gem install turbodocx-sdk +``` + +Or add it to your `Gemfile`: + +```ruby +gem "turbodocx-sdk" +``` + +```bash +bundle install +``` + @@ -258,6 +300,12 @@ import com.turbodocx.WebhookSignatureVerifier; - An **administrator** TurboDocx API key (the webhook routes are gated on the administrator role — non-admin keys return HTTP 403) - All TurboWebhooks methods return `com.google.gson.JsonObject` for forward compatibility — new server fields surface without an SDK upgrade + + + +- Ruby 2.7 or higher +- An **administrator** TurboDocx API key (the webhook routes are gated on the administrator role — non-admin keys return HTTP 403) + @@ -370,6 +418,22 @@ TurboWebhooks webhooks = new TurboDocxClient.Builder() TurboWebhooks endpoints require the **administrator** role on the API key. A valid TDX- key without the role throws `TurboDocxException.AuthorizationException` (HTTP 403). Generate or rotate keys in the **Settings → API Keys** page. ::: + + + +```ruby +require "turbodocx_sdk" + +TurboDocxSdk::TurboWebhooks.configure( + api_key: ENV["TURBODOCX_API_KEY"], + org_id: ENV["TURBODOCX_ORG_ID"] +) +``` + +`configure` hardcodes `skip_sender_validation: true` internally — webhook management never sends signature emails, so no `sender_email` is required. + +If you skip `configure`, the first call falls back to the `TURBODOCX_API_KEY` and `TURBODOCX_ORG_ID` environment variables; if either is missing it raises a descriptive `TurboDocxSdk::TurboDocxError`. + @@ -455,6 +519,22 @@ TURBODOCX_WEBHOOK_SECRET=whsec_... TurboWebhooks endpoints require the **administrator** role on the API key. A valid TDX- key without the role throws `TurboDocxException.AuthorizationException` (HTTP 403). Generate or rotate keys in the **Settings → API Keys** page. ::: + + + +```bash +TURBODOCX_API_KEY=your_admin_api_key +TURBODOCX_ORG_ID=your_org_id +# optional — defaults to https://api.turbodocx.com +TURBODOCX_BASE_URL=https://api.turbodocx.com +# store the secret returned by create_webhook so your receiver can verify signatures +TURBODOCX_WEBHOOK_SECRET=whsec_... +``` + +:::warning Administrator role required +TurboWebhooks endpoints require the **administrator** role on the API key. A valid TDX- key without the role raises `TurboDocxSdk::AuthorizationError` (HTTP 403). Generate or rotate keys in the **Settings → API Keys** page. +::: + @@ -600,6 +680,34 @@ To detect "the whole document is done", use `completed` (or `recipient_signed` w See [TurboSign → Webhooks](/docs/TurboSign/Webhooks) for the full payload schemas and the lifecycle diagram. ::: + + + +TurboSign dispatches **seven** events. Subscribe to any subset — `events` requires at least one. + +| Event | Constant | Fires when | +|---|---|---| +| `signature.document.sent` | `TurboDocxSdk::WebhookEvent::SENT` | The document is dispatched to recipients | +| `signature.document.viewed` | `TurboDocxSdk::WebhookEvent::VIEWED` | A recipient opens the document for the first time | +| `signature.document.recipient_signed` | `TurboDocxSdk::WebhookEvent::RECIPIENT_SIGNED` | Any individual signer completes their signature — fires **once per signer**, including the last | +| `signature.document.signed` | `TurboDocxSdk::WebhookEvent::SIGNED` | A signer signs and the document is **not yet complete** (document-level partial progress) | +| `signature.document.completed` | `TurboDocxSdk::WebhookEvent::COMPLETED` | All recipients have signed and the signed PDF is finalized | +| `signature.document.finalization_failed` | `TurboDocxSdk::WebhookEvent::FINALIZATION_FAILED` | The signed PDF fails to finalize (e.g. a KMS signing error); the document is **not** completed | +| `signature.document.voided` | `TurboDocxSdk::WebhookEvent::VOIDED` | The document is voided or cancelled | + +:::danger `signed` does not mean "the document is done" +`recipient_signed` is the **per-person** event: it fires once for **every** signer (including the last) and carries the signer's identity plus `is_final_signer` and `remaining_signers`. + +`signed` is a document-level **partial-progress** event. On each signature `recipient_signed` fires first, then exactly one of `signed` (signers still remain), `completed` (that was the final signature and finalization succeeded), or `finalization_failed` (final signature, finalization failed). Two consequences: + +- **`signed` never fires on the final signature.** +- **A single-signer document never emits `signed` at all** — it emits `recipient_signed` (`is_final_signer: true`) then `completed`. + +To detect "the whole document is done", use `completed` (or `recipient_signed` with `is_final_signer: true`) — never `signed`. + +See [TurboSign → Webhooks](/docs/TurboSign/Webhooks) for the full payload schemas and the lifecycle diagram. +::: + @@ -812,6 +920,39 @@ webhooks.testWebhook(WebhookEvent.COMPLETED.getValue(), payload); Nothing was narrowed. The events list is still `List`, so existing code keeps compiling and the backend can add new events without an SDK release. The enum exists for discoverability and type safety. `getWebhook()` also returns `availableEvents` — the list the backend advertises at runtime. ::: + + + +The events ship as frozen string constants under `TurboDocxSdk::WebhookEvent`, so a typo raises a `NameError` at load time instead of becoming a webhook that silently never fires. + +```ruby +require "turbodocx_sdk" + +# Subscribe to a chosen subset +TurboDocxSdk::TurboWebhooks.create_webhook( + urls: ["https://your-server.example.com/webhooks/turbodocx"], + events: [ + TurboDocxSdk::WebhookEvent::SENT, + TurboDocxSdk::WebhookEvent::VIEWED, + TurboDocxSdk::WebhookEvent::RECIPIENT_SIGNED, + TurboDocxSdk::WebhookEvent::COMPLETED, + TurboDocxSdk::WebhookEvent::FINALIZATION_FAILED, + TurboDocxSdk::WebhookEvent::VOIDED + ] +) + +# ...or to everything TurboSign emits — ALL is the frozen list of all 7, +# in lifecycle order. +TurboDocxSdk::TurboWebhooks.create_webhook( + urls: ["https://your-server.example.com/webhooks/turbodocx"], + events: TurboDocxSdk::WebhookEvent::ALL +) +``` + +:::note Raw strings still work +Nothing was narrowed. `events` still accepts plain strings (`"signature.document.completed"`), so existing code keeps running and the backend can add new events without an SDK release. The constants exist for discoverability. `get_webhook` also returns `availableEvents` — the list the backend advertises at runtime. +::: + @@ -904,6 +1045,21 @@ the stored delivery-history rows those return. Those are not the delivered envel ::: + + + +:::warning Dispatch on `event`, not `eventType` + +The event name travels in the top-level **`event`** field. There is no `eventType` key on the +wire — a receiver written against it reads `nil` and silently dispatches nothing, which +looks exactly like "the webhook never fired". + +`eventType` **is** correct in two other places, which is where the confusion comes from: it is +the request parameter name for `test_webhook` and `list_webhook_deliveries`, and it is the column name on +the stored delivery-history rows those return. Those are not the delivered envelope. + +::: + @@ -1189,6 +1345,47 @@ public class CreateSignatureWebhook { TurboDocx rejects non-HTTPS webhook URLs with HTTP 400. For local development, expose your receiver via an HTTPS tunnel ([ngrok](https://ngrok.com), [cloudflared](https://github.com/cloudflare/cloudflared), or [webhook.site](https://webhook.site)) and pass the tunnel URL to `createWebhook`. ::: + + + +```ruby +require "turbodocx_sdk" + +TurboDocxSdk::TurboWebhooks.configure( + api_key: ENV["TURBODOCX_API_KEY"], + org_id: ENV["TURBODOCX_ORG_ID"] +) + +begin + created = TurboDocxSdk::TurboWebhooks.create_webhook( + urls: ["https://your-server.example.com/webhooks/turbodocx"], + events: [ + TurboDocxSdk::WebhookEvent::SENT, + TurboDocxSdk::WebhookEvent::VIEWED, + TurboDocxSdk::WebhookEvent::RECIPIENT_SIGNED, + TurboDocxSdk::WebhookEvent::COMPLETED, + TurboDocxSdk::WebhookEvent::FINALIZATION_FAILED, + TurboDocxSdk::WebhookEvent::VOIDED + ] + ) + + # SAVE THIS SECRET — it is shown ONCE and cannot be retrieved later. + File.write(".secret", created["secret"]) + puts "Created webhook id=#{created['id']}" +rescue TurboDocxSdk::ConflictError + # 409 — the signature webhook already exists for this org. + # Use TurboDocxSdk::TurboWebhooks.update_webhook(...) or .delete_webhook instead. + puts "Webhook already exists. Use update_webhook or delete_webhook." +rescue TurboDocxSdk::ValidationError => e + # 400 — most commonly a non-HTTPS URL or empty events array. + puts "Validation failed: #{e.message}" +end +``` + +:::warning HTTPS only +TurboDocx rejects non-HTTPS webhook URLs with HTTP 400. For local development, expose your receiver via an HTTPS tunnel ([ngrok](https://ngrok.com), [cloudflared](https://github.com/cloudflare/cloudflared), etc.) and pass the tunnel URL to `create_webhook`. +::: + @@ -1657,6 +1854,50 @@ The signature contract: | Tolerance | 300 seconds (configurable via the 6-arg `verify` overload) | | Comparison | `MessageDigest.isEqual` (constant-time) | + + + +When TurboDocx POSTs to your receiver, every request carries an `X-TurboDocx-Signature` header. Verify it before trusting the payload — the helper enforces a 300-second timestamp tolerance and uses constant-time comparison. + +```ruby +require "turbodocx_sdk" + +# In your Rack/Rails/Sinatra webhook handler: +raw_body = request.body.read # raw bytes — do NOT JSON.parse first +signature = request.get_header("HTTP_X_TURBODOCX_SIGNATURE") || "" +timestamp = request.get_header("HTTP_X_TURBODOCX_TIMESTAMP") || "" +secret = ENV["TURBODOCX_WEBHOOK_SECRET"] + +unless TurboDocxSdk.verify_webhook_signature( + payload: raw_body, + signature_header: signature, + timestamp_header: timestamp, + secret: secret +) + return [401, {}, ["invalid signature"]] +end + +event = JSON.parse(raw_body) +# process event["event"], event["data"], ... (NOT "eventType" — not on the wire) + +[200, {}, ["ok"]] +``` + +:::danger Use the raw request body +The HMAC is computed over the **exact bytes** that left the TurboDocx server. Never `JSON.parse` and re-serialize before verifying — re-encoded JSON will not byte-match and verification will fail. +::: + +The signature contract: + +| Field | Value | +|---|---| +| Header | `X-TurboDocx-Signature: sha256=` | +| Timestamp header | `X-TurboDocx-Timestamp: ` | +| Signed string | `.` | +| Algorithm | HMAC-SHA256 | +| Tolerance | 300 seconds (configurable) | +| Comparison | constant-time | + @@ -1687,6 +1928,11 @@ All methods are instance methods on `*turbodocx.WebhooksClient`. Construct once, All methods are instance methods on `com.turbodocx.TurboWebhooks`. Construct once via `new TurboDocxClient.Builder()...buildWebhooksClient()` and reuse. + + + +All methods are class-level; call `TurboDocxSdk::TurboWebhooks.configure` once, then invoke any method directly on the class. + @@ -1841,6 +2087,32 @@ The URL list accepts **1 to 10** HTTPS URLs. The events list requires **at least | `TurboDocxException.ValidationException` (400) | A URL is not HTTPS, the URL list is empty or has more than 10 entries, or the events list is empty. | | `TurboDocxException.AuthorizationException` (403) | API key lacks the administrator role. | + + + +Subscribe the org to events. Returns `{ "id" => ..., "secret" => ... }` — the **secret is shown once**. + +```ruby +created = TurboDocxSdk::TurboWebhooks.create_webhook( + urls: ["https://your-server.example.com/webhooks/turbodocx"], + events: [ + TurboDocxSdk::WebhookEvent::RECIPIENT_SIGNED, + TurboDocxSdk::WebhookEvent::COMPLETED, + TurboDocxSdk::WebhookEvent::FINALIZATION_FAILED, + TurboDocxSdk::WebhookEvent::VOIDED + ] + # or subscribe to all 7: events: TurboDocxSdk::WebhookEvent::ALL +) +``` + +`urls` accepts **1 to 10** HTTPS URLs. `events` requires **at least 1** of the [seven events](#webhook-events) — raw strings and `TurboDocxSdk::WebhookEvent::*` constants are interchangeable (the constants *are* strings). Both are required on create. + +| Raises | Why | +|---|---| +| `TurboDocxSdk::ConflictError` (409) | The signature webhook already exists for this org. | +| `TurboDocxSdk::ValidationError` (400) | A URL is not HTTPS, `urls` is empty or has more than 10 entries, or `events` is empty. | +| `TurboDocxSdk::AuthorizationError` (403) | API key lacks the administrator role. | + @@ -1912,6 +2184,21 @@ JsonObject webhook = webhooks.getWebhook(); // webhook.get("availableEvents") ``` + + + +Get the org's signature webhook plus delivery statistics. + +```ruby +webhook = TurboDocxSdk::TurboWebhooks.get_webhook +# webhook["urls"], webhook["events"], webhook["isActive"] +# webhook["deliveryStats"]["totalDeliveries"] +# webhook["deliveryStats"]["successfulDeliveries"] +# webhook["deliveryStats"]["failedDeliveries"] +# webhook["deliveryStats"]["pendingRetries"] +# webhook["availableEvents"] +``` + @@ -2027,6 +2314,26 @@ JsonObject deactivated = webhooks.updateWebhook(null, null, Boolean.FALSE); `urls` and `events` are optional on update, but optional does **not** relax their minimum length. An empty list serializes to `urls: []` / `events: []`, which the API rejects with a **400** — exactly as it would on create. To leave a field unchanged, pass `null` so the key is omitted; never pass `Collections.emptyList()`. The URL list still caps at 10 entries on update. ::: + + + +Patch one or more fields. All parameters are optional — pass only what changes; untouched fields are omitted from the request. + +```ruby +TurboDocxSdk::TurboWebhooks.update_webhook( + urls: ["https://your-server.example.com/webhooks/turbodocx"], + events: ["signature.document.completed"], + is_active: true +) + +# Leaving urls and events alone: just don't pass those keyword arguments. +TurboDocxSdk::TurboWebhooks.update_webhook(is_active: false) +``` + +:::danger Never send an empty array +`urls` and `events` are optional on update, but optional does **not** relax their minimum length. `urls: []` or `events: []` is a **400** — the same as sending an empty array on create. To leave a field unchanged, **omit the keyword argument entirely**. `urls` still caps at 10 entries on update. +::: + @@ -2071,6 +2378,13 @@ _, err := wh.DeleteWebhook(ctx) JsonObject deleted = webhooks.deleteWebhook(); ``` + + + +```ruby +TurboDocxSdk::TurboWebhooks.delete_webhook +``` + @@ -2171,6 +2485,21 @@ if (summary.has("errors") && summary.get("errors").isJsonArray()) { `notifyWebhook` is also exposed for symmetry with the backend surface — it routes through the same handler and returns the same shape. Prefer `testWebhook` in new code. + + + +```ruby +result = TurboDocxSdk::TurboWebhooks.test_webhook( + event_type: "signature.document.completed", + payload: { "documentId" => "...", "documentName" => "..." } +) + +puts "#{result['summary']['successful']}/#{result['summary']['total']} succeeded" +result["summary"]["errors"].each do |err| + puts " failure: #{err}" # per-URL failure messages +end +``` + @@ -2227,6 +2556,18 @@ $result = TurboWebhooks::notifyWebhook( `notifyWebhook` exists for cross-SDK parity. For smoke-testing a receiver, use [`testWebhook`](#testwebhook) — same behaviour, clearer intent. ::: + + + +Send a manual notification to every configured URL. Routes through the same backend handler as `test_webhook` and returns the same shape; prefer `test_webhook` in new code. + +```ruby +TurboDocxSdk::TurboWebhooks.notify_webhook( + event_type: "signature.document.voided", + payload: { "documentId" => "..." } +) +``` + @@ -2281,6 +2622,15 @@ String newSecret = rotated.get("secret").getAsString(); // rotated.get("regeneratedAt") ``` + + + +```ruby +rotated = TurboDocxSdk::TurboWebhooks.regenerate_webhook_secret +# rotated["secret"] +# rotated["regeneratedAt"] +``` + @@ -2375,6 +2725,23 @@ JsonObject page = webhooks.listWebhookDeliveries( // page.get("totalRecords") ``` + + + +Page through historical delivery attempts with filters. + +```ruby +page = TurboDocxSdk::TurboWebhooks.list_webhook_deliveries( + limit: 20, + offset: 0, + event_type: "signature.document.completed", + is_delivered: false, + http_status: 500 +) +# page["results"]: array of delivery rows +# page["totalRecords"] +``` + @@ -2424,6 +2791,14 @@ JsonObject replayed = webhooks.replayWebhookDelivery("delivery-uuid-here"); // replayed.get("id"), replayed.get("httpStatus"), replayed.get("attemptCount"), ... ``` + + + +```ruby +replay = TurboDocxSdk::TurboWebhooks.replay_webhook_delivery("delivery-uuid-here") +# replay["id"], replay["httpStatus"], replay["attemptCount"], ... +``` + @@ -2491,6 +2866,18 @@ JsonObject stats = webhooks.getWebhookStats(30); // stats.get("eventBreakdown") (per-event totals) ``` + + + +Aggregate delivery stats over a sliding window. + +```ruby +stats = TurboDocxSdk::TurboWebhooks.get_webhook_stats(days: 30) +# stats["summary"]["successRate"] +# stats["summary"]["avgResponseTime"] (milliseconds) +# stats["eventBreakdown"] (per-event totals) +``` + @@ -2583,6 +2970,23 @@ boolean ok = WebhookSignatureVerifier.verify( A `String` body overload is provided for convenience (`verify(String rawBody, ...)`), and a 6-arg overload accepts a custom `toleranceSeconds` plus an optional `LongSupplier now` for testing. Pass `toleranceSeconds = 0` to disable the timestamp check entirely (NOT recommended in production). + + + +Verify the `X-TurboDocx-Signature` header on an incoming request. It is a module-level function (`TurboDocxSdk.verify_webhook_signature`) and does **not** require `TurboWebhooks.configure` — receivers commonly run in a different process than the management code. It never raises on bad input; it always returns a boolean. + +```ruby +ok = TurboDocxSdk.verify_webhook_signature( + payload: raw_body, + signature_header: signature_header, + timestamp_header: timestamp_header, + secret: webhook_secret, + tolerance_seconds: 300 # default; pass 0 to disable the timestamp check (NOT recommended) +) +``` + +A negative `tolerance_seconds` **fails closed** (rejects every signature) rather than silently disabling the replay-window check. + @@ -2928,6 +3332,93 @@ def turbodocx_webhook(request): + + + + + + +Configure TurboWebhooks once in an initializer, then add a controller for the receiver. + +```ruby +# config/initializers/turbodocx.rb +require "turbodocx_sdk" + +TurboDocxSdk::TurboWebhooks.configure( + api_key: Rails.application.credentials.dig(:turbodocx, :api_key), + org_id: Rails.application.credentials.dig(:turbodocx, :org_id) +) +``` + +```ruby +# app/controllers/webhooks_controller.rb +class WebhooksController < ApplicationController + # Webhook receivers are server-to-server — skip CSRF. + skip_before_action :verify_authenticity_token + + def turbodocx + raw_body = request.body.read + signature = request.headers["X-TurboDocx-Signature"].to_s + timestamp = request.headers["X-TurboDocx-Timestamp"].to_s + secret = Rails.application.credentials.dig(:turbodocx, :webhook_secret) + + unless TurboDocxSdk.verify_webhook_signature( + payload: raw_body, signature_header: signature, timestamp_header: timestamp, secret: secret + ) + return head :unauthorized + end + + event = JSON.parse(raw_body) + case event["event"] + # fires once per signer — event.dig("data", "is_final_signer") marks the last + when TurboDocxSdk::WebhookEvent::RECIPIENT_SIGNED then on_recipient_signed(event["data"]) + # partial progress only — NEVER fires on the final signature + when TurboDocxSdk::WebhookEvent::SIGNED then on_partial_progress(event["data"]) + # the document is done + when TurboDocxSdk::WebhookEvent::COMPLETED then on_completed(event["data"]) + when TurboDocxSdk::WebhookEvent::FINALIZATION_FAILED then on_finalization_failed(event["data"]) + when TurboDocxSdk::WebhookEvent::VOIDED then on_voided(event["data"]) + end + + head :ok + end +end +``` + +```ruby +# config/routes.rb +post "/webhooks/turbodocx", to: "webhooks#turbodocx" +``` + + + + +```ruby +require "sinatra" +require "turbodocx_sdk" + +post "/webhooks/turbodocx" do + raw_body = request.body.read + signature = request.env["HTTP_X_TURBODOCX_SIGNATURE"].to_s + timestamp = request.env["HTTP_X_TURBODOCX_TIMESTAMP"].to_s + + halt 401 unless TurboDocxSdk.verify_webhook_signature( + payload: raw_body, + signature_header: signature, + timestamp_header: timestamp, + secret: ENV["TURBODOCX_WEBHOOK_SECRET"] + ) + + event = JSON.parse(raw_body) + # process event["event"], event["data"], ... (NOT "eventType" — not on the wire) + status 200 + "ok" +end +``` + + + + @@ -3119,6 +3610,34 @@ try { } ``` + + + +```ruby +begin + TurboDocxSdk::TurboWebhooks.create_webhook(urls: urls, events: events) +rescue TurboDocxSdk::ConflictError + # 409 — signature webhook already exists; update or delete it instead +rescue TurboDocxSdk::ValidationError + # 400 — non-HTTPS URL, empty events array, etc. +rescue TurboDocxSdk::AuthorizationError + # 403 — API key lacks the administrator role +rescue TurboDocxSdk::AuthenticationError + # 401 — bad or revoked API key +rescue TurboDocxSdk::NotFoundError + # 404 — read/update/delete against a webhook that doesn't exist +rescue TurboDocxSdk::RateLimitError + # 429 — back off and retry +rescue TurboDocxSdk::NetworkError + # request never reached the server (DNS, refused, timeout) +rescue TurboDocxSdk::TurboDocxError => e + # base class for any other typed SDK error (raw 5xx, etc.) + puts "Error #{e.status_code}: #{e.message}" +end +``` + +All errors inherit from `TurboDocxSdk::TurboDocxError` and carry `status_code` and `code` readers. + @@ -3184,6 +3703,18 @@ try { | 409 | `TurboDocxException.ConflictException` | Creating when the signature webhook already exists | | 429 | `TurboDocxException.RateLimitException` | Rate limit exceeded — back off | + + + +| Status | Error | When | +|---|---|---| +| 400 | `ValidationError` | Non-HTTPS URL, empty `urls`/`events` array, more than 10 URLs, invalid body | +| 401 | `AuthenticationError` | Missing or invalid API key | +| 403 | `AuthorizationError` | Valid key without administrator role | +| 404 | `NotFoundError` | Operating on a non-existent webhook | +| 409 | `ConflictError` | Creating when the signature webhook already exists | +| 429 | `RateLimitError` | Rate limit exceeded — back off | + @@ -3226,6 +3757,13 @@ It exercises every CRUD step plus every error branch (400 / 401 / 403 / 404 / 40 It exercises every CRUD step plus every error branch (400 / 401 / 403 / 404 / 409) against a live backend. Run it after exporting `TURBODOCX_API_KEY` and `TURBODOCX_ORG_ID`; override `TURBODOCX_RECEIVER_URL` to point at a real receiver (e.g. webhook.site, ngrok). + + + +**[`packages/ruby-sdk/examples/turbowebhooks_crud.rb`](https://github.com/TurboDocx/SDK/blob/main/packages/ruby-sdk/examples/turbowebhooks_crud.rb)** + +It exercises every CRUD step plus every error branch (400 / 401 / 403 / 404 / 409) against a live backend. + @@ -3299,6 +3837,19 @@ It exercises every CRUD step plus every error branch (400 / 401 / 403 / 404 / 40 - **`createWebhook` takes wire strings, not enum constants.** Pass `WebhookEvent.COMPLETED.getValue()` — the events parameter is `List`. `WebhookEvent.allValues()` returns all 7 wire strings in one call (as an unmodifiable list; copy it if you need to mutate). - **`signature.document.signed` is partial progress, not completion.** It never fires on the final signature, and a single-signer document never emits it at all. Use `WebhookEvent.COMPLETED` to detect a finished document. See [Webhook Events](#webhook-events). + + + +- **One webhook per org.** Every method targets the fixed-name `signature` webhook. Creating it twice raises `ConflictError` (409). To manage multiple webhooks per org, call the REST API directly. +- **Save the secret immediately.** `create_webhook` and `regenerate_webhook_secret` return the HMAC secret **once**. There is no endpoint to retrieve it later. If you lose it, rotate. +- **Use the raw bytes for verification.** The HMAC is over the exact request body received. Never `JSON.parse` first. +- **`verify_webhook_signature` uses keyword arguments** (`payload:`, `signature_header:`, `timestamp_header:`, `secret:`) — not positional args. +- **`verify_webhook_signature` never raises.** Non-String headers, a missing secret, or a malformed timestamp all return `false` rather than raising; a negative `tolerance_seconds` fails closed. +- **`update_webhook` only sends what you pass.** Omitted keyword arguments are excluded from the PATCH body, so you can flip `is_active` without resending `urls`/`events`. +- **An empty array is not "no change".** `urls: []` and `events: []` are 400s on update, not no-ops — omitting the keyword is the only way to leave a field alone. +- **`signature.document.signed` is partial progress, not completion.** It never fires on the final signature, and a single-signer document never emits it at all. Use `TurboDocxSdk::WebhookEvent::COMPLETED` to detect a finished document. See [Webhook Events](#webhook-events). +- **`WebhookEvent::ALL` is frozen.** It's the canonical list of all 7 events — `dup` it before mutating. + @@ -3357,5 +3908,16 @@ It exercises every CRUD step plus every error branch (400 / 401 / 403 / 404 / 40 - [SDKs Overview](/docs/SDKs) — all SDKs across all six languages - [TurboDocx SDK on GitHub](https://github.com/TurboDocx/SDK/tree/main/packages/java-sdk) + + + +- [TurboSign → Webhooks](/docs/TurboSign/Webhooks) — concepts, dashboard UI, retry behavior +- [TurboWebhooks JavaScript / TypeScript SDK](/docs/SDKs/webhooks?language=js) — same API, JS idioms +- [TurboWebhooks Python SDK](/docs/SDKs/webhooks?language=python) — same API, Python idioms +- [TurboSign Ruby SDK](/docs/SDKs/turbosign?language=ruby) — sending documents for signature +- [SDKs Overview](/docs/SDKs) — all SDKs across all supported languages +- [TurboDocx SDK on RubyGems](https://rubygems.org/gems/turbodocx-sdk) +- [TurboDocx SDK on GitHub](https://github.com/TurboDocx/SDK/tree/main/packages/ruby-sdk) + diff --git a/docs/TurboSign/Webhooks.md b/docs/TurboSign/Webhooks.md index b04334b2..c99d9710 100644 --- a/docs/TurboSign/Webhooks.md +++ b/docs/TurboSign/Webhooks.md @@ -37,7 +37,7 @@ keywords: Webhooks enable your application to receive real-time notifications when important events occur in TurboSign. Instead of polling for changes, webhooks push event data to your specified endpoints immediately across the whole signature lifecycle — when a document is sent, viewed, signed by each recipient, completed, voided, or fails to finalize. -![Get It Signed button on TurboDocx homepage](/img/webhooks/webhook-schema.png) +![Diagram comparing webhooks, which push new data to your app, with APIs, which your app has to ask for data](/img/webhooks/webhook-schema.png) ## Overview @@ -46,7 +46,7 @@ TurboSign webhooks provide a robust and secure way to integrate document signatu ### Key Features - **Real-time Notifications**: Receive instant updates when documents are signed or voided -- **Multiple URLs**: Configure up to 5 webhook URLs per configuration +- **Multiple URLs**: Configure up to 10 webhook URLs per configuration - **Secure Authentication**: HMAC-SHA256 signature verification ensures webhook authenticity - **Reliable Delivery**: Automatic retry logic with up to 3 attempts per webhook - **Delivery History**: Track and replay webhook deliveries with detailed logs @@ -68,21 +68,21 @@ Webhooks can be configured from the E-Signature settings on the **Features and i ![Settings menu with Features and integrations highlighted](/img/webhooks/features-and-integrations-link.png) -3. **Open E-Signature Settings and go to the Webhooks tab** +3. **Open E-Signature Settings and select Webhooks** - Scroll down to the **Core Features** section, find the **Signatures** card, and click **"Configure E-Signature"** ![Features and integrations page with the Configure E-Signature button on the Signatures card highlighted](/img/webhooks/core-features-section.png) - - In the **E-Signature Settings** dialog that opens, select the **"Webhooks"** tab + - In the **E-Signature Settings** dialog that opens, select **Webhooks** in the left menu 4. **Add Webhook URLs** - Enter your webhook endpoint URL(s) - - You can add up to 5 different URLs + - You can add up to 10 different URLs - Each URL will receive all subscribed events - - URLs must use HTTPS for production environments + - Every URL must use HTTPS (plain `http://` is rejected, even for testing). To receive webhooks on your machine, expose your local server through an HTTPS tunnel such as ngrok or Cloudflare Tunnel -![E-Signature Settings Webhooks tab showing the Webhook URLs field and the Add Another URL button](/img/webhooks/signature-webhook-config.png) +![E-Signature Settings Webhooks section showing the Webhook URLs field and the Add Another URL button](/img/webhooks/signature-webhook-config.png) 5. **Select Events to Subscribe** - Choose which events should trigger webhooks: @@ -101,7 +101,7 @@ Webhooks can be configured from the E-Signature settings on the **Features and i - Your webhook secret key will be displayed (only shown once for new configurations) - **Important**: Copy and securely store your webhook secret - it won't be shown again -![E-Signature Settings Webhooks tab with the Save Configuration button highlighted](/img/webhooks/dill-signature-webhook-config.png) +![E-Signature Settings Webhooks section with the Save Configuration button highlighted](/img/webhooks/dill-signature-webhook-config.png) ![Webhook secret key displayed after saving the configuration](/img/webhooks/copy-webhook-secret.png) ### Managing Webhook Configuration @@ -113,10 +113,10 @@ The Delivery History tab shows all webhook delivery attempts with detailed infor - **Event Type**: The type of event that triggered the webhook - **HTTP Status**: Response status code from your endpoint - **Attempts**: Number of delivery attempts made -- **Timestamps**: When the webhook was created and last updated -- **Actions**: View details or replay failed deliveries +- **Timestamps**: When each delivery was created and last updated +- **Actions**: View details or replay any delivery -![Get It Signed button on TurboDocx homepage](/img/webhooks/delivery-history.png) +![Delivery History tab listing a webhook delivery with its event type, HTTP status, attempts, and the view and replay actions highlighted](/img/webhooks/delivery-history.png) #### Webhook Secret Management @@ -127,7 +127,7 @@ Your webhook secret is used to verify that webhooks are genuinely from TurboDocx - **Regeneration**: You can regenerate the secret at any time if compromised - **Display**: After initial viewing, only a masked version (first 3 + \*\*\* + last 3 characters) is shown -![Get It Signed button on TurboDocx homepage](/img/webhooks/regenerate-secret.png) +![Webhook Secret Key field showing the masked secret, with the regenerate button highlighted](/img/webhooks/regenerate-secret.png) ## Webhook Events @@ -394,7 +394,7 @@ Each webhook request includes these headers: | `X-TurboDocx-Signature` | HMAC signature for verification (format: `sha256=`) | | `X-TurboDocx-Timestamp` | Unix timestamp when the webhook was sent | | `X-TurboDocx-Event` | The event type that triggered this webhook | -| `X-TurboDocx-Delivery-Id` | Unique ID for this delivery attempt (for idempotency) | +| `X-TurboDocx-Delivery-Id` | Unique ID for this delivery attempt. A retry gets a new one, so dedupe on the payload's `event_id` instead. It is not the delivery `id` shown in Delivery History or returned by the API (use that `id` to replay) | ### Try it Now @@ -406,7 +406,7 @@ Each webhook request includes these headers: ### SDK Verification Examples -Our SDKs include built-in webhook verification. The snippets below show the minimum receiver code; for the full SDK reference (createWebhook, updateWebhook, testWebhook, listWebhookDeliveries, replayWebhookDelivery, rotateSecret, framework integration patterns, and gotchas), see the dedicated TurboWebhooks SDK pages: +Our SDKs include built-in webhook verification. The snippets below show the minimum receiver code; for the full SDK reference (createWebhook, updateWebhook, testWebhook, listWebhookDeliveries, replayWebhookDelivery, regenerateWebhookSecret, framework integration patterns, and gotchas), see the dedicated TurboWebhooks SDK pages: - [TurboWebhooks JavaScript / TypeScript SDK](/docs/SDKs/webhooks?language=js) - [TurboWebhooks Python SDK](/docs/SDKs/webhooks?language=python) @@ -423,25 +423,22 @@ import TabItem from '@theme/TabItem'; ```typescript -import { verifyWebhookSignature } from '@turbodocx/sdk'; import express from 'express'; +import { verifyWebhookSignature } from '@turbodocx/sdk'; const app = express(); +// Use express.raw: the signature is computed over the raw bytes. app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => { - const isValid = verifyWebhookSignature({ - signature: req.headers['x-turbodocx-signature'], - timestamp: req.headers['x-turbodocx-timestamp'], - body: req.body, - secret: process.env.TURBODOCX_WEBHOOK_SECRET - }); - - if (!isValid) { + const signature = req.header('x-turbodocx-signature') ?? ''; + const timestamp = req.header('x-turbodocx-timestamp') ?? ''; + + if (!verifyWebhookSignature(req.body, signature, timestamp, process.env.TURBODOCX_WEBHOOK_SECRET!)) { return res.status(401).json({ error: 'Invalid signature' }); } - const event = JSON.parse(req.body.toString()); - // Process event... + const event = JSON.parse(req.body.toString('utf8')); + // Process event.event, event.event_id, event.data... res.status(200).json({ received: true }); }); ``` @@ -450,82 +447,151 @@ app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => { ```python -from turbodocx import verify_webhook_signature -from fastapi import FastAPI, Request, HTTPException +import json +import os + +from fastapi import FastAPI, HTTPException, Request +from turbodocx_sdk import verify_webhook_signature app = FastAPI() @app.post("/webhook") async def handle_webhook(request: Request): - body = await request.body() - - is_valid = verify_webhook_signature( - signature=request.headers.get("x-turbodocx-signature"), - timestamp=request.headers.get("x-turbodocx-timestamp"), - body=body, - secret=os.environ["TURBODOCX_WEBHOOK_SECRET"] - ) + raw_body = await request.body() # raw bytes: the signature is computed over them + signature = request.headers.get("x-turbodocx-signature", "") + timestamp = request.headers.get("x-turbodocx-timestamp", "") - if not is_valid: + if not verify_webhook_signature(raw_body, signature, timestamp, os.environ["TURBODOCX_WEBHOOK_SECRET"]): raise HTTPException(status_code=401, detail="Invalid signature") - event = json.loads(body) - # Process event... + event = json.loads(raw_body) + # Process event["event"], event["event_id"], event["data"]... return {"received": True} ``` + + + +```php + ```go -func webhookHandler(w http.ResponseWriter, r *http.Request) { - body, _ := io.ReadAll(r.Body) +package main + +import ( + "encoding/json" + "io" + "log" + "net/http" + "os" - isValid := sdk.VerifyWebhookSignature( - r.Header.Get("X-TurboDocx-Signature"), - r.Header.Get("X-TurboDocx-Timestamp"), - body, - os.Getenv("TURBODOCX_WEBHOOK_SECRET"), - ) + turbodocx "github.com/TurboDocx/SDK/packages/go-sdk" +) + +func webhookHandler(w http.ResponseWriter, r *http.Request) { + rawBody, err := io.ReadAll(r.Body) // raw bytes: the signature is computed over them + if err != nil { + http.Error(w, "read failed", http.StatusBadRequest) + return + } - if !isValid { + signature := r.Header.Get("X-TurboDocx-Signature") + timestamp := r.Header.Get("X-TurboDocx-Timestamp") + if !turbodocx.VerifyWebhookSignature(rawBody, signature, timestamp, os.Getenv("TURBODOCX_WEBHOOK_SECRET"), nil) { http.Error(w, "Invalid signature", http.StatusUnauthorized) return } - var event sdk.WebhookEvent - json.Unmarshal(body, &event) - // Process event... + var event struct { + Event string `json:"event"` + EventID string `json:"event_id"` + Data json.RawMessage `json:"data"` + } + if err := json.Unmarshal(rawBody, &event); err != nil { + http.Error(w, "bad payload", http.StatusBadRequest) + return + } + // Process event.Event, event.EventID, event.Data... w.WriteHeader(http.StatusOK) } + +func main() { + http.HandleFunc("/webhook", webhookHandler) + log.Fatal(http.ListenAndServe(":8080", nil)) +} ``` - + -```csharp -[HttpPost] -public async Task HandleWebhook() -{ - using var reader = new StreamReader(Request.Body); - var body = await reader.ReadToEndAsync(); - - var isValid = WebhookVerifier.VerifySignature( - Request.Headers["X-TurboDocx-Signature"], - Request.Headers["X-TurboDocx-Timestamp"], - body, - _configuration["TurboDocx:WebhookSecret"] - ); - - if (!isValid) - return Unauthorized("Invalid signature"); - - var webhookEvent = JsonSerializer.Deserialize(body); - // Process event... - return Ok(new { Received = true }); +```java +import com.turbodocx.WebhookSignatureVerifier; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@RestController +public class WebhookController { + + // Bind the body to byte[]: the signature is computed over the raw bytes. + @PostMapping(value = "/webhook", consumes = "application/json") + public ResponseEntity handleWebhook( + @RequestBody byte[] rawBody, + @RequestHeader("X-TurboDocx-Signature") String signature, + @RequestHeader("X-TurboDocx-Timestamp") String timestamp) { + + if (!WebhookSignatureVerifier.verify(rawBody, signature, timestamp, System.getenv("TURBODOCX_WEBHOOK_SECRET"))) { + return ResponseEntity.status(401).build(); + } + + // Parse rawBody as JSON and process "event", "event_id", "data"... + return ResponseEntity.ok().build(); + } } ``` + + + +```ruby +require "json" +require "sinatra" +require "turbodocx_sdk" + +post "/webhook" do + raw_body = request.body.read # raw bytes: the signature is computed over them + + valid = TurboDocxSdk.verify_webhook_signature( + payload: raw_body, + signature_header: request.env["HTTP_X_TURBODOCX_SIGNATURE"].to_s, + timestamp_header: request.env["HTTP_X_TURBODOCX_TIMESTAMP"].to_s, + secret: ENV.fetch("TURBODOCX_WEBHOOK_SECRET") + ) + halt 401, "Invalid signature" unless valid + + event = JSON.parse(raw_body) + # Process event["event"], event["event_id"], event["data"]... + status 200 +end +``` + @@ -534,11 +600,11 @@ public async Task HandleWebhook() ### Security Best Practices 1. **Always verify signatures**: Never process webhooks without verifying the signature -2. **Use HTTPS**: Always use HTTPS endpoints in production +2. **Use HTTPS**: Webhook URLs must be HTTPS; TurboDocx rejects `http://` URLs, so use an HTTPS tunnel when testing locally 3. **Store secrets securely**: Keep webhook secrets in environment variables or secure vaults 4. **Implement timestamp validation**: Reject webhooks with timestamps older than 5 minutes 5. **Use timing-safe comparison**: Prevent timing attacks when comparing signatures -6. **Handle retries idempotently**: Use the `X-TurboDocx-Delivery-Id` to prevent duplicate processing +6. **Handle retries idempotently**: Dedupe on the payload's `event_id`, which stays the same across retries (`X-TurboDocx-Delivery-Id` changes on every attempt). A manual replay resends the same payload, so it keeps the same `event_id` too: if you want a replay to be processed again, clear that event's record first 7. **Respond quickly**: Return 200 OK immediately and process webhooks asynchronously 8. **Log failures**: Keep logs of signature verification failures for security monitoring @@ -547,9 +613,9 @@ public async Task HandleWebhook() ### Delivery Behavior - **Timeout**: Each delivery attempt has a 10-second timeout -- **Success Criteria**: Only HTTP 2xx status codes are considered successful -- **Retry Logic**: Failed deliveries are automatically retried up to 3 times -- **Retry Schedule**: Exponential backoff between retry attempts +- **Success Criteria**: Only HTTP 2xx status codes are considered successful; redirects (3xx) are not followed and count as a failure +- **Retry Logic**: Failed deliveries are automatically retried up to 2 more times (3 attempts in total) +- **Retry Schedule**: Exponential backoff: the 2nd attempt about 1 minute after the 1st, the 3rd about 5 minutes after the 2nd - **Delivery Order**: Webhooks are delivered to all configured URLs in parallel ### Handling Failures @@ -558,7 +624,7 @@ When a webhook delivery fails: 1. **Automatic Retries**: The system will automatically retry failed deliveries 2. **Delivery History**: All attempts are logged in the delivery history -3. **Manual Replay**: You can manually replay failed deliveries from the UI +3. **Manual Replay**: You can manually replay any delivery from the UI 4. **Error Details**: Response status codes and error messages are captured @@ -584,6 +650,8 @@ You can test your webhook configuration before going live: 4. **Check the Delivery History** to verify successful delivery 5. **Verify your endpoint** received and processed the webhook correctly +To send a sample event without signing a document, call `testWebhook` from the [TurboWebhooks SDK](/docs/SDKs#turbowebhooks-sdks). It is delivered, signed and retried like a real event, and appears in the Delivery History. Its payload is sample data, not a real document: the IDs are placeholders, `event_id` starts with `evt_test_`, and a few `data` fields differ from real events, so don't look the document up or rely on exact field names from a test event. If your endpoint fails, the call returns only after all 3 attempts, about 6 minutes. + ### Development Tools For local development, consider using: @@ -627,7 +695,7 @@ For local development, consider using: - Ensure you're using the raw request body (not parsed JSON) - Verify the webhook secret matches exactly -- Check that header names are lowercase in your code +- Check that you read the `X-TurboDocx-Signature` and `X-TurboDocx-Timestamp` headers by name; header names are case-insensitive, so match your framework's lookup (Express lowercases them, Go's `Header.Get` and Spring accept any case) - Confirm timestamp validation isn't too strict #### Timeouts @@ -647,7 +715,7 @@ For local development, consider using: **Solutions**: -- Implement idempotency using `X-TurboDocx-Delivery-Id` +- Implement idempotency using the payload's `event_id` (the same on every retry; `X-TurboDocx-Delivery-Id` is new on each attempt) - Store processed event IDs temporarily - Use database constraints to prevent duplicates @@ -666,8 +734,8 @@ If you encounter issues not covered here: ```json { - "id": "webhook_abc123", - "orgId": "org_xyz789", + "id": "6f1c2d3e-4b5a-4c7d-8e9f-0a1b2c3d4e5f", + "orgId": "9a8b7c6d-5e4f-4a3b-9c2d-1e0f9a8b7c6d", "name": "signature", "urls": [ "https://api.example.com/webhooks/turbosign", @@ -684,30 +752,45 @@ If you encounter issues not covered here: ], "secretExists": true, "maskedSecret": "whs***f6a", - "isActive": true, + "isActive": 1, + "metadata": null, + "createdBy": "3c2b1a0f-9e8d-4c7b-a6f5-e4d3c2b1a0f9", "createdOn": "2024-01-15T09:00:00.000Z", - "updatedOn": "2024-01-15T09:00:00.000Z" + "updatedOn": "2024-01-15T09:00:00.000Z", + "deliveryStats": { + "totalDeliveries": 4, + "successfulDeliveries": 3, + "failedDeliveries": 1, + "pendingRetries": 0 + } } ``` +Fetching a single webhook also returns `availableEvents`, the list of events you can subscribe to. Boolean flags such as `isActive` and the delivery's `isDelivered` come back as `1` / `0`, so check them as truthy values rather than comparing with `true`. + ### Delivery Object ```json { - "id": "delivery_def456", - "webhookId": "webhook_abc123", + "id": "0ebddb5e-7c1a-4f2b-9d3e-5a6b7c8d9e0f", "eventType": "signature.document.completed", "url": "https://api.example.com/webhooks/turbosign", "httpStatus": 200, + "responseBody": "{\"received\":true}", "attemptCount": 1, "maxAttempts": 3, - "isDelivered": true, + "isDelivered": 1, "deliveredAt": "2024-01-15T10:30:05.000Z", + "nextRetryAt": null, + "errorMessage": null, + "status": "delivered", "createdOn": "2024-01-15T10:30:00.000Z", "updatedOn": "2024-01-15T10:30:05.000Z" } ``` +`status` is one of `delivered`, `retrying`, `failed` (all attempts used) or `pending`. + --- diff --git a/docs/TurboSign/embedded-signing/index.md b/docs/TurboSign/embedded-signing/index.md index ee070132..37574bff 100644 --- a/docs/TurboSign/embedded-signing/index.md +++ b/docs/TurboSign/embedded-signing/index.md @@ -103,10 +103,6 @@ Requesting a signing URL needs an **Administrator** or **Contributor** key. A ** You can allow `http://localhost` origins to test on your machine. Remove every `http://` origin before you go live; production origins must be `https://`. ::: -:::note Ruby -The Ruby tabs in these guides show the Ruby SDK API. The `turbodocx-sdk` gem is not on RubyGems yet; until it is, install it from the [TurboDocx SDK repository](https://github.com/TurboDocx/SDK/tree/main/packages/ruby-sdk). -::: - ## The flow, end to end 1. Your backend prepares the document with an embedded recipient and `sendEmail: false`, then stores the returned `documentId` on the customer record. diff --git a/sidebars.js b/sidebars.js index 66c4b52c..7f867d4a 100644 --- a/sidebars.js +++ b/sidebars.js @@ -193,6 +193,11 @@ const sidebars = { id: 'SDKs/java', label: 'Java', }, + { + type: 'doc', + id: 'SDKs/ruby', + label: 'Ruby', + }, ], }, { diff --git a/src/theme/Root.js b/src/theme/Root.js index 54909bd6..78dd2a17 100644 --- a/src/theme/Root.js +++ b/src/theme/Root.js @@ -84,10 +84,10 @@ function scrollToHashTarget(hash) { // like /docs/SDKs/python#get-status points at a section that is no longer on the setup page, so once // the page has rendered and the anchor is still missing, hop to the same anchor on the TurboSign page // with that language's tab selected. Anchors that still exist on the setup page are left alone. -const MOVED_TURBOSIGN = { javascript: 'js', python: 'python', php: 'php', go: 'go', java: 'java' }; +const MOVED_TURBOSIGN = { javascript: 'js', python: 'python', php: 'php', go: 'go', java: 'java', ruby: 'ruby' }; function hopToMovedSection(pathname, hash) { - const m = pathname.match(/^\/docs\/SDKs\/(javascript|python|php|go|java)\/?$/); + const m = pathname.match(/^\/docs\/SDKs\/(javascript|python|php|go|java|ruby)\/?$/); if (!m) return null; let id; try { diff --git a/static/_redirects b/static/_redirects index a073df76..85902aaa 100644 --- a/static/_redirects +++ b/static/_redirects @@ -16,6 +16,9 @@ /docs/SDKs/deliverable-java /docs/SDKs/deliverable?language=java 301 /docs/SDKs/deliverable-java/ /docs/SDKs/deliverable?language=java 301 /docs/SDKs/deliverable-java.html /docs/SDKs/deliverable?language=java 301 +/docs/SDKs/deliverable-ruby /docs/SDKs/deliverable?language=ruby 301 +/docs/SDKs/deliverable-ruby/ /docs/SDKs/deliverable?language=ruby 301 +/docs/SDKs/deliverable-ruby.html /docs/SDKs/deliverable?language=ruby 301 /docs/SDKs/quote-javascript /docs/SDKs/quote?language=js 301 /docs/SDKs/quote-javascript/ /docs/SDKs/quote?language=js 301 /docs/SDKs/quote-javascript.html /docs/SDKs/quote?language=js 301 @@ -31,6 +34,9 @@ /docs/SDKs/quote-java /docs/SDKs/quote?language=java 301 /docs/SDKs/quote-java/ /docs/SDKs/quote?language=java 301 /docs/SDKs/quote-java.html /docs/SDKs/quote?language=java 301 +/docs/SDKs/quote-ruby /docs/SDKs/quote?language=ruby 301 +/docs/SDKs/quote-ruby/ /docs/SDKs/quote?language=ruby 301 +/docs/SDKs/quote-ruby.html /docs/SDKs/quote?language=ruby 301 /docs/SDKs/webhooks-javascript /docs/SDKs/webhooks?language=js 301 /docs/SDKs/webhooks-javascript/ /docs/SDKs/webhooks?language=js 301 /docs/SDKs/webhooks-javascript.html /docs/SDKs/webhooks?language=js 301 @@ -46,6 +52,9 @@ /docs/SDKs/webhooks-java /docs/SDKs/webhooks?language=java 301 /docs/SDKs/webhooks-java/ /docs/SDKs/webhooks?language=java 301 /docs/SDKs/webhooks-java.html /docs/SDKs/webhooks?language=java 301 +/docs/SDKs/webhooks-ruby /docs/SDKs/webhooks?language=ruby 301 +/docs/SDKs/webhooks-ruby/ /docs/SDKs/webhooks?language=ruby 301 +/docs/SDKs/webhooks-ruby.html /docs/SDKs/webhooks?language=ruby 301 # The TurboSign for Salesforce overview was merged into the Salesforce Integration page (CR #231). # Only the overview moved: the TurboSign for Salesforce guides below it keep their /turbosign-for-salesforce/... URLs, so these are exact matches, not a splat. From 0c3dde48ee87a9d839af3a8f101bcf02d212cb4e Mon Sep 17 00:00:00 2001 From: yacinekahlerras-turbodocx Date: Wed, 21 Oct 2026 12:56:12 +0100 Subject: [PATCH 5/6] docs(sdks): fix Java pin, PHP getenv config, readonly claim, JS .env; add send-without-emails section (#229) * docs(sdks): fix stale Java pin, PHP $_ENV config, readonly claim, JS .env; add send-without-emails section - java.md: 0.7.0 -> 0.8.0 (Maven, Gradle Kotlin, Gradle Groovy). - PHP snippets on php, turbosign, deliverable, webhooks, partner-php, quote and index pages: $_ENV[...] -> getenv(...). $_ENV is empty under the default variables_order = "GPCS". - "readonly classes" is a PHP 8.2 feature; the SDK needs ^8.1 and uses readonly properties. Typed Classes section: Field::$required is ?bool = null (null = required), and Recipient lists phone / externalId / identityVerification. - javascript.md .env adds TURBODOCX_SENDER_EMAIL (required) and TURBODOCX_SENDER_NAME. - turbosign.md: new "Send without emails and sign in your app" section (sendEmail false + createSigningUrl) for JS, Python, PHP, Go and Java, with the Enable identity verification prerequisite. Closes #220 Co-Authored-By: Claude Opus 5.5 * docs(sdks): review fixes - all Java pins 0.8.0, reusable-link wording, getenv ?: null - Bump the remaining 0.7.0 Java pins (turbosign, index, deliverable, quote, webhooks, partner-java). The new Java tab needs 0.8.0 (sendEmail / createSigningUrl). - The signing URL in the new section is the reusable signing link for passcode / no-verification signers; only external_idv / override URLs are single-use. - TurboSign page JS .env adds TURBODOCX_SENDER_EMAIL / TURBODOCX_SENDER_NAME. - getenv(...) ?: null for nullable config args, so an unset variable is null (not false) under declare(strict_types=1). - "readonly properties" on the deliverable and partner-php pages too. - Webhook PHP verification sample: getenv('WEBHOOK_SECRET') instead of $_ENV. Co-Authored-By: Claude Opus 5.5 * docs(sdks): round-2 review fixes - getenv ?: '' for string params, PHP tab import - TurboWebhooks::configureFromCredentials() and PartnerClientConfig take non-nullable strings: `?: null` turned an unset variable into a TypeError. Use `?: ''`, which gives the SDK's clear AuthenticationException (matches fromEnvironment()). Same for the webhook receiver's secret, so an unset secret fails closed (401) instead of a TypeError (500) under strict_types. - The new PHP tab now imports TurboDocx\TurboSign like every other PHP tab. Co-Authored-By: Claude Opus 5.5 (1M context) * docs(sdks): match the 0.9.0 SDKs and add the Ruby tab to send-without-emails (#220) - Java pins 0.8.0 -> 0.9.0 (the published version since 2026-10-20) on every SDK page. - Send without emails: a Ruby tab; say the opt-out also covers the initial CC email, later signers' turn emails and scheduled reminders; recipients is always present on the JS response in 0.9.0, so no non-null assertion. - PHP Typed Classes: Recipient's signingOrder is optional when the recipient has a role, and role is new in 0.9.0. - Go webhook verification: 0.9.0 treats ToleranceSeconds 0 as the 300s default and rejects every delivery on a negative value; -1 no longer disables the timestamp check. Co-Authored-By: Claude Opus 5.5 (1M context) --------- Co-authored-by: Yacine Kahlerras Co-authored-by: Claude Opus 5.5 Co-authored-by: Amit Sharma --- docs/SDKs/deliverable.md | 12 +- docs/SDKs/index.md | 8 +- docs/SDKs/java.md | 6 +- docs/SDKs/javascript.md | 2 + docs/SDKs/partner-java.md | 6 +- docs/SDKs/partner-php.md | 10 +- docs/SDKs/php.md | 10 +- docs/SDKs/quote.md | 10 +- docs/SDKs/turbosign.md | 199 +++++++++++++++++-- docs/SDKs/webhooks.md | 22 +- static/scripts/webhooks/verification/php.php | 2 +- 11 files changed, 232 insertions(+), 55 deletions(-) diff --git a/docs/SDKs/deliverable.md b/docs/SDKs/deliverable.md index d8c2d4dd..e3607d44 100644 --- a/docs/SDKs/deliverable.md +++ b/docs/SDKs/deliverable.md @@ -173,7 +173,7 @@ go get github.com/TurboDocx/SDK/packages/go-sdk com.turbodocx turbodocx-sdk - 0.7.0 + 0.9.0 ``` @@ -181,14 +181,14 @@ go get github.com/TurboDocx/SDK/packages/go-sdk ```kotlin -implementation("com.turbodocx:turbodocx-sdk:0.7.0") +implementation("com.turbodocx:turbodocx-sdk:0.9.0") ``` ```groovy -implementation 'com.turbodocx:turbodocx-sdk:0.7.0' +implementation 'com.turbodocx:turbodocx-sdk:0.9.0' ``` @@ -248,7 +248,7 @@ bundle install - ext-fileinfo :::tip Modern PHP Features -This SDK leverages PHP 8.1+ features including enums, named parameters, readonly classes, and match expressions for a superior developer experience. +This SDK leverages PHP 8.1+ features including enums, named parameters, readonly properties, and match expressions for a superior developer experience. ::: @@ -364,8 +364,8 @@ use TurboDocx\Config\DeliverableConfig; // Configure with all options Deliverable::configure(new DeliverableConfig( - apiKey: $_ENV['TURBODOCX_API_KEY'], // Required: Your TurboDocx API key - orgId: $_ENV['TURBODOCX_ORG_ID'], // Required: Your organization ID + apiKey: getenv('TURBODOCX_API_KEY') ?: null, // Required: Your TurboDocx API key + orgId: getenv('TURBODOCX_ORG_ID') ?: null, // Required: Your organization ID baseUrl: 'https://api.turbodocx.com' // Optional: Custom API endpoint )); ``` diff --git a/docs/SDKs/index.md b/docs/SDKs/index.md index acd99a7a..70565a27 100644 --- a/docs/SDKs/index.md +++ b/docs/SDKs/index.md @@ -204,7 +204,7 @@ go get github.com/TurboDocx/SDK/packages/go-sdk com.turbodocx turbodocx-sdk - 0.7.0 + 0.9.0 ``` @@ -343,9 +343,9 @@ use TurboDocx\Types\Requests\SendSignatureRequest; // Configure with your API key TurboSign::configure(new HttpClientConfig( - apiKey: $_ENV['TURBODOCX_API_KEY'], - orgId: $_ENV['TURBODOCX_ORG_ID'], - senderEmail: $_ENV['TURBODOCX_SENDER_EMAIL'] + apiKey: getenv('TURBODOCX_API_KEY') ?: null, + orgId: getenv('TURBODOCX_ORG_ID') ?: null, + senderEmail: getenv('TURBODOCX_SENDER_EMAIL') ?: null )); // Send a document for signature diff --git a/docs/SDKs/java.md b/docs/SDKs/java.md index f2794937..7827f850 100644 --- a/docs/SDKs/java.md +++ b/docs/SDKs/java.md @@ -32,7 +32,7 @@ The official TurboDocx SDK for Java applications. Build document generation and com.turbodocx turbodocx-sdk - 0.7.0 + 0.9.0 ``` @@ -40,14 +40,14 @@ The official TurboDocx SDK for Java applications. Build document generation and ```kotlin -implementation("com.turbodocx:turbodocx-sdk:0.7.0") +implementation("com.turbodocx:turbodocx-sdk:0.9.0") ``` ```groovy -implementation 'com.turbodocx:turbodocx-sdk:0.7.0' +implementation 'com.turbodocx:turbodocx-sdk:0.9.0' ``` diff --git a/docs/SDKs/javascript.md b/docs/SDKs/javascript.md index c167c480..d65dba24 100644 --- a/docs/SDKs/javascript.md +++ b/docs/SDKs/javascript.md @@ -106,6 +106,8 @@ Authenticate using `apiKey`. API keys are recommended for server-side applicatio # .env TURBODOCX_API_KEY=your_api_key_here TURBODOCX_ORG_ID=your_org_id_here +TURBODOCX_SENDER_EMAIL=you@company.com # Required for TurboSign +TURBODOCX_SENDER_NAME=Your Company Name # Optional (strongly recommended) ``` --- diff --git a/docs/SDKs/partner-java.md b/docs/SDKs/partner-java.md index 35319961..1173a535 100644 --- a/docs/SDKs/partner-java.md +++ b/docs/SDKs/partner-java.md @@ -82,7 +82,7 @@ public class Main { com.turbodocx turbodocx-sdk - 0.7.0 + 0.9.0 ``` @@ -90,14 +90,14 @@ public class Main { ```kotlin -implementation("com.turbodocx:turbodocx-sdk:0.7.0") +implementation("com.turbodocx:turbodocx-sdk:0.9.0") ``` ```groovy -implementation 'com.turbodocx:turbodocx-sdk:0.7.0' +implementation 'com.turbodocx:turbodocx-sdk:0.9.0' ``` diff --git a/docs/SDKs/partner-php.md b/docs/SDKs/partner-php.md index 1c84249c..98c651e6 100644 --- a/docs/SDKs/partner-php.md +++ b/docs/SDKs/partner-php.md @@ -51,8 +51,8 @@ use TurboDocx\Types\Enums\OrgUserRole; // 1. Configure TurboPartner::configure(new PartnerClientConfig( - partnerApiKey: $_ENV['TURBODOCX_PARTNER_API_KEY'], - partnerId: $_ENV['TURBODOCX_PARTNER_ID'], + partnerApiKey: getenv('TURBODOCX_PARTNER_API_KEY') ?: '', + partnerId: getenv('TURBODOCX_PARTNER_ID') ?: '', )); // 2. Create an organization with entitlements @@ -96,7 +96,7 @@ composer require turbodocx/sdk - ext-curl :::tip Modern PHP Features -This SDK leverages PHP 8.1+ features including enums, named parameters, readonly classes, and match expressions for a superior developer experience. +This SDK leverages PHP 8.1+ features including enums, named parameters, readonly properties, and match expressions for a superior developer experience. ::: --- @@ -114,8 +114,8 @@ use TurboDocx\Config\PartnerClientConfig; // Configure with your partner credentials TurboPartner::configure(new PartnerClientConfig( - partnerApiKey: $_ENV['TURBODOCX_PARTNER_API_KEY'], // Required: Must start with TDXP- - partnerId: $_ENV['TURBODOCX_PARTNER_ID'], // Required: Your partner UUID + partnerApiKey: getenv('TURBODOCX_PARTNER_API_KEY') ?: '', // Required: Must start with TDXP- + partnerId: getenv('TURBODOCX_PARTNER_ID') ?: '', // Required: Your partner UUID )); ``` diff --git a/docs/SDKs/php.md b/docs/SDKs/php.md index 50635d75..fa098149 100644 --- a/docs/SDKs/php.md +++ b/docs/SDKs/php.md @@ -39,7 +39,7 @@ composer require turbodocx/sdk - ext-fileinfo :::tip Modern PHP Features -This SDK leverages PHP 8.1+ features including enums, named parameters, readonly classes, and match expressions for a superior developer experience. +This SDK leverages PHP 8.1+ features including enums, named parameters, readonly properties, and match expressions for a superior developer experience. ::: --- @@ -57,10 +57,10 @@ use TurboDocx\Config\HttpClientConfig; // Configure with all options TurboSign::configure(new HttpClientConfig( - apiKey: $_ENV['TURBODOCX_API_KEY'], // Required: Your TurboDocx API key - orgId: $_ENV['TURBODOCX_ORG_ID'], // Required: Your organization ID - senderEmail: $_ENV['TURBODOCX_SENDER_EMAIL'], // Required: Reply-to email for signature requests - senderName: $_ENV['TURBODOCX_SENDER_NAME'], // Optional: Sender name (strongly recommended) + apiKey: getenv('TURBODOCX_API_KEY') ?: null, // Required: Your TurboDocx API key + orgId: getenv('TURBODOCX_ORG_ID') ?: null, // Required: Your organization ID + senderEmail: getenv('TURBODOCX_SENDER_EMAIL') ?: null, // Required: Reply-to email for signature requests + senderName: getenv('TURBODOCX_SENDER_NAME') ?: null, // Optional: Sender name (strongly recommended) baseUrl: 'https://api.turbodocx.com' // Optional: Custom API endpoint )); ``` diff --git a/docs/SDKs/quote.md b/docs/SDKs/quote.md index 7dc5713b..90321558 100644 --- a/docs/SDKs/quote.md +++ b/docs/SDKs/quote.md @@ -234,7 +234,7 @@ import turbodocx "github.com/TurboDocx/SDK/packages/go-sdk" com.turbodocx turbodocx-sdk - 0.7.0 + 0.9.0 ``` @@ -242,14 +242,14 @@ import turbodocx "github.com/TurboDocx/SDK/packages/go-sdk" ```groovy -implementation 'com.turbodocx:turbodocx-sdk:0.7.0' +implementation 'com.turbodocx:turbodocx-sdk:0.9.0' ``` ```kotlin -implementation("com.turbodocx:turbodocx-sdk:0.7.0") +implementation("com.turbodocx:turbodocx-sdk:0.9.0") ``` @@ -414,8 +414,8 @@ use TurboDocx\TurboQuote; use TurboDocx\Config\QuoteClientConfig; TurboQuote::configure(new QuoteClientConfig( - apiKey: $_ENV['TURBODOCX_API_KEY'], - orgId: $_ENV['TURBODOCX_ORG_ID'], // optional, but required for most endpoints + apiKey: getenv('TURBODOCX_API_KEY') ?: null, + orgId: getenv('TURBODOCX_ORG_ID') ?: null, // optional, but required for most endpoints )); ``` diff --git a/docs/SDKs/turbosign.md b/docs/SDKs/turbosign.md index 57bec31a..e6213914 100644 --- a/docs/SDKs/turbosign.md +++ b/docs/SDKs/turbosign.md @@ -179,7 +179,7 @@ go get github.com/TurboDocx/SDK/packages/go-sdk com.turbodocx turbodocx-sdk - 0.7.0 + 0.9.0 ``` @@ -187,14 +187,14 @@ go get github.com/TurboDocx/SDK/packages/go-sdk ```kotlin -implementation("com.turbodocx:turbodocx-sdk:0.7.0") +implementation("com.turbodocx:turbodocx-sdk:0.9.0") ``` ```groovy -implementation 'com.turbodocx:turbodocx-sdk:0.7.0' +implementation 'com.turbodocx:turbodocx-sdk:0.9.0' ``` @@ -254,7 +254,7 @@ bundle install - ext-fileinfo :::tip Modern PHP Features -This SDK leverages PHP 8.1+ features including enums, named parameters, readonly classes, and match expressions for a superior developer experience. +This SDK leverages PHP 8.1+ features including enums, named parameters, readonly properties, and match expressions for a superior developer experience. ::: @@ -361,10 +361,10 @@ use TurboDocx\Config\HttpClientConfig; // Configure with all options TurboSign::configure(new HttpClientConfig( - apiKey: $_ENV['TURBODOCX_API_KEY'], // Required: Your TurboDocx API key - orgId: $_ENV['TURBODOCX_ORG_ID'], // Required: Your organization ID - senderEmail: $_ENV['TURBODOCX_SENDER_EMAIL'], // Required: Reply-to email for signature requests - senderName: $_ENV['TURBODOCX_SENDER_NAME'], // Optional: Sender name (strongly recommended) + apiKey: getenv('TURBODOCX_API_KEY') ?: null, // Required: Your TurboDocx API key + orgId: getenv('TURBODOCX_ORG_ID') ?: null, // Required: Your organization ID + senderEmail: getenv('TURBODOCX_SENDER_EMAIL') ?: null, // Required: Reply-to email for signature requests + senderName: getenv('TURBODOCX_SENDER_NAME') ?: null, // Optional: Sender name (strongly recommended) baseUrl: 'https://api.turbodocx.com' // Optional: Custom API endpoint )); ``` @@ -547,6 +547,8 @@ Creating a client per request leaks OkHttp threads until they are closed. Prefer # .env TURBODOCX_API_KEY=your_api_key_here TURBODOCX_ORG_ID=your_org_id_here +TURBODOCX_SENDER_EMAIL=you@company.com # Required for TurboSign +TURBODOCX_SENDER_NAME=Your Company Name # Optional (strongly recommended) ``` @@ -2965,6 +2967,175 @@ puts result["documentId"] +### Send without emails and sign in your app {#send-without-emails} + +Set `sendEmail` to `false` to create the signature request without emailing the signers their links. The document still goes out for signing, and passcode and completed-copy emails are still sent. The opt-out also covers the initial CC email, later signers' turn emails and scheduled reminders. Then call `createSigningUrl` for a signer when they are ready to sign in your app. For a signer with an email/SMS passcode or no verification (as here), the URL is their reusable signing link for the life of the document, so treat it like a password and don't log it. `external_idv` and `override` signers get a single-use URL that expires in about five minutes; mint those at the moment of signing. + +:::info Prerequisite +Embedded signing must be turned on for your organization: in the E-Signature settings, turn on **Enable identity verification** (see [Set up your organization](/docs/TurboSign/how-to-enable-embedded-signing)). While it is off, `createSigningUrl` fails with `EmbeddedSigningNotEnabled`. +::: + + + + +```typescript +const result = await TurboSign.sendSignature({ + fileLink: "https://www.turbodocx.com/examples/turbodocx.pdf", + documentName: "Service Agreement", + recipients: [{ name: "Recipient Name", email: "recipient@example.com", signingOrder: 1 }], + fields: [{ type: "signature", page: 1, x: 100, y: 500, width: 200, height: 50, recipientEmail: "recipient@example.com" }], + sendEmail: false, // no signing-link emails; you hand out the link +}); + +// When the signer is ready, mint their signing URL +const link = await TurboSign.createSigningUrl(result.documentId, { + recipientId: result.recipients[0].id, +}); +console.log(link.url); // open in a new tab or redirect to it +``` + + + + +```python +result = await TurboSign.send_signature( + recipients=[{"name": "Recipient Name", "email": "recipient@example.com", "signingOrder": 1}], + fields=[{"type": "signature", "page": 1, "x": 100, "y": 500, "width": 200, "height": 50, "recipientEmail": "recipient@example.com"}], + file_link="https://www.turbodocx.com/examples/turbodocx.pdf", + document_name="Service Agreement", + send_email=False, # no signing-link emails; you hand out the link +) + +# When the signer is ready, mint their signing URL +link = await TurboSign.create_signing_url( + result["documentId"], + recipient_id=result["recipients"][0]["id"], +) +print(link["url"]) # open in a new tab or redirect to it +``` + + + + +```php +use TurboDocx\TurboSign; +use TurboDocx\Types\Recipient; +use TurboDocx\Types\Field; +use TurboDocx\Types\SignatureFieldType; +use TurboDocx\Types\Requests\SendSignatureRequest; +use TurboDocx\Types\Requests\CreateSigningUrlRequest; + +$result = TurboSign::sendSignature( + new SendSignatureRequest( + recipients: [new Recipient('Recipient Name', 'recipient@example.com', 1)], + fields: [ + new Field( + type: SignatureFieldType::SIGNATURE, + recipientEmail: 'recipient@example.com', + page: 1, + x: 100, + y: 500, + width: 200, + height: 50 + ) + ], + fileLink: 'https://www.turbodocx.com/examples/turbodocx.pdf', + documentName: 'Service Agreement', + sendEmail: false // no signing-link emails; you hand out the link + ) +); + +// When the signer is ready, mint their signing URL +$link = TurboSign::createSigningUrl( + $result->documentId, + new CreateSigningUrlRequest(recipientId: $result->recipients[0]['id']) +); +echo $link->url; // open in a new tab or redirect to it +``` + + + + +```go +sendEmail := false // no signing-link emails; you hand out the link +result, err := client.TurboSign.SendSignature(ctx, &turbodocx.SendSignatureRequest{ + FileLink: "https://www.turbodocx.com/examples/turbodocx.pdf", + DocumentName: "Service Agreement", + Recipients: []turbodocx.Recipient{ + {Name: "Recipient Name", Email: "recipient@example.com", SigningOrder: 1}, + }, + Fields: []turbodocx.Field{ + {Type: "signature", Page: 1, X: 100, Y: 500, Width: 200, Height: 50, RecipientEmail: "recipient@example.com"}, + }, + SendEmail: &sendEmail, +}) +if err != nil { + log.Fatal(err) +} + +// When the signer is ready, mint their signing URL +link, err := client.TurboSign.CreateSigningURL(ctx, result.DocumentID, &turbodocx.CreateSigningURLRequest{ + RecipientID: result.Recipients[0].ID, +}) +if err != nil { + log.Fatal(err) +} +fmt.Println(link.URL) // open in a new tab or redirect to it +``` + + + + +```java +SendSignatureResponse result = client.turboSign().sendSignature( + new SendSignatureRequest.Builder() + .fileLink("https://www.turbodocx.com/examples/turbodocx.pdf") + .documentName("Service Agreement") + .recipients(Arrays.asList( + new Recipient("Recipient Name", "recipient@example.com", 1) + )) + .fields(Arrays.asList( + new Field("signature", 1, 100, 500, 200, 50, "recipient@example.com") + )) + .sendEmail(false) // no signing-link emails; you hand out the link + .build() +); + +// When the signer is ready, mint their signing URL +CreateSigningUrlResponse link = client.turboSign().createSigningUrl( + result.getDocumentId(), + new CreateSigningUrlRequest.Builder() + .recipientId(result.getRecipients().get(0).getId()) + .build() +); +System.out.println(link.getUrl()); // open in a new tab or redirect to it +``` + + + + +```ruby +result = TurboDocxSdk::TurboSign.send_signature( + fileLink: "https://www.turbodocx.com/examples/turbodocx.pdf", + documentName: "Service Agreement", + recipients: [{ name: "Recipient Name", email: "recipient@example.com", signingOrder: 1 }], + fields: [{ type: "signature", page: 1, x: 100, y: 500, width: 200, height: 50, recipientEmail: "recipient@example.com" }], + sendEmail: false # no signing-link emails; you hand out the link +) + +# When the signer is ready, mint their signing URL +link = TurboDocxSdk::TurboSign.create_signing_url( + result["documentId"], + recipient_id: result["recipients"][0]["id"] +) +puts link["url"] # open in a new tab or redirect to it +``` + + + + +To frame the signing page inside your app instead of opening it, and for identity verification options, see [Embedded Signing](/docs/TurboSign/embedded-signing). + ### Reminders and expiration {#reminders-and-expiration} @@ -4995,19 +5166,23 @@ enum ConditionalAction: string { -### Readonly Classes {#readonly-classes} +### Typed Classes {#readonly-classes} -The SDK uses readonly classes with typed properties: +The SDK uses final classes with typed, constructor-promoted properties: ```php final class Recipient { public function __construct( public string $name, public string $email, - public int $signingOrder + public ?int $signingOrder = null, // Required unless the recipient has a role + public ?string $phone = null, // E.164; required for SMS passcodes + public ?string $externalId = null, // Your own key, unique in the document + public ?IdentityVerification $identityVerification = null, + public ?string $role = null // Template signer role this recipient fills ) {} } @@ -5024,7 +5199,7 @@ final class Field { public ?string $defaultValue = null, // checkbox: 'true'/'false'; date: a fixed MM/DD/YYYY (omit to auto-fill the signing date) public bool $isMultiline = false, public bool $isReadonly = false, - public bool $required = false, + public ?bool $required = null, // null (default) = required; false = optional for the signer public ?string $backgroundColor = null, public ?FieldMetadata $metadata = null // Conditional (IF/THEN) metadata ) {} diff --git a/docs/SDKs/webhooks.md b/docs/SDKs/webhooks.md index 30bbbaeb..d9c100ee 100644 --- a/docs/SDKs/webhooks.md +++ b/docs/SDKs/webhooks.md @@ -213,7 +213,7 @@ import turbodocx "github.com/TurboDocx/SDK/packages/go-sdk" com.turbodocx turbodocx-sdk - 0.7.0 + 0.9.0 ``` @@ -221,14 +221,14 @@ import turbodocx "github.com/TurboDocx/SDK/packages/go-sdk" ```groovy -implementation 'com.turbodocx:turbodocx-sdk:0.7.0' +implementation 'com.turbodocx:turbodocx-sdk:0.9.0' ``` ```kotlin -implementation("com.turbodocx:turbodocx-sdk:0.7.0") +implementation("com.turbodocx:turbodocx-sdk:0.9.0") ``` @@ -348,8 +348,8 @@ TurboWebhooks.configure( use TurboDocx\TurboWebhooks; TurboWebhooks::configureFromCredentials( - apiKey: $_ENV['TURBODOCX_API_KEY'], - orgId: $_ENV['TURBODOCX_ORG_ID'], + apiKey: getenv('TURBODOCX_API_KEY') ?: '', // string params: '' makes an unset variable a clear auth error + orgId: getenv('TURBODOCX_ORG_ID') ?: '', ); ``` @@ -369,8 +369,8 @@ If you need to build the config yourself, pass `skipSenderValidation: true` — use TurboDocx\Config\HttpClientConfig; TurboWebhooks::configure(new HttpClientConfig( - apiKey: $_ENV['TURBODOCX_API_KEY'], - orgId: $_ENV['TURBODOCX_ORG_ID'], + apiKey: getenv('TURBODOCX_API_KEY') ?: null, + orgId: getenv('TURBODOCX_ORG_ID') ?: null, skipSenderValidation: true, // webhooks don't send email )); ``` @@ -1189,8 +1189,8 @@ use TurboDocx\Exceptions\ValidationException; use TurboDocx\Types\Enums\WebhookEvent; TurboWebhooks::configureFromCredentials( - apiKey: $_ENV['TURBODOCX_API_KEY'], - orgId: $_ENV['TURBODOCX_ORG_ID'], + apiKey: getenv('TURBODOCX_API_KEY') ?: '', // string params: '' makes an unset variable a clear auth error + orgId: getenv('TURBODOCX_ORG_ID') ?: '', ); try { @@ -1531,7 +1531,7 @@ use function TurboDocx\Utils\verifyWebhookSignature; $rawBody = file_get_contents('php://input'); // raw bytes — do NOT json_decode first $signatureHeader = $_SERVER['HTTP_X_TURBODOCX_SIGNATURE'] ?? ''; $timestampHeader = $_SERVER['HTTP_X_TURBODOCX_TIMESTAMP'] ?? ''; -$secret = $_ENV['TURBODOCX_WEBHOOK_SECRET']; +$secret = getenv('TURBODOCX_WEBHOOK_SECRET') ?: ''; if (!verifyWebhookSignature($rawBody, $signatureHeader, $timestampHeader, $secret)) { http_response_code(401); @@ -2952,7 +2952,7 @@ ok := turbodocx.VerifyWebhookSignature( ) ``` -Pass `&turbodocx.VerifyWebhookSignatureOptions{ToleranceSeconds: 60}` to tighten the window, or `ToleranceSeconds: -1` to disable the timestamp check entirely (NOT recommended in production). +Pass `&turbodocx.VerifyWebhookSignatureOptions{ToleranceSeconds: 60}` to tighten the window, or a larger positive value to widen it. `0` (the zero value) means the 300-second default, so the Go helper has no way to turn the timestamp check off, and a negative value rejects every delivery. diff --git a/static/scripts/webhooks/verification/php.php b/static/scripts/webhooks/verification/php.php index d7118fb0..d330f978 100644 --- a/static/scripts/webhooks/verification/php.php +++ b/static/scripts/webhooks/verification/php.php @@ -185,7 +185,7 @@ function testWebhookVerification(string $secret = 'test-secret'): bool // Example usage when script is run directly if (__FILE__ === $_SERVER['SCRIPT_FILENAME']) { - $webhookSecret = $_ENV['WEBHOOK_SECRET'] ?? 'your-webhook-secret'; + $webhookSecret = getenv('WEBHOOK_SECRET') ?: 'your-webhook-secret'; // If running from command line, run test if (php_sapi_name() === 'cli') { From 37310401b246e7a6f7ddd9f4134cfa94e7c4d2c8 Mon Sep 17 00:00:00 2001 From: Nicolas Date: Fri, 23 Oct 2026 08:03:24 -0400 Subject: [PATCH 6/6] docs(wrike): document reminder status, void on re-send and void status (#251) * docs(wrike): document reminder status, void on re-send and void status for e-signature automations Adds a Reminders, Re-sends and Voiding section to the Wrike e-signature automation guide with annotated screenshots, and notes the domain rule behind bulk 'Invalid Email' failures. * docs(wrike): recapture screenshots with generic workflow names --------- Co-authored-by: Nicolas Fry --- .../Wrike/signature-automation.md | 52 +++++++++++++++++- docs/TurboSign/API-Bulk-Signatures.md | 1 + .../SigAuto-ReviewVoidRules.png | Bin 0 -> 168887 bytes .../SigAuto-SendReminder.png | Bin 0 -> 62521 bytes .../wrike-integration/SigAuto-VoidOnSend.png | Bin 0 -> 67715 bytes .../wrike-integration/SigAuto-VoidStatus.png | Bin 0 -> 68698 bytes 6 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 static/img/wrike-integration/SigAuto-ReviewVoidRules.png create mode 100644 static/img/wrike-integration/SigAuto-SendReminder.png create mode 100644 static/img/wrike-integration/SigAuto-VoidOnSend.png create mode 100644 static/img/wrike-integration/SigAuto-VoidStatus.png diff --git a/docs/Integrations/Wrike/signature-automation.md b/docs/Integrations/Wrike/signature-automation.md index 5cb902f6..e8913960 100644 --- a/docs/Integrations/Wrike/signature-automation.md +++ b/docs/Integrations/Wrike/signature-automation.md @@ -8,6 +8,8 @@ keywords: - wrike automated signing - wrike signature workflow - wrike document signing + - wrike void signature request + - wrike signature reminder --- # How to Setup E-Signature Automation @@ -67,7 +69,7 @@ In the field editor, **Send** stays disabled until *each* recipient has at least ## Configure Signers :::note -The steps below apply to **all three** delivery modes. If you chose **Place signature fields manually**, complete this section and then skip ahead to [Post-Signature Settings](#post-signature-settings) — the **Map Document Fields** steps won't appear. +The steps below apply to **all three** delivery modes. If you chose **Place signature fields manually**, complete this section and then skip ahead to [Reminders, Re-sends and Voiding](#reminders-re-sends-and-voiding-optional). The **Map Document Fields** steps won't appear. ::: ### Step 3: Select the First Recipient's Email Field @@ -134,6 +136,54 @@ Optionally, repeat the process to map more document fields for the signer.
+## Reminders, Re-sends and Voiding (Optional) + +Signature requests don't always go out right the first time. A signer misses the email, or someone spots a typo after the request was sent. The three settings below let your team handle that from Wrike by moving the task to a status, without opening TurboDocx. + +All three are optional and sit below **Map Document Fields** in the signature step. Pick statuses your team doesn't already use to send for signature. + +### Send a reminder + +In **Send a reminder when the task moves to**, pick the Wrike status your team uses to nudge signers. + +![The Send a reminder status picker highlighted, set to Please Sign](/img/wrike-integration/SigAuto-SendReminder.png) + +When a task moves to that status, TurboDocx emails a reminder, with the same signing link, to every signer who hasn't signed yet. It doesn't create a new request, and requests that were voided are skipped. A comment on the task confirms how many signers were reminded. + +### Void earlier requests when the task is sent again + +Under **When the task is sent again**, check **Void outstanding requests when sending a new one** if a task should only ever have one open request. + +![The "Void outstanding requests when sending a new one" option checked, with its warning and the Triggered by line](/img/wrike-integration/SigAuto-VoidOnSend.png) + +With this on, each time the task moves to a send status and the new request goes out, TurboDocx voids every earlier request this automation sent from that task that isn't fully signed. The warning lists the statuses that trigger it on the **Triggered by** line. + +:::caution Voiding can't be undone +Requests some signers have already signed are voided too, and their signers are emailed that the request was withdrawn. Fully signed requests are never touched. Leave the option off if earlier requests should stay open when the task is sent again. +::: + +If the automation uses **Send for review first** or **Place signature fields manually**, earlier requests stay open until the new draft is sent. They're voided when someone sends it. + +### Set a void status + +In **Void status**, pick the Wrike status that withdraws a task's open requests, for example **Rejected** or **Needs Changes**. + +![The Void status picker highlighted, set to Rejected](/img/wrike-integration/SigAuto-VoidStatus.png) + +When a task moves to that status, TurboDocx voids the open signature requests this automation sent from the task. Signers who were sent a request are emailed that it was withdrawn, and one comment on the task says how many requests were voided. To send a corrected request, fix the task and move it back to the send status. + +:::note Statuses can't overlap +The void status can't be one of the automation's trigger statuses, the reminder status, the completed status, or a status used in [Wrike Activity Updates](#wrike-activity-updates-optional). The wizard won't let you save an overlap, because one status move would then both send and void. +::: + +On the last step of the wizard, **Trigger conditions** lists all three, so you can check them before you create the automation. + +![The Trigger conditions summary highlighted, showing the Sends when, Reminds when and Voids when lines](/img/wrike-integration/SigAuto-ReviewVoidRules.png) + +Each run shows up in the automation's **View Logs** with a summary such as "Voided the signature request" or "Sent a reminder to 1 signer who hasn't signed." + +
+ ## Post-Signature Settings ### Step 11: Choose Where the Signed Document Gets Attached diff --git a/docs/TurboSign/API-Bulk-Signatures.md b/docs/TurboSign/API-Bulk-Signatures.md index 7551dbba..df74f4e9 100644 --- a/docs/TurboSign/API-Bulk-Signatures.md +++ b/docs/TurboSign/API-Bulk-Signatures.md @@ -702,6 +702,7 @@ If you exceed rate limits, you'll receive a `429 Too Many Requests` response. Im **Solutions:** - Verify email format +- Check the domain: it must end in at least two letters and have no empty parts, so `name@acme.c`, `name@acme.com.` and `name@acme..com` are rejected - Check for typos - Ensure no special characters in local part diff --git a/static/img/wrike-integration/SigAuto-ReviewVoidRules.png b/static/img/wrike-integration/SigAuto-ReviewVoidRules.png new file mode 100644 index 0000000000000000000000000000000000000000..9a36e5e7b629dc0e213c5e4ba463da832000c2a5 GIT binary patch literal 168887 zcmZ_0bzD?k7dFhT5`vUL4XU{o1)>?b*>$>)Ys3<{jvB|K}(9m#YWhB+m(C&RhL%U0fbq6@( zw{IDY_757GtfZK_`{ZVW$NP8fal$^u+GzZ-&doQI{r5NQ3ycHN-x$@EL=mq4}t952hH z_$cCiojSUrz&DqxqODKv{d!#*jnaBfze{c3vHUtWVo*k?*-=vEA`amF<6ypD0`w&9~GwsLzB;F$`@nxt)3)aRv z*TrZbdS^KnRb);b&FFzYT55%6rR6B1!RtBu_Dr4IXwmD{R41jw41KJRF+H6zn1MK` z!rz2{9;5Nqlv~5OrpD(9?l25KjQHnI6SQ&AR8(|yY%TeES%gw7M>v6DE6{fA|8>B7HOnnAvZOuN~s^Pm9kPqZftWY3L$1 z-n+SbdtL@+W?p$;EJ-@^hg#5+7S++-ELul&kt;$0#!p(TgBx{Aa0HVOcpqnKmx-SOKhnUuc`?|Zm&<* z_*EdNQ(xX*R-300aKj`0b7$Iia^niBfJa!UOE1aNBm~Ft)Ng+yG7;h*}u#%@N%B;AO}07`w8X3J1ggi%LOV-IQ$zLx<+!xgonQ z(E<{)ojFm5fAY85?|)v>J8fO{&We27|e|xp{ecMVqLZnR};M z1C+52)9vq1Jj^un1X_#iifY~3+Tvmh6|8P^O))G69_NF)@#@ z?s0K*-~ISuc87uCU1~dh>$97cbB6`G<26I=6`JFuQ1kK)l>!J}^Gt_dsy&t=d#S`? zl|mTn)`~NIqW2K!W@QpuU-oo+Q^vII-5@puOwa9UI`Fz^t81o&Z{BsuR_e$WVzDwS zR9f2Y;yhDhv%Oi6&tE$;GXvO4@$HeF?a$dk!pyp*p{a?LLGVEW3r+R_BZ5-c@erv> z)6><($Xbb2U*o$;*E`d)LS2JrX*W%gWBBIBl#&O&w)?DcD^wpM+yi~bS5P|7I26UN|5s7TjimqfO%T4R};d4S({W+Pint)pnfkZ=H(I5lgYAxitviVc_84 z;Np0TT*t%9h<3_i8<*ruj`ff7Zlz}_*k(roe8p?!pb5fFEZ3zLDBmh8D=P>DlKfq! z=PR2|0C;B*!3SRRbzD~$m*>y7H0qnx`5sPCS zNL((tKld8$BzRw(0mbVzww&PFQu*W-7gz4Ypw1~M7R`I<*wb#}rH?rQH zdrC@5x_ciLROWt>FQx9xHkB0@Gjnsp>g%T?$t4kUvPry1bMCY@8yb&A9<|kge8Uu^ zu(dGKG(76$QrpdSY39D083duMos+~F2;xt^pL*bZar~)u zz7cra(zZrCe=nXHBoH7HP8_M5cx&quMHXzYjAa>`m3n9Llab5LDX}MN_~6SHMVaO_*SnsrRpebNJQn# z%WQ2H+!w%8uXpyvRlqPm7L?@Otv(esuOQ3?N zDs5r$jIgr0I;hpaNrQ-zdgztgDliqqiU(3Ir9R4T4Z^Gb&O`k8@dFZ$%mglRDBpL= zUM!DraFUjR zpd8y~*K@G5_-2>2ZZp){468;Uj@nL;Ap@lPHgObT1<4X!>teWv#uxCj`~K7;YBIaX z-$%{$knNF2-AcCU((EPy(OEGoP(nvuxqN-vDWk@irC`;HgS2T*aoO$~MN#n5B=lD+ zR_+M&U0-Ohn}J^Qm){b;C6 zCS?9)pTM)IcAiedui!AQC~Iw{)=0wWdH%22_1lK!+gbbj<(jY`B}}-_V-> z4SiQ4l%ENL3(ONKTZVikltIN^`~4Pl;R3$TUF1R`2N=Q~h9mEuaE}t6r@zrTR)=N3 z`dV88L@hZJ7kJK8)X4}@>@ib6tq86ml@`QO(hI78Z}X*?%PvW=4+8EXCgA| z>cxmX$f_K)J^N!D5)Bj$>tw#`e`VWyin?UwG{LkZF%&$7A&EVd}#QOR4p3-yQ!51{9 zluw;NUmytTqpo@}MRk!}5C4VWT-FYShwt^7_S2%HpRNechD7&2l!vDG1*=Byr{Pcy}IEe^gqL3tRG!w(P9Us zIYAZ9G&Vj_4>p#ti_GMm@Y=*e^~q*~r@txKba8+arXltaRkv3d$p=}n z!9sQ5L+4+ae?A=xHHfudJhwmkP5YGZCCX;7PrbVD?ql3X-7VI%Hj~%<_$ZTCW{6zj zBS_3HQpu)4O#AL$MVw#fZFiGRB*Y9~j;eaA{*6$#5BS@7g)q>XU1}e<%-2+bz+YTw zz-olR-)enXxv`NE70v#Z9jb-=?XSWSavpNwR>$n!lMlMzo+)p0iq5GAda|vNh#y%N zl(E+ub-L1!aT*3_8LNt{SQ5&{9lrrd5`4vX&+#jc3U7Zqo$x?o@o?O&XYj|OWwfr& zSbGUay+hJ)OgJY4FO%JAJf->Z01kksfhS1CRXvq60CnF%C z$oOUwdfVB5O#uri57^I$Ib>Y_EG;HP;&p{5zPpK?mz^!nBBLN z2|`r2y6>;yPI{ZgU341GlGcg-8CCannZ!l>|5#-vSdivFMk++;>Cg2MKWJ6_kq9kb z?5)`lk2w?VV=PYrR&ako+-{c^1{f+Z2ffmV+}gK5H5d(*L()gFXLBTCwNe0HdOJn^ z{|um}z<^mNNo(Trrw3{olTUU?C!OT_+$@?#TT9k}P6;;9g~61#$H z=@~Ws5h?U?^B+_KsDFQB;>(C8;52kKWJuh%eb}h#szeumL}Z5j9YNhvUUQvX(%V7# zZnnC>ZMcd1zcK3Dt#5ODc9oRvX*-@H6)#3b(?e5DQ&oBP0EHJZLtg){AzVk|$`QF9 zSA4w#zx6XVjzUpp)rRlwhEcqU)0!-Ye>_y73UJCl(a-==rQ{yEDU;vbH)H!54b^9A zUO|2PlK1`{MlXr~a~SDIp$Zf)DX`H|V?%qG{3vi(#NkU2%AEcizfiW@91B;iIK;qp z!g{U^;$|mY6~FBz3dpUgDmzF6@dq$!ICN-2;6DsvW8dd@4WqOBUblRSzSwD;tEUlNt+&}AzBw@MEzoAG zGc&eb5F3S`4$LO7Gm%}v%04shb(W2JyU#Npn2wn!)?GzU1ul26A-v58m~r%GVqE$` zBerA@sj+v`L|2CgBU}R)^=O#gdK6z#ktCFP-gDjdI{CB=dmBb|x`Mv?#Ed|7qiVUy zqk;2c`oPEYwFlAaZ+L|{V$yAOoZYTB?Y+;a;z*}5OLw>~yJpkz9Y`(*Q z{{`=*hpEl@r&p9U1$G}=aB)^TJO_K2o~=2pwCz==kFe{D$TeS)Q)Xz%6DwUeOSOMI z-H;;|NPZ%f$%;avR6+1zkIZ<8J8zD`IFXtAnwaPQ-)p^|zMmU0jx|~vH zcfvV+>i1@R+d7&iIzxgdPa1bGL-{dV_L5$vK3YDy>fmLsvHs8m^Xa!U+s1w;u$)i) zxYPFQ!BC5b6(X(4t-XA@dsSn`eR(1zS8I6Cb?mGAVO*eJH?a^`uHJ`W@gNZ&i(wYB z^BBR7IJ1{_Lspx!_A$7qNvakGz72jrz=^F;u!aSbqaD6K<+%4U!mo=R9=P3BZ86!= z+$8hkOR33OMRF&iOqj?(^0APkar;WEV1!hxCcROK&BaPm*xQu>c>T9$sXt_Br&Y!) z3^y8+GIlKS9vStm9-wbnUGwLgw6A~#BOql2wu0`?XUA26N)^Fvu+(cayj)g2+l#3M ze=!>D%06$mgG~W4{yf^3l3(KCg9FzCVRcoH4>Ml0G%YMvo?Lk%vRb1i%=|mYY%JiO z12C6Dkw8x%SCn69-pz1{m=yITM|*Pwu(oZfh!cQIT@ zi0EzBJqPKOFAiBz*}^A@F35hrx!K-qV0NXLbo?eyk!w_$qNn*D39Hd2dj4rtFR>Qt zRx%5(+E%G%x-;crZPov!Rzjy4DOHQ_eYv?Aq&wMAnW^WDwsX^eDHUXxux@FiQ++mM z#m<`6P#qSmnX{p<(;GTz)NH>wPHg7KWf)z4fGin$Cl+FcK znIAwxQjxf1Kp8CqDXMOG)Dfo1_IMhIKkbPU_mgFaLI;#0t;L?xFdEjf3t-5B1bi-_ zTH0@)x}oj#3-9+%etTE!C&79sNv9wWC_503Y_$)hj6j4gReicM&Wau$)MQ%WzEuV$ zTl*V9davS}>!!xprfb+(bU!kR$7&t^lo+3RL92gyL}HYB5tu4EUp2TYa#42F%g!VW z+v`oTYRxW9u~*chU%k|viBDp#lUB?)pWb?Xc5Q!9RO2S1D(a*)(za&u(LFpSCUR7) zoM|kab0CB(Y}*$(Ifa3Vl-V+BO1#;Q)|qX{{6RBf9t(Xwpfx5fsa|b0Fu)Cg_9;FH z914yQbQpkPq#yO(2&5DgZ(p4>9^=hi&EdM?_lN4daCV;GoOFR-`JD9@+p(M+EPgH% zzAl>`&}zEOstCh=l<=kFTuWPfkgxg!<9qv8{Uui|#IHJhyBm?GgKuYe8cJAFIMcNq z#!qZ(!;lm4=x*18rJ-f-&Jub<+cViCZv2DaTJhdEy&mscBNlbjc19De+vsj!XA$La z@YMPcEHz$#9N(!2cSnHD5{lVh{>@%TT7bBX%12XXN?z=@?>9SR8Zs;{qXN8Xuf<%^T^+u5Um{o+a zREWe?_cOBdtBW4M`gh*{s4gwI{MgHUaMh-XoEz&9=*f6dSV8U28Lui(;pzCy20rxr z7b{iRXN27kW(6%$ADF7;RLvEvqr|H5#d$^6Vup8l8LPqqWBIAd8H-co!?Nlf?Q(Fc zsO|33wGWLU{}sDPHKYAE6DgyhbAKHe(dhGlU~vc$JKs=AM0?eXKHc%>hYJp~pe?=X z@2+M+syjtdrYzTY0MJIoslPET*7qz&?97K|KOwvz6i?qNn8fHYG)>S(yLuj9@B6(^ zHMy%iOCAptwYhY+p(FOqMzk|fYw#h09~VbJDV@T;*&?xA8!+tW`34;xJ&!`R`Ea{O zh?YK*^LQQHF9&nS^NqSLdA|7xU4rz@!2j8CHFnoSEj7{VJ^hJt4`PQhCtieWkyVEj zyx+a?anhH%g3b;i;ACUYl!!Xp&X%fF3*yhUD_PMc=fW^Imx2Y~+^hV!kx36h%Ltbp zomYYlXHK z=R-6yJXB>5`NwA_CqaFEOlvWOb*V>b%e9}H{B*I79ah$;|69?_c+^`9c5JSxC{Prb5TnCb%{@Vp^{Zw2 z)ch0{TCx9ZdJ+Nhl0FaSI$$SH8LcXJoxj%q_GKllfBuWvA=NrDxOoPb+>*F*`JL-9 zV7pJuM#l#cqovoNN`pnly3R!PW83rgZim}WjCIa|;s)gXK=-M59z#%ywF0T|L9o9QF?LS9vm81EZ1lc+$lzM8GZ zZuYD3?+Mpdlkz7KrCl#Vj8|jz+!iChNb>0K-X)GR>1@=MenUj~$={(7D%J9sX5Xyh z!P9z0Qw0#=r;RGA#EbS)tvd5b@A1q1tOe^Xw`D2>1>^kHJ3hZegFAsW4Y{ zz8r6;15;p8Wz^NrYf5fT8W+*(Lh)LH$^^JPGBH-^J9zMja5;X~^P*sH3zO2< z2_g}xgatP4jZD>)mZ|8;q6IGr+YNzGuPQ#vUvgG(qnX(z0qEfpYUAv0B-{ouB);<*~2Cw=b?^Z?bmxv@(7RU1-U3tG4z`nm}ql4VuQLsy?qlo)!;! z@BMz0%vWP+PU#X7)y|=6s^2x#Y!*%`C*jzDaX?6ErR5h+EZLkL5KaJ4GiLvzw;~B^9Zk5sl4~Xd@GkDC_S}&MI&h0e!*2P zRB=^LPdAmTueJ{2O|t@D3%;Si#o=5b@h-e_knMhYxSFsE!Q?o9Yqrr`8B~x{|1IFY zUizzy=0#s;8=r&PnVlDEktGutXWz=DXtl5V4eMuB+4EpCH6Z@=b^r~#$wYUXcP^m2 z&)lEVzdb%2-0eG*oFX?9!QB0@E@gh~P_<&SD|@(RyL}jQhBWP@Y_$s+eR@Pes`JqI zUD$=E(-`CT^8@GX#oL>QPxgM7yLem)=ndohc#Q{Y>`d*h zd&~Q(YdPdtjGcoGc{o*sPV=0c3L2ObHQtZF+tDSp42_4CA7gKqOjX*BlpdwHm6gHk z4$Rx=lM4(RxGvE<_K1`ffXX-u_vq zWbx-TzgJa&(*VUZ1Ee0(F<~KL+fZ0ytg-b9=NSE{0aKfZ)%Je8M#E`e1G#R4-4(N2 zBOkcQrn6M)^HUn^LsrsPG8;rTn$r_fTZ$Qjg%PfV9K)PppA~eQtnwZY4@`>sYEDtC zTVC(?=C6PTsf67frQVddQ4tdMvZM=D>dEp=Qw$`(aFMYfDwk}l%{Dzl95rT93AwJG zYi#SB?DG=e=$$h*GjI=w5i>W`wmGD=#=Xs)nU}*BqKf1EVk!8gWK)Wd)g$}W6;g9&6l2Ywi~@JF7`bG@g@;~ zi4LLHNu?iP%)CyhOnf3-Q(Mwrg1kR!(rwdkKs;(ACV+6)LRLksP z9P-!KG*dp%fK{n~caU0##D>?3D3a)xSpfg5PKqhMP@(s@}+)Q)y`#(oz ztdnqi0|zOV5Gc2AGqT%Xy1$U$eJuFk9Mdm_r~0L2r=GX%aPgi7z3;&!L*CKgi;}4h zqjUwH9FmL4{MR$SW{WFkmNy3sWdwv#z6;?v+hlQ%>dIP*E}CZ4FMOvcujj)gC1YLS z<9Y9`-ieh^7bw@HmMx^-cZ(3(Jq;=r6*M~^y?eRv!TH5zVr81Nj-au*&mptPXCb#a zQYxFI%B;0Ou_tgT44rAwyolzxi#AR7l_7byQ?af3PDGmTTAidMPv&NIb;Re;ix4ZN zZsfW}?uBk|Nxg-;fhqT%`RnHc9@>l3%Qhd29Egtw!(CN5>OChvGyn}Bbr*AxqPK9w zdK7i)u39w_=3TtqWHh^CX63s-GQM!v{aPp6(I`qMLv(LN#DBZ?tL5;`nCf-KNf( zZw;!OqUf^0YQa3=;R$ep;4SZ{Fhact8E-0S%Lgv8RSz|LZOKS4cKW9gz&d3kQQ_8k0m=KAuV zt0E;F#tdvq>uJw`9%XjsenVhg`1?n05(XX`;@w=FD#F*bto(O#}ThZ4rwVfZ@ z&-$Qu+STl>9ih@bR}tN3uf5pV(Ab!bv81*dReNrvK5b_{%d#${rs2z@ss5sfhxu9} zNSmAt;0bX-lcJ*MUM>`qYQ91onbtA}G(LS1REV1Dw9wwb<0FQO%euGZCzQ6^`@{+O z1zjf$rs5Z0zIqvHP}6jX_t)X^s35wU^U>egc(Q~}lC%6+F~FJn4E>5LFhfrksK3NJ zW?D|3RMp!V7emNRAq+!NfzjEkwr||2IQOjNOA9F9XmqM!nxb$`J{J;WnrI9A>IXYO z?5!y^Trh7tZ1~|+y`;kqaELaLZRtLXiLAoHkYFZ^HxD(0B<9oB72M~Ai$vn=pj&iv z==1g@cu$8eC|V{#Q%{08(js_wA_Uwbc&8vb>o4v>UyR63(|d-u*Sb;~XYI?*(tA>H zj!#LBL)$_sz#eJemnNgWJjrQ>*7MDG{~}k&2YI-)%)q0reMXERr5YL&Q6ou_K7!F= zzn@ZQ@?!x{s-qC6AVv2i;K|=zrn;*t8H1Ts7G?vZKx-`~t?DlA$i6-|wW~5u5mx#7 z$gy4sLGhWSkejUp(tQ*hr4t`E0zXk(% zCZgzZpV_!RZtywZ>RLTWBM|&GZ6|=@+CP8*$XH};c(=qfG#xVbk&@5xB|AEWcqV4E z%2T;VY@-26%lteWLb&ByYyct|WxWIWIxRb2(>20D!I?DS>j;Lk!DM5imT5>w#~y!o zPUc10TE)d)PCbf7v7uc~D2`-5eP;>9j0(aBA|Ef~TC&jCoK?r3v+#AtG1#~+`GqNk zg3==E#T?tE@@Z~}5Y(vjU#OX-%B(^0JD%$?wse;~?G!jDeqE-DRl<>pL%ixicL+dp zS^YnG%*)BDR%WO7s;2aOj+C*@4sBR)X!xaH%sXir(?IQMyLEtLBi@5 zW1H;NdXi*DfQAD1I)|8@yW9Q}TvM7Q2DIAra+aX(;1bnz6zNrYhhGo^j-ieIs83J74J8OET~UkeZbW6xZ4GCEqg zh4gaZVeZ=U_{Td%$=O8|?s>(vpEfPE9232>l>5NnN)R99f07E$#1mDk4+LF2Me4^*j zhFNP`&0_kg(tjz9&b0?sn7-G4dn{YhR?BdYav9PGWS2|9QQGl|krF6;_CwA~X&kl? z4>H<>*|^Z;j|`Ht-N}R%KOh@2FVgP(A$Kxq!T0`v?i>xSk_-ZNLx%Ww(Ewr7PuvpX zy`>e4Lp5o}X95=6Bv0M4ow21WgjWP}1){gi+pI~yXdPiTkOb3TIpf##lk>p-0QGDQVo8Z~`xr6g zVTy7HYP#2U9BYK00D3V%PHQ)vxlvFLQ3B(-N&*vg;p*!IMGFLVZh5V><5rgxB6F+b zZ3na-rcDWJPc1F|md&$-8*SFmoU>GZ7X`xFFXB!LJc!=Y5J%{98J6FI0nWc}8L3-% zICpT4;Fi%tbN}du*T1`m(I5seA=S5R;a?hn9s>n3PXh39VbJodAMKxX94UY2d;YD!gH}GCeGFmgNS@h|&Eqw< z0Vo>4Q{K^#u>&MR(GD@NVuszhCAyX@0fgD`55f%K-i{vr$-)m@op0NAzdJMx;2rJ4 zBin`FLMm>VF`xo}2sa@yS4m+$I|BXyR9P93TlQuXH_H09vR)DYf#-RCvu$GCS}6l# zFWWxGtH)utcsB5~?y5f=pr=1TWslw8k@ECUzVP!!*%jJJa0g!0zeE`TtN`tqNx8-2 z)rBJJmvGl15B~bUSV*~+kUr21wrCsgh+CqR-hYJpZ|^=s(Kl-B-A(PTcqrPY`=46| zK{$>O09nQCIN+{-sntl&uZT?dh})hL67%>@Z8s#PPI=2}gsA!<^ws{f8=xQISLte= z{(&dKud;9ZDFR6r`bV&E%N!_t`qTEYO`<~#*|&B>)?YvH-uenH+W(Rye@D|R4rFkH zfpR6i?||yDR?~v+l=wv7K_wzkEWX^&g(>3oo(-YMr*LTf}RgCWd|MTaO}d z4FcN!ABG7a)POOx7)NcV#%xWqpwdqSvrfS;0mdN~xO7WdD$J&peLQWS4>dntP9Zz~k_0_~iHYgpwqn z3CsV@EuQkirl+T;sHo^6e(_LuFP1?JYg4!D_cTA4r+Dh<;RGI_2)idJaDOw{NmpBY zYIO9uGgK%Q4Z?EygIFhtR%YV44D?Rz~z=*|eg}EZZ86 zZHFgTf^xFu;3?I07uO}jH?-{l)br^wbiE5Y-H#ncr4B$p30hMZE@luVvri)mQfGuQ z2Mr__-{9 zGyaW3fQ}&T-v&DaLqJRr9lK*JY{>Q_836P) zv>Xh#x^yrK-2@$Z9z}QA)}%ZEq_MMMbu4`O++wqNJf?=)LQby|cuyzS$1;4KITlj2 zFG}*f5mitv26$&t1AyPEhJpXIP%VI(8upLWO~${ z_j}2L_7kBa@dbmOhkrC&uy9Cr<7t%jhN|3~##aJXp>F}LokC=YalRPCRsbNDe4qbn z4BGV?qp*G}^}Va4#W4BimTOKEdjulW4=F|2m}AGZ+0`Cw0KR39%LrUPs&!(mEhfZP z)QjZcQ$}_(V4OKPgi3=LxG~?U)5zCJ_TIu@0Nn$9Y{)3UtrENgeIW`vY{mb}9$Y zgg1b!;x_BJ)o~zkTcB#Gyg#n=#|K3P5~tHzfj9T#%uRz_t=I)2*Y0Txl}|720`Mi! z4qtL~NEW`#Rdn_6Hw;#ixZe|?engefXU%zeXJ72yGIny6O+DNdrABPW#1*B{qxiMy zV{&IO@MI%+%@GK#Nz|guJkH<42%UJCfrX5g8q%T)+?o`LA^5OPCLg5bOY7olY${mz z_aq=-(uV-*xixVLI+*VDF8qs3#Z@lWYE#CPpsgYm zRU-QNR~>iaOpq5 z*Hss`p7_Rm^Ja%G+6KUJvBM)-CBzwG2_4&{80ezYum!nN?(frn6GXkU`MiU;8eh?Y za^v|cz_6q_X9507uxy|tSDH2g$|6E@;GY*u7`^mj#16o9&E3pi%Or>Sc#Nus3BMGp zy2)_MXxwK2`@Zo0ne)^G9e(X+eS;NznRU(X1?^sUx7zJGeXdcGf&7fI2i2=x@{u7W;>0K9jc-2X@>)_0!ZPhb)b`lW0uI=>|b~e$&>4lY< zpxR(_dxx>=yx3_U+gVbx$2vkRO^oAquAgeOr&1~W&m3P4Y+?HK zY}CE2_1U*w?Cr((Jxyc6vEv9mo0@8Jee>}X$YKD`y^zi7fEN7&0t2I|@^m_iz0Ke)+g0GkTIui9; z&IFOuUsai>&$A{DHseMUuBzgZt(Zl{#Z%eh;{ANiHb1`G;;G{T6=d3P) zvd&h)T3TClb!UHj*gD7>AFArHdaT_cc+UK(Rv>R7vMNbl&5;{qsYAa zeh{XCNA9|IW1BxYs}udh&$g{?_S4cnPoIdnD>{ti>xzFgZM4=n7k68URg(RW_Rn?X zoUK1$M~pS!z`#C-&8~$`7h%Kw%fQRvHGmF!GXaf;UjYhOV5QlERRcD{4I2Lh;?FW> zwVquIh7a7+7OY5n63E@=NeEQ%rty<`<+qRylPL=iACIrHI zv8Ca=Zx9(=un*OUXVb2-hF6%#C$M?1UCU*0>NQvs5ONwyhCkF8IXsK87j)6Q+t>Y6C7;b zUzX={oDWJ$nG#)K4HN3h5?*#bsUd5YiSs#=WDd~ieCL1xsc&ll2Bo<8&}^5b=~be98GE%yZN4BD*VUeWx<*P(nJ7z22{epD!7)M zbH~GfyFwOVeF_WunYj&tG`AgJ4sYYov+Nm=mNB9~FP#CTyU*=Z9NVfkd0nt}_{!J` z8-8pKb#yGAH(j6hT+cS-sGAa(oA{cATE6R@iZZ>2mRXGkk^V>-qz&NP#o;5c2irf&tzUuTv2$cks|0=t=t{E6X zEU~8IGO~2DKHGitBrZOli1DcsDv$ebcvCs&w|ZfS3#sj=JWmMkV#p$nCoLGgncKg< z@v#u??w4qdvfTjY!(pdnKzAE+5v5Rg)czdpUQb-y-G%A)z}#N*L$HKDE31xV+u6_c`-i`((jITmdKNr)eM7IJ z@|IxeUc}k?sFnFIJBBCc@5?C}bbRIK;&QEAN3`;9mk0&*z6U)fJjYRAn*IBSnd3E- zGZS8na*_$H{bEM8=KJn8wMQTvJdS=|-aok>3}{m!|C|Fzoui7Q`pBKrU+eN#2Xn^huVTV~e-gm$lR>xWzeq4x?4JV{;i9D)I3AW7maec|q zmeTamd`G_e-SO1qglNX>^~Ey>$<)bF1`wrDiu| z-^P-D{e@$&J7-ft52DfL#RzYKmN5I(0uaozLiF2&8ZLm4pn*3>Pzv2#XqWn~_dic~ zy=vxgemTF68KA#f1le&vN4gA(czA!=B~fw2%El+(o2PaD$zLYq&7-;;L!REm200*T zI2{3;40*VyOPxN&ajZpGp+s+P4d3!r$drC>ojB?w!ujm|NSYgbo~cINez zEu>w`qA5O+i(V?CDIW1miLDPUfljjm(5tZPQgYa_IV#71Ff-MBwJxa<&-hSQIWjR@ zEc%%2)pi*ZuC+Pewh8et!`#7-EHy5siWb&;p5Vwc>_a}1vHP)w8WuX-D%bwKD>q?* zvwORTMVBlC{C2|A$zAx?88;axO)|VfXT9<`ZTNU4WKz!GD}~du?2$i*+ZwRk+W9|= zdfn;w-GOC?P~wAxEmh$W3Zg#_{dxUA9x$XTEx1d~3eA_?KRolwpnS5PM=8+5pWnbf z<2BFfTR5M3@KWq3Hbc}ARLQ1UsZo+*s$CWx&LmrV`dR4uM>3q|EbVJ?Z_n(HF#PD& z`R65FOgCa&Wz8Ec&?V6VVofLE-?SPW@y;%UBWH`24@2MG{3!iAPzUnh5g2daJI@r% zKDfRmWSi2#+42h!^6}5(8xGY}jeB19O##X#y^M)*PrKb!ZDw*`-tDHcXWU*AQmTO? zPvWLUj{4%Cx%=P3XI$C^5t`&$^BX(0L zW3aQQ@q9=Fo9Ml7hw?1^o$u}(6kU1R0j?EMKbzO2m!YgPV*L{&T2rjw+{*29F1yw2 zeBeo9?h(~l!Dm%?z%Z#* z`epUR29D2BTadcPa(i64(p~k7?cQFpWNkqTjbm7;mYL!wRs2G>jhu=Mg=Se;nH(PT z1wR=lPESi1NbCKyYpjgMlUI!u8Cot{Q-n?$Pe+D>qe5uYHn5Yni+bPog{HsL88duy z7_eTkRJHOgY`sFbN)8sLW#I4$$Qt_7Ps>X9+W2Qg_P&=d^PBD@2?*Wf-ItO)TJ()_p(l4%d*I+@*5($;BC}fF~TkOyK5He*4mDnKslL~*@qON$ccm!nrVQ5D9fGN7b#Dgz{4g_oZ{`h# zRmq%tBX+(Pd0h__o-}&=7jX``-9Z6_q4I1ej3j{oAl=o~@nCH2y!IJilaPDx5L8N` z!*P&45`sK>9fbP{JDbl;#dY!!!)6N$%@dAC@rZaA&wz;2Uz9U0rd2(|u*YlN(v4vF zn?dU|e`K`9o_st@&29@$zpYqaeL$W~R5w^l{pEh+As(zwugBsGAq+pSwmv{g4DXC^ zWR{O#;fl9zHYXwB+mMXREo2s$z52ag5)d~0*}!>=6seVG^@viZ4q&@67tLP@0E)=` zYl_c_jl^!B%1R&#riTE8L<}DLO(b%I?_%oP-+kzPm{z1}0&lhzakA)zg{6>31cW+X z`CpiNTgi2YbB6|-x0fDIrBAsC8NYQmUBeGL9z4;W-l;I@rB_S_;Hj<%&HrF%285sV zLS>$-Pjk!ZvW@f!=vL5*R^wV zJ0dpg(8OBfgwI`DO|j|#T19#Xt$`5OxRUO72*|^W_7c;J5|^qvvO9|siL!y! zX_CSJfmX#nZV3!O6 z668v?UV#vwcCd|lB`7E5qP4k<(p}Bnhtj~8#Ozc=7UWC$c*10=;NEcQ3fYCZ$gqol z7gnD11b;WKFu3yM3Y-9NQpV_a?ah1Z_-OxU0A zG!Qc~-92QPkggbcC975;kUEdqpb;Hg=w&+WBEVchpBtS6ECST+MqWgx9m+*Ri&&y{ zq~7d2*#)+dcFIMUZgqLl$pV{68=`4zin`YSzI{i~(-qPbyEG_9vrT#c``@H+rvOn? z7+Dqcjk=>Yd}28CJlmqZ(fC4Mq{D~jYa+$i4<%cvH?6~HA9U|=1iV!KsNf3duEZ2+ z5#JJwrBE9x3fNcTuirCN^e%m&T^6LHlj!qmd_&@1?veQDB=aawIqZPVe zcj+K9>p@Rr{=kz4gz(wrCWCN0hYz zr22%}zn28H`Up0{-22=d|0VH~X0lJS1uMX3R2r~}9fx^KX$&F z5hL*{)R>&caUtQ6(tr3qcmJgt`z8gJvGe(Lwqs=kuulZ$7M;HH+ldA~mK|I2KHqul zaU~@ufLAa^D;7SR-bo|OdOR*308-uGPwT2d>yQP6?VkUH$NYpcnj}p`ynCx4iSTX- zV%xsBD$I{keX(}`JNWbuKLOQF6p&^-$7p^3AqSaLV-zsm&Z68bQG;(-QC7w}YVSX0_WCg5T781BUhEI#s^zNZ2zv+641$7! z0POnTaGSez`x(d)Jz?N}x5lGQKNzOTjgM`Z%Z#cp8+p_TV2Mh=c5^CGO00X)xxD5t z1oP65Bw5sP&?r9bBON zQ$sbD)AHppzkdZgDI#BwDnn2(RFdZ6WQXd7H3^XY14Q6Y*^2v^b-3<99ASyg8HuNZ zZB2Zu!zYm0S9L~$gt$~9)9oFTp7+OC#wsf-CDnCwwhlSx44w3mCjxQ8_IplUb=ra1 z2^en7Az*sZN3>=#zh=JXJYKa2ne73|XH^KmE^Lr1&mc+jhVz=CLIU$Zd~ltSi2~Iy zlVb?(i#+cDD>xVDK-=0B(I ze!vN6HQ)<)x#NW8W<8t77f|R_orQCfrY~;h>bw0B`VVKm zJ|h3QZwM*nmJt@1r@Y&&Y6tvdfEB=yS$xYbkkI5uI-@G#h~-Vfp1Jz73YjtS25*D= zpDL=uv-jcUoJJj|?;F{hE-T8*%d@j3Za@!28Fj^GtNIbDrPNijY&y-G@%RwTG@FJD-zthT%^_qx&MP1Pud4OWOyTxPKGH$eG3-g6W%NlHsbq z%szz?j!dP6X+1RpR(fM_IDBH_hiN}q#vre0U!pObkpG!H4q5{`VDO$-xAMzjBjHlnS zU-d&%MIuOyfF}TE-WrJ8J2*#hobJ^@T(&j~XT>n4fzA`F~rfoAy1PBlyxCAEzm%#}H3BetLyEC{;65QPf zC%6QMU+$cVNFnf(=p3!rvlfyEh#6K(LsBWgJ1(8#cFwXt%q~ zmD(@7$gkf=)*01k2(L8?zXBK$2-XYR8=3AdCtI9YnU77;@t*=p)bzxzj9;qh;p{5Q ztLg!<1t0hT0A}cKx5mO&y)+K7#oW`)9eeeZRe3%vsOjY*3NKTXtA{<{+n=JJtY{fV zXylPBCxgb;N(jOL6x!+GAE0VKGV{6fzFyoaJy@1y=l5#w=m)!hF(7NK?wpvdY=BY) zu$=6B05C?LdM~?@98i<%fNRLNQvmLc= z6YYz`_y{~J-$DROgpX+CG15G?DhgwO#IuB>Gz*3Kqp0P=7_$&XN?)A4Xh4*vZ)_BT zZq){G!V`kl>7 za8HsEA7KoIXuWnNE*sz0We=}CG zpz+KToVQhr&Gl;Y`l=V~np2TC#DD|C5>38n5s%(!eOG@_KlsY<^b;OWIpp;+f;d&p z+Lm-rJf0|V0SqYcJ(X)~$kW=NQ0{$L?{I?>8OBM# zqMDnDAg9F={s1us3+l>B;}JhW()T*e27M6DP8Cw$;IC`CZT2|n z(*vR?ZPy~V3wI8SqnZYW=<$v4r;y`D`FSd_2K9n!LSn7@p-E^XaHZaf)HJQY>5{* zzd#1J<%z5b^bm+@o@A9ub=ke_=CA@MT>GC@tIkGxCw|vGC0Ur=g>?7AV!i!M$Vd&%iq)j&74py-$~oxz@-||6+O)wTEKB zWdV=;3B5-1*1@!ru)Y0Gu-9$*H}VhI8;ee@3A~wpj0+y-mdF<@i= zv&dNoQCKPP8u&DcpRxZlz0j)8-JV!(r2t1@!5$&8w`RjdQPgxDJl@tM8N9ME{vOSLBldfy9u{}w*%@(Lo9})j zQNf)%XERPJT`zDunmJdx$Q-Ebem)aVuba6mh~w$u>R@%XVUlpRUEkmCYboU)_9S0# z1XM~g?@zSI2KTOW`--(SKw#58$ynT%BUO5BYTof(b|v*x`b`p>=}_u;GMa;&j6SoK?O?z1X3e35+ zCthIMon~ZS>YDMghke6OrQaQVeg8S=#!~uslWA70+Hfskgup=(gl-t4?bus6>_U{x zfAhP7PZOvUk>|x-o%%}!s$!)DJaxRjM+Z@9x{U_RLmQe(d|RYsJfcqK3x8;NnQeUc zFX0bnZo0`@gyJ5x5(Eh(bJgURHrqJe7@}!E$H>^+u^1=ropp;Bx=i3;^-=o(y`);h>B>fj+Wo zVCFW}zS&6HL^}-K5nZzco}Zat0u8!sXdrseolzyRKr*%WIa(ln;SxRaBrU&n!UXuB zi~ZUp!``6U=!mhvH)K(^{@^qCkdo3^?d4kdBuP48c;ktq<+SG0B$d_=nN^(G*ldbB z)zKLfF?K9f*IXQ)PZ3y-D^1Z}GVZJ%z$jfbp05YDmArD^EV!y;-6*4LcAUOvrh56S zen-749%Iw%RBAHh%_$g|dGWm*YV*sA3+cS(PC(k9sDyXaCmIeHW;`N8-kIutz7iH5 zE4zqByRE9HYu$kITwUQQAZ@%P(z-r0H~&N?{G|s53=!^lCyR^Yd9S@Nbh+k3l{t=l zlD`0UAW#X~drH7{xBK=5mrY$hIveDCJazarYGmpO7l})+lNd_}KCYb3P*qK;8~*I! zx^}aMhe2P=#AE2hapT1-Nco(*$sHbh78keZG<+B?upsB&@8P5<3%^85OKr61(!@EB zd#kEoeTZg7)Z)nK?%JJ`6S?Blf7xJowRh_&$}oPjbIY&IeluVftfvXptYza|8gQdp zAFiIhg;cor)#SvrfirD}uR4MV_UlW(&P+C*9mfk}X>h?|aW*wxVD}e=$uKXNa#*u| z+vOk#Thnn7RFJn{p@LHc#?DEGBzg`Ktu^S6^T-S?GGF48amO)V72Yzx@jqph z^UG^2yaf^0ax;z`ANHYbSQIuLZo5e*pKXiTZ}Dy5RG`YmZB-t=e*hjQN*BC7wE*`O zCdoAzFKKgN&pF>#Vc)E1H(d2VEXP48GK!k!Q0~1jw-TDw*+o~^{-i8@DiW=#^Ycx& zW_EtYa#-U={99tLoyw?9P#xTDG~cj0d9akrvy;y$esth0RlBLurLQu~x76}Y?ctZ5 z9yR!gidIT}@wOjENI>2yq#oJ}jEa<2XtO&CkqO0fl*Z#!@yC@XE7Z!CTr8f))oWFh zqx(%O_Ga3Lr`oT^A#T@PXLD)rnKZ{2;cni;zphrJi6}>*O<9nzVt4rT<0^eo5Ca$g zdNNwbPODSn*%gk&Km^VvnZ2DwFUN)LL+$3RdJm&(V6KBok#t;8kp-2@ z@nV4YH+lEsNHn#D$IiRm*nL&zPpWLqv@ZrKkR3xx7EZR7hSA*JgtXv(liHfiCtrKT z+8t3Ik3XE=O|fMA-8JAn=4mkbdV8_1CSPZ$jj%dC;N!p#(+;NF3`+2TM!o(g7oEfM zl4sh@J9E4r~Wy+cu1c zA-4$Azvj1B!q$iLU)YNs9)st!q=^WO1>lEAqs{z2d0F*~p|_3>FUH+3J6(8k791u+ z=1vVu8_V6{zS?+7&CY6*i8YH{WoWa1>gsVDLqO7#jF@B4G?hf`NhhXLMMx}o_Hy8* zjAsr-F3^*+colcp1E9I(Jm5|_#+7efV7^sV@o}i3x9Pu>U=x0W*E46G8}cie&3l&Q znFEX)H--9h*NgZmI9vzQ!4>>O2cgNfuNs?ZZ~fd#8O|Kuy6v6R%@&q!XkYDgZNi(` zUzd8c?vz?ix!zRD4G~~9;r{jTOG-JY)%yOSO@+r&G;X5WN@I1=9%1BOwai%`aDofW zvjyXo&jVnPiUGWGli@IO@~>{H7ggB8!Y(U=giRJ(9j)$15k0$3fUU*owJ|EmS^sPh z%lU-wlNKre#q;Jh;jwwV-G%pxxNZ@O(p+A>5{$QYv>3i$r?XlEQBCYLk9#1nIZsND zfPlT3c`PgL-1;GCom6*)9**-y<8Y;sdl5}!otY` z4@7d;B5Y%rT*IfQ>mYU$U=2eZ<(2#V4QcN*WXE>4cnU^tf1QeETDm=K1$PO2FDbiL zg{u!jDafAtR-9E09q181G2Fmn8K7;Z0TJ#};M)%PsxNxofXxH)cyMuXf?imp%MjZP z1jFp|(rZI(^jthx0{xv8G~dI^!fH~3wcT%DaBO4czH2go|G?ZGtx1J z2hf0bzk4D(PGF>bOME>nESj3|+T%HLU_g@7zA4x|?YhO0EXdvo*v78SwjF9&EA<#+ zHd_6Tw@4UI-qUK-Y29etQreH_T^gAd7_eI_v?4hPq=p9mCC4(?n;x( ztm)0UCNsxorZ{_Po@?N>;I4Ec_SNqJK1EL{E)2Q-DVx?f#zlAgrx=D$Yy$$G!(g^Y z@HN{3y9d)_M9UDghRufJ(uULJqw^CHJB8B^Qal8vLzHX$WIZWNx(88|JYkTuR@y=t z5`m4YN`9_+DZwRArwI}oVh06=4M;2wjywT|<*Zw}_Q?s*)5@;D5;Bd=%#)AsXJ>g9 zE;>s#v!AnZjMhDTLjURF@(EFvnDXFxM=ij4|JV2_V+i4MbuX#|Q~u*IQt;(!`u!b0zCjt( z*w*RJP^gYBVh59bf1)-!lJVn%kD9Xljr$ffRu)q#Q2w`wl-Is*dym=(M)AC~+OTBf^b`(nV~5#WS*f@iY>Vr0NvA6IGO zIv?8CBrsdQw)8wSJd+~W3+_ynDJ5hxo{Z9@_l;E$C7L~6IGx$mxwU(Od&MHmp5{Km zeUn;GwI;W6HOU{e9?g!fj{noyYI)rw~O zV*cex;xzV4kR%pW4}n8}v*w5l(`{686LYrV*+3{eEKOb3eY$Z}l;z*PP9wVij`2ZI z&pp0KYRL#W(G0!*ol6{cFglszmuIb)P_4$i*L{JT2l47oX&eUjx-ociwHV8gGXi;O zw`vaI0GbAu`GJOCN+RFhKRN6;L4^besdHHL<`ZgmfxM3A7ULY0UnDc_6%4o2KRG+v z&UlzKQOx^M7|TqfW=nRtsb&7xQ-Hm2zPW#0Tu_SN%(Bt2@(#vKwydON_++BgYz+b{ z@jFRIvunDZZ*C~dtFSn3Lk8ojjEz;Mq2aR7Xpmfwm0^SVn9coL9@;EjhzgHQyM)*U z5vn#*PnDLZSxIJs89AMV*MV5)qOijNGZu|LH)Y4{2j|9B*J&|(XDw#}8N7=tS2m&r z65zbE(AfFXONF8MLNg{9Gt&0(+%rkBvUuBjNtR*`cs8BD=A2|r{%v?8Ue<=rgO{Sq z5EAu^Q_PBL1)2}Tk>L5+p^}E0!p0QNjXi=I5*j=vwgmzV8!h>%jSr(%(!!`uX4xLL z!_kP_c2ssZsmK6x3r{il@Ha3&SA7#S0s}{zxol)|Zi;N6wLq}lP1$OT)q;%?mp$8U z-Y@In8~;sk6epUKlV~O^+rdde{VMrsD@~YJjHIl8x46zJ$KWL#M)%d*Po{RaN6rI{ z9jf$l3dMD664YFrpAj7p#?D@2ZdL7kKpNEFx1ZEMTR|s=V}0`I0}zkd1^MvkM>jag zEHgZMlNu24@ku<4k3AG)xxo$Qr&*VaMn5)(9C*f4Tdv(37fK{797-=1h$-hF()^Hz zqsC4;GR|-|Oz{QLCys20WAWmvv@#yr>0k2dP+~t@RhPTK}<0K9FJ|;1~BpFDQI_mw7pI4}8s`va^Ypo!)J)6vq8EGSjY-pxC~rnGW)*!SgvLeU0ZxAkZk3yZt2u@<}joC{7G{FGXT|60Uv zaM7tPX6xFWqAgWS=~e&U8jH7@u3Q~cpPxmGmR|gh6(||#qU-Ap&?>I1wI0Utx}rEZINqi!E%IDj z@w$oxM$e_D`@Dr3}O0i$g$b|}CL29s}hUdCcE+$@KuJ!tJ-fVOZmD*&u$ajh5nagHfxjIEBo*yX0F+|KNHX%N%Di53**GM1`8`swfG=IDTE zgmX$(Q5Ml?hU0fmt-@N!2XxL%LbAq?OR*bQu$N@HiJM-CQU%c3DDw@L7SA|AxFP#8gPWY zq0w5MAR~em4zFGeFu2#9d6LQ6^IJwzgpPSUH{mFiXtoAp7=QpNNir|1(vK*0lf+ z5UL3OxA7DMK7g=TVOBhjh*A^ab{?-nMT~~znK7eEK$|o{#vZ^>$|f2iL4mdhF?^%6xqh-~_0EQO&zcYmaXZSvYOAmRkU;*eJysv(M|6!YK8ZDCxc%E_w`mR^@WS~YEZDWCSXkhp#4BQR+E_r9U&DPKfQOH zvj@Tz`pFa3f^M~_+=@%U?_O(Zz&tMJ5*{fsDd*zEYy|!LX9a5>?J{%J%M2$ry%J*) z+iCg=xRf^$AV#5{3!6KH0Mgp=jmICp)`+JdRAuZcb}VJ;09x<13U-`=% z$HvCma0vk2HOg!2miqu1J~luU9tC(elf8jbmTxk@fyz<$YbvHjMM75@-lPG%TgK#v zlW)uZbq@xxCO|!`VyE{9Bd)}yykk@J8$WH}1h#kqJ-0$SElb?(`;6Gg$T_)H|ZbgPB3vvCdJ*bYGMdTU&d_W*sTj5kr_EGs9#3AGUc9DFZg{iAwb z67UayPkD$iVI=dx=E#xG30#gQJ2#Z5(jj-(JzCglBGY{CNfNxsfry= zW?SPAiA&@Id{csKMWuK^Px==*1rCVSyb7IK^ii$YzMovqEE;XQ}1j0{y%=b z=ak5(51mc z^>;FKZW~wcM!s8)ewW?9A^i_PjsnnB7H$SH;CxG<54e*a1H<>hUwiy)&mX&L$mO5y zpt@p_-$!t7(tW9-wkhAFjWh@{pQcsgvbqe6lB!%ti+7_-h@|=%%<2P<*Z(V@-v1p! zCdHTY(e5J*>141UV3Fj|VAjXaV9fmi5AP%J!t}?;_ZtOgF}x83l)HKz?E zK4w$(0jI$hNp8RXeOFPvcP4@uKd)s{$0Zp$IGZeHAJpkdz*FE?=7#>T=e0>eT+dF^R@ttr3e(Q9=bXZ-{Vja^Z-W0t=U!RQq zN+2(r2(T`wKHC`x0|;uli9x`?*B1+u)~&^5?pBKgoRitcsQm$7tR>=V(R&eWZ?zg! zS5RNdy?@`j+#Ve3wcJG$@!T3!e3RxKAeoh_#rkiM+k%eF2tlPP-JBKV9w}vBem=9C zCKu;(fAmc?Yo~}iN$_9#D*&YhbjSsW*`yH=ndX$R-#bRHtgfDEdf|`$0r^o+gh=~V z|H5Cw+@bdfpqM4=NuwZ+qc9*p3 z0mP7hRoTEyqg4pXYt{xF))AU)9OCqaQg6hVzVl2OBB+0ikhA~&@C`a2AG^5Be~TR$w2|0I

i8ByZC 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 ij5^R#l9ZSBD2(1<9;9#_x3wTKRN0j_`=TuZ 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 TzsV(ofS*@VN|NQ`2LAsChdBc{ literal 0 HcmV?d00001 diff --git a/static/img/wrike-integration/SigAuto-SendReminder.png b/static/img/wrike-integration/SigAuto-SendReminder.png new file mode 100644 index 0000000000000000000000000000000000000000..397acadefd42bcccaa4e4aae00cd2a412577c160 GIT binary patch literal 62521 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�?hvrJKOxfHvVB}X$TlYH2 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 literal 0 HcmV?d00001 diff --git a/static/img/wrike-integration/SigAuto-VoidOnSend.png b/static/img/wrike-integration/SigAuto-VoidOnSend.png new file mode 100644 index 0000000000000000000000000000000000000000..65296e99445f782ef13e4ba92011e4560105f309 GIT binary patch literal 67715 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 z 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 literal 0 HcmV?d00001