Siglio API documentation

One POST creates a signing envelope. Tag your PDF, choose email or SMS, and the signed document comes back on a webhook. This page covers everything you need to ship an integration.

01Quickstart

Creating an envelope is one HTTP request. There is no SDK to install, no OAuth dance, and no field-placement editor to configure first.

1. Put anchor tags in your PDF

Siglio finds signing fields by looking for anchor text in your document. Type ^S1 where signer 1 should sign. Set that text in white on a white background and it disappears for the reader while staying findable in the PDF text layer. Full detail in anchor tags.

2. POST the file

POSThttps://api.esigndev.com/v1/envelopes

Create an envelope

curl -X POST https://api.esigndev.com/v1/envelopes \
  -H "Authorization: Bearer sig_..." \
  -H "Idempotency-Key: order-41882-contract-1" \
  -H "Content-Type: application/json" \
  -d '{
    "document_name": "agreement.pdf",
    "document_base64": "JVBERi0xLjQK...",
    "delivery": "both",
    "signer": {
      "name":  "Jane Smith",
      "email": "jane@example.com",
      "phone": "+18135551212"
    },
    "sender": { "company_name": "Your Company" }
  }'

Your signers see the sender as “Your Company via Siglio”. If you gave your company name at signup you can leave sender out; it is in the example so the first call works either way. See the sender object.

The request is JSON. Send the PDF inline as document_base64 for files up to 3 MB, which covers most generated contracts in a single call. Larger files, up to 15 MB, go through the two-step upload flow in documents.

The envelope is created and delivered immediately. The response carries an envelope ID beginning with env_, and every response, successful or not, carries a request ID beginning with req_. Log the request ID. It is the difference between a support ticket that gets diagnosed and one that turns into a conversation.

3. Handle the completion webhook

Siglio deletes an envelope’s files 30 days after it completes. When signing completes, your webhook endpoint fires and that is your cue to download the signed document and store it. Build that into your handler on day one, not after someone asks you for a contract from six months ago. See signed documents.

Start here

Every account gets 25 free documents and no card is required to get them. They are real sends to real recipients, so send the first one to your own phone and watch what your signers will actually see.

02Build it with an AI assistant

If you would rather not write the integration yourself, hand this page to an AI assistant that can write and run code, and let it do the work.

Give it this one line:

Read https://esigndev.com/agent.txt and build me a Siglio integration.

Use it from Claude: the MCP server

If you want to send documents from a conversation rather than from code, the Siglio MCP server turns the API into five tools an assistant can call directly: send a document for signature, check an envelope, download the signed PDF, download a file the signer uploaded, and void an envelope. siglio-mcp is on npm and in the MCP Registry. One entry in your config installs it:

{
  "mcpServers": {
    "siglio": {
      "command": "npx",
      "args": ["-y", "siglio-mcp"],
      "env": { "SIGLIO_API_KEY": "sig_..." }
    }
  }
}

Put that in claude_desktop_config.json, restart Claude Desktop, and ask it to send something: “Send ~/contracts/lease.pdf to Jane Smith, jane@example.com, for signature.” The server reads the PDF from disk and encodes it itself, so the file never passes through the conversation. Other MCP clients (Cursor, Claude Code, anything that speaks stdio MCP) take the same command, args and env in their own config format.

A send can do what the API does. delivery defaults to auto, and payment, attachments, form_fields and constraints (the last two Enterprise) are passed straight through. check_envelope shows any payment, the files the signer uploaded and their answers by label. Social Security numbers are always shown as the last four digits, because chat transcripts are kept.

What the server will and will not do on its own

It uses your API key as it is. Your first 25 documents are free. After that every send is billed, so if an assistant will send on its own, set a spending cap in your dashboard first.

Void asks first. The server will not void an envelope until the assistant has confirmed with you. Without that confirmation it makes no API call at all.

Retries are safe. Sends are idempotent by content, so an assistant that retries gets the first envelope back rather than putting a second copy in someone’s inbox.

Files over 3 MB are refused with an explanation rather than uploaded. Use the two-step upload from code for those.

That file is written for the assistant rather than for you. It carries the API contract, the two mistakes that break most first integrations, and an instruction to ask what you are building into before it writes anything. If you tell it you are not a developer, it is told not to bury you in code, and to ask what you send and to whom instead.

Three machine-readable references

esigndev.com/agent.txt — instructions for an assistant building an integration.

esigndev.com/llms-full.txt — the complete reference in one fetch: endpoints, tags, states, webhooks, errors and limits.

esigndev.com/openapi.json — OpenAPI 3.1, for code generation and tooling.

All three are checked against the running code on every deploy, so an assistant reading them cannot be told about an endpoint that does not exist or a limit that has changed. That matters more for a machine than for a person: you would notice a wrong answer, an assistant will confidently build on it.

Test before you trust it

Whatever the assistant builds, send one real envelope to yourself and sign it before wiring it into anything. Your free documents deliver for real, so that is a genuine end-to-end proof rather than a mock.

03What an envelope is

An envelope is one signing transaction: one PDF, sent to one or two signers, delivered by email, SMS, or both. Creating it is a single POST.

One envelope is one charge. Two signers, email and SMS both: still one envelope, still 25 cents.

Envelopes carry your business identity

Every envelope goes out under your company name. Signers see it as “Your Company via Siglio”, and it heads the Signature Originator Information block of the signing certificate. You give the name when you sign up; if your account has none yet, the studio and dashboard ask for it, and the API refuses to send (company_name_required) until it exists or the request carries sender.company_name.

During the free trial the company name is all you need. The certificate shows it and leaves the other originator fields blank, never filled in with anyone else’s details. After the trial your full business profile is required: company name, phone, email, and address. You add it in the dashboard in the same step as your card, and from then on every field on the certificate is yours. A send with an incomplete profile is rejected with a message naming the missing fields, and costs nothing.

The sender object

Resolution is per field, not all-or-nothing: for each field, the request wins, then your saved business profile. Override just the company name on one envelope and the rest still rides on your profile.

FieldMaxNotes
company_name100Required whenever sender is present.
phone25
email254Must be a valid email address.
address150
city60
state30
zip15
representative100Optional. A person's name shown alongside the company.

Every field is a string. An unknown key, a non-string value, anything over its limit, or a blank company_name rejects the request with invalid_request before the envelope is created, so a bad sender never costs anything.

"sender": {
  "company_name": "Coastal Group",
  "phone": "+18135551212",
  "email": "contracts@coastalgroup.com",
  "address": "100 Harbor Way",
  "city": "Tampa",
  "state": "FL",
  "zip": "33602"
}

Your logo on notification emails

Upload your logo once in the portal's Account information section and it appears at the top of the notification emails your signers receive. PNG or JPEG, up to 512 KB. With nothing uploaded, your envelopes carry the Siglio mark instead, so there is no broken-image state to worry about.

Retrieve an envelope

GEThttps://api.esigndev.com/v1/envelopes/:id

Fetch any envelope by its env_ id to see where it stands. The response is the same shape the create call returned: state, delivery, the signer with signed_at filled in once they have signed (two-signer envelopes carry a signers array; per-signer signed_at is how you tell which of the two has finished). A null signed_at means only that no signature time was recorded for that signer, not that they did not sign: on a completed envelope everyone has signed, so read state for whether and signed_at for when, signing_url, the resolved sender, created_at, and completed_at. An id that does not exist, or that belongs to a different account, is a 404. Polling this works, but the completion webhook is the push version of the same information: treat the webhook as the signal and this endpoint as the check.

Void an envelope

DELETEhttps://api.esigndev.com/v1/envelopes/:id

Voiding cancels a sent envelope: the signing link stops working immediately and the signer sees a cancelled notice instead of the document. The response is the envelope with state voided, and your webhook receives envelope.voided. Voiding requires a read_write key, a completed or failed envelope can no longer be voided (a 422 tells you so), and voiding an already-voided envelope is a harmless no-op that returns it unchanged. Voiding does not refund the envelope; the charge was for creating it, as the next section explains.

An envelope that is still not completed 30 days after it was sent voids itself the same way. See expiry.

Collect a payment with the document

An envelope can ask the signer for money. Add a payment object to the create call and the signer is sent a Siglio-hosted payment page, powered by Stripe, that pays you: the money lands in your own Stripe account, and Siglio takes nothing on top of Stripe’s card fees. Connect your Stripe account once, in the document studio: choose Connect Stripe; until that is done the field is refused with payment_not_configured.

"payment": {
  "amount": 15000,              // whole cents, so $150.00
  "description": "Deposit",     // optional, shown to the signer
  "when": "after"               // "after" (default) or "before"
}

After signing is the default: the document goes out exactly as it would without a payment, and the moment it is completed the signer is sent the payment link by the same channel the document went by. Before signing holds the document: the signer receives the payment link instead of the signing link, sees a read-only preview of what they are paying for, and the signing link goes out the moment the payment lands. A held envelope stays in state created, its signing_url is the payment page until it is paid, and it is not billed until the document actually goes out. Void it and it never is.

The envelope carries a payment object from then on, with status (pending, paid, waived when you marked it paid outside Stripe in the studio, or cancelled when a held envelope was voided), paid_at, and pay_url, which you can pass to the signer yourself. When the payment is recorded your webhook receives envelope.paid. USD only, and the signer who pays is signer one.

Ask the signer for files

An envelope can ask the signer to upload documents along with their signature: a photo of their ID, proof of insurance, a W-9, the last two pay stubs. Add an attachments object to the create call. The signer gets a Siglio-hosted upload page that works from a phone camera; they upload photos or PDFs, up to 15 MB each and up to three per item.

"attachments": {
  "when": "before",             // "before" or "after", no default
  "items": [
    { "label": "Photo ID" },
    { "label": "Proof of renter's insurance", "required": false }
  ]
}

Before signing holds the document exactly as a before-signing payment does: the signer receives the upload link instead of the signing link, sees the document read-only, and the signing link goes out once every required file is in. After signing sends the upload link the moment the document is completed. If the same envelope also has a payment at the same timing, one page and one message cover both, and a held document goes out only when both are done.

The envelope carries an attachments object from then on, with status (pending, received, waived when you skipped the files in the studio, or cancelled when a held envelope was voided), each item with its files, and upload_url. Download a file with GET /v1/envelopes/:id/attachments/:file. When every required file is in, your webhook receives envelope.attachments_received. Files are never emailed: they stay with the envelope until you fetch them.

You are billed on creation, not on completion

The charge is for creating the envelope, not for a completed signature. If the signer declines, ignores it, never opens it, or you void the envelope afterward, the envelope was still created and it still costs 25 cents.

This is not buried in the terms. It is how the product is priced, and it is why your first 25 documents are free. Use them to get the flow right, then send the envelopes you actually intend to send.

Not billable

A request that fails validation costs you nothing. Document checks, tag checks, and signer checks all run before the envelope is created, so a rejected request is never charged. See errors.

04Authentication

Authentication is a bearer token. Put your API key in the Authorization header:

Authorization: Bearer <your key>

No JWT assembly, no key pairs, no OAuth consent screen, no one-time authorization dance. One header.

Scopes

ScopeWhat it allows
readNon-mutating calls: envelope and status metadata, usage data exposed through the API, webhook delivery information.
read_writeEverything in read, plus the mutating calls. In V1 that means creating an envelope and voiding one.

Key lifecycle

There is one kind of key. It is sig_ followed by 32 characters, and it works from your first free document through every paid one; there is no test key to swap out later. You create, rotate, and revoke your own keys, and Key IDs begin with key_. You can hold up to 10 active keys, so different applications can use different keys.

Keys belong to the account, not to individuals. There are no teams, seats, or roles in V1, and keys carry no IP allowlist or per-key volume limit, so treat every key as fully capable within its scope and give each application its own.

Rotation gives you a 24-hour overlap. The replacement key is created and the old one stays valid for 24 hours, so you can deploy without a gap. If you would rather cut over immediately, revoke the old key at any point during that window and it stops working right away.

Keys come from your account, nowhere else

You create, rotate, and revoke keys yourself, in your account. Support can point you to the right screen, but no key is ever issued over email or chat, and none ever will be. If a message offers you one, it isn't from us.

05Free trial

Every account starts with 25 free documents. No card, no separate test mode: the same key and the same sends you will use in production.

  • The 25 are shared between the API and the document studio. A document sent from either counts once.
  • After 25, add a card and every envelope is 25 cents.
  • Adding a card early does not forfeit what is left. You keep sending free until all 25 are used.
  • Sending the studio’s sample document to yourself is free and does not count, up to 3 times.

The free documents are not a simulation

They perform real end-to-end delivery to real recipients. Send one to your own phone and it arrives as a real text. Send it to a colleague’s email and it lands in their inbox and they can actually sign it. There is no watermark, no demo stamp, and no fake-signer mode. When your integration works on a free document, you have seen the thing your users will see.

What happens at document 26

The 25 free documents are a one-time allowance per account. They do not refill, reset, or renew. Nothing about them is time-limited either: use 4 and come back six months later and the other 21 are still there.

Once they are used up, a send without a card is refused with payment_required (HTTP 402) and costs nothing. Add a card and your business details in the dashboard, in one step, and the next send goes through at 25 cents. Your key does not change.

Keys issued before October 2026 still work, and behave exactly like a sig_ key.

Resource ID prefixes

Every public ID starts with a prefix that says what it is.

PrefixResource
env_Envelope
acct_Account
req_API request. Send this when reporting a problem.
evt_Webhook event
key_API key
wh_Webhook endpoint

06Documents

RuleValue
Accepted formatPDF only
Maximum file size15 MB
Encrypted or password-protected PDFsRejected

You upload the finished PDF with every request. Documents cannot be pulled from a remote URL, and Word documents are not accepted, so generate the document on your side and send the bytes, or send a template you set up in the studio by its id. If your PDF is encrypted or carries an open password, remove the protection before upload. A protected PDF is rejected at creation rather than silently mishandled later.

Two ways to send the file

Inline, up to 3 MB. Base64-encode the PDF and send it as document_base64 in the create request. One call, done. Most generated contracts fit here comfortably.

Upload flow, up to 15 MB. For bigger files, get an upload URL first, put the file there, then create the envelope with the returned ID:

POSThttps://api.esigndev.com/v1/uploads

Authenticated with your normal API key, no body required. The response gives you a document ID beginning with doc_ and a signed upload_url. PUT the raw PDF bytes to that URL, then create the envelope with "document_id": "doc_..." instead of document_base64. Send exactly one of the two; both or neither is a 400.

Three rules that keep this flow honest: the upload URL expires in 15 minutes, a document ID is consumed by one envelope and cannot be reused, and uploaded originals are working input rather than storage, so they are swept about 24 hours after use. The size and PDF-only checks are enforced at the storage layer, so an oversized or mistyped file fails at the PUT, not later at creation.

Document rejections

All of these are checked before the envelope is created, so none of them are billable.

What happenedHTTPtypecode
File over 15 MB413invalid_documentfile_too_large
Not a PDF415unsupported_documentunsupported_file_type
Encrypted or password-protected PDF422invalid_documentencrypted_pdf
No ^S1 tag found422missing_required_tagmissing_required_signature_tag
Tags found for signer 3 or beyond422invalid_requestunsupported_signer_tag
PDF could not be parsed422invalid_documentunreadable_pdf

07Templates

Set a document up once in the document studio, then send it from code by its id. Siglio prints your values on it, places the signature and date marks, and sends it. No PDF in the request.

A template here is the same one you see in the studio, with the same id. Copy the id from the Templates list in the studio, or list your templates with the API. Any key can read them.

List your templates

GEThttps://api.esigndev.com/v1/templates

Newest first. limit is 1 to 100 and defaults to 25. When has_more is true, pass the last id you got as starting_after for the next page.

{
  "templates": [
    { "id": "tpl_example4471", "name": "Roofing agreement", "signer_count": 1, "pages": 2,
      "created_at": "2026-10-01T14:02:00Z", "updated_at": "2026-10-03T09:15:00Z" }
  ],
  "has_more": false
}

Retrieve a template

GEThttps://api.esigndev.com/v1/templates/:id

One template, with every value it prints and where each one comes from. An id that doesn’t exist, has been archived, or belongs to another account is a 404 template_not_found.

{
  "id": "tpl_example4471",
  "name": "Roofing agreement",
  "signer_count": 1,
  "pages": 2,
  "merge_fields": [
    { "name": "full_name", "label": "Full name", "signer": 1, "source": "signer", "from": ["name"] },
    { "name": "full_address", "label": "Full address", "signer": 1, "source": "signer",
      "from": ["address.line1", "address.line2", "address.city", "address.state", "address.zip"] },
    { "name": "policy_number", "label": "Policy number", "signer": 1, "source": "merge", "slot": 4, "max_length": 100 },
    { "name": "job_site", "label": "Job site", "signer": 1, "source": "merge", "slot": 5, "max_length": 100 },
    { "name": "today", "label": "Today's date", "signer": 1, "source": "auto" }
  ],
  "signing_fields": { "signature": [1], "initial": [], "date": [1] },
  "created_at": "2026-10-01T14:02:00Z",
  "updated_at": "2026-10-03T09:15:00Z"
}
FieldWhat it tells you
merge_fieldsEvery value the template prints, in page order. name is what you call it, label is what the sender sees in the studio, signer is 1 or 2.
sourcesigner: taken from that signer’s details, and from lists which ones, such as address.city. merge: you send it in merge. auto: Siglio fills it in.
slot, max_lengthFor a custom field, its slot (1 to 10, also accepted as custom_N) and the most characters it holds.
signing_fieldsWhich signers have a signature, initials and a date mark.
answer_fieldsPresent only when the template has boxes the signer fills in (Enterprise).

Send a template

Create the envelope as usual, with template_id in place of document_base64 or document_id. Send exactly one of the three.

curl -X POST https://api.esigndev.com/v1/envelopes \
  -H "Authorization: Bearer sig_..." \
  -H "Idempotency-Key: policy-PN-4471" \
  -H "Content-Type: application/json" \
  -d '{
    "template_id": "tpl_example4471",
    "signer": {
      "name":  "Jane Smith",
      "email": "jane@example.com",
      "phone": "+18135551212",
      "address": { "line1": "12 Bay St", "city": "Springfield", "state": "FL", "zip": "33609" }
    },
    "merge": { "policy_number": "PN-4471", "job_site": "Lot 9" }
  }'
  • Signer details. A signer takes name, email, phone, phone_other, company, job_title, address (line1, line2, city, state, zip, country), merge and delivery. Fields with source signer are filled from these. First and last name are split from name at the first space.
  • Your values. merge fills custom fields by name or by custom_N. Sending the same value both ways is fine; two different values is a 422 conflicting_merge_values. reference is a merge key when the template prints one. Names are case-insensitive. Each value is text or a number, up to 100 characters (reference: 60).
  • Two signers. Top-level merge is shorthand for signer 1. For signer 2, put merge on signers[1].
  • Missing values are a 422 missing_merge_fields that lists each one. Set "allow_blanks": true to send with them blank instead. It does not excuse characters the document cannot print.
  • document_name defaults to the template’s name. payment, attachments, sender and Idempotency-Key work as they do for any send. form_fields and constraints come from the template, so sending them with template_id is a 422.

Custom fields

Each signer can have up to ten custom fields, in slots 1 to 10. Name them in the studio with the Custom field tool: lowercase letters, digits and underscores, up to 40 characters, unique for that signer, and not one of Siglio’s own keys or custom_N. A field you don’t name is called custom_N and labelled “Custom Field N”.

Printed values use the Latin alphabet with accents. Cyrillic, Greek and Chinese, Japanese or Korean characters are refused with unsupported_characters. A template has one or two signers for now.

Template errors

All type invalid_request, all checked before anything is created, none billed. Where a code is about particular values, error.fields lists them.

HTTPcodeWhen
404template_not_foundNo template with that id on your account
422missing_merge_fieldsValues the template needs were not sent. fields: name, label, signer.
422unknown_merge_fieldA merge key the template doesn’t print for that signer. fields: name, signer.
422conflicting_merge_valuesThe same field sent by name and by custom_N with different values. fields: name, signer.
422invalid_merge_valueA value that isn’t text or a number, or is too long. fields: name, signer.
422unsupported_charactersA value with characters the document can’t print. fields: name, label, signer.
422signer_count_mismatchThe request has a different number of signers than the template
422template_not_readyA signer on the template has no signature mark. Fix it in the studio.
422 form_fields or constraints sent with a template
400 More than one of document_base64, document_id and template_id, or merge or allow_blanks without template_id

08Anchor tags

Siglio uses tagged-PDF signing. You place anchor tags in the document itself and Siglio finds them and puts the fields there. There is no drag-and-drop field editor and no coordinate-based placement API.

Tags do more than signatures. On Enterprise accounts, ^M, ^T, ^C and ^R collect typed answers, checkboxes and choices in the same document, so a signing envelope can also be a short form. On other accounts a document with any of them is refused with feature_not_enabled. Contact us to turn it on. See collecting answers.

The tags

Every tag ends in the signer number it belongs to, 1 or 2.

Signer 1Signer 2Field
^S1^S2Signature. ^S1 is required on every envelope.
^I1^I2Initial
^D1^D2Date. Fills itself. See below.
^M1^M2Text field, required. The signer cannot finish without filling it. Enterprise
^T1^T2Text field, optional Enterprise
^C1^C2Checkbox. A square the signer ticks. See below. Enterprise
^R1_G1^R2_G1Radio option, in group 1. See below. Enterprise

^S1 is mandatory. An envelope with no ^S1 anchor has nowhere to put a signature and will not be accepted. Signer 2 tags only mean anything on an envelope that actually has a second signer.

Use as many of each as the document needs. A five-page agreement can carry an initial tag on every page and a signature tag on the last one.

Text fields hold 500 characters

^M and ^T each accept a maximum of 500 characters. Worth knowing while you are laying out the document rather than after a signer runs into it: a field meant for an explanation holds about one short paragraph, not a page.

A text tag can carry a name: ^M1:policy_number (letters, digits and underscore, up to 40). The name is how you find the answer in field_values. Without one, fields are named text_1, text_2 and so on, in reading order across both signers.

Checkboxes, and values on checkboxes and radios

A checkbox tag carries a name: ^C1:has_license. Several ^C tags for the same signer with the same name, each with a value, form a group the signer can tick more than one of: ^C1:coverage=liability, ^C1:coverage=collision. A group has 2 to 50 boxes. Radio options take a value the same way: ^R1_G1:plan=monthly, ^R1_G1:plan=annual.

Values are letters, digits, underscore and hyphen, up to 40. A radio option without one is named option_1, option_2 and so on, in reading order within its group. An unnamed checkbox is check_1, check_2 and so on, and an unnamed radio group is choice_ plus its group number (choice_1 for _G1).

Where the X lands. A ^C or ^R tag marks the box: a 12 pt tag is a 12 by 12 point square whose bottom edge is the tag’s baseline and whose left edge is the tag’s left edge. Set the tag’s font size to the size of the box printed in your document (10 to 24 points), and the X is drawn inside it, two lines corner to corner. Nothing else is drawn. The box itself is yours.

Date fields fill themselves

^D1 and ^D2 are not something the signer types. The date is filled in automatically at signing.

The date used is the server’s date in US Eastern time, which observes daylight saving. It is not the signer’s local date.

The edge case worth knowing before it surprises you

A signer in Pacific time who signs after 9:00pm local gets the following day’s date stamped on the document. If the exact calendar date carries weight in your use case, plan around it. If it does not, this will never come up.

Radio groups

A radio group is defined by two things matching: the signer number and the _G value. Every anchor that shares both belongs to the same group, and the signer picks exactly one option from it.

So a three-way election for signer 1 is three separate anchors, all starting ^R1_G1, each placed over the box in front of one of the three choices in your document (set in white, like every tag). A second, independent question on the same page is ^R1_G2.

Choose one:

  ^R1_G1:term=monthly  Month to month
  ^R1_G1:term=six      Six month term
  ^R1_G1:term=twelve   Twelve month term

Autopay:

  ^R1_G2:autopay=yes   Yes
  ^R1_G2:autopay=no    No

Each signer gets up to nine groups, _G1 through _G9. There is no limit on how many options sit inside one group.

Making tags invisible

Place the tag text in white font on a white background. It is invisible to the person reading the document and still parseable when the envelope is created. That is the intended way to use it: your contract looks like a contract, and the anchors sit quietly in the text layer.

The two things that break tagging

The tag must be real text in the PDF text layer. A tag flattened into an image, or a PDF produced by scanning, has no text to find.

Template edits can move an anchor. If you generate documents from a template, check that your edits have not moved, split, or reflowed the anchor text. Anchor placement depends on the anchor surviving into the final file, and this is the most common cause of a field ending up in the wrong place.

Testing with visible tags

Leaving tags in black text for your first test documents is fine, and useful: you can see exactly where fields will land. Just expect the signed output to show the tag text underneath the filled values, because the anchors are part of the document. That overlap is your visible tag, not a rendering bug. Switch to white-on-white before anything real goes out.

A note on terminology

"Tagged PDF" here means anchor-string field placement, as described above. It does not mean PDF/UA structural accessibility tagging. Those are unrelated concepts that happen to share a name.

09Collecting answers Enterprise

Enterprise

Available on Enterprise accounts. Contact us to turn it on. What the signer and the studio see: data collection.

Before the signer signs, Siglio asks them for every answer on a short form, in document order: typed answers (^M required, ^T optional), dropdowns, checkboxes (^C) and choices (^R). Answers are saved as they type. The review shows each answer where it will print, and one Sign applies the signatures, dates and answers together.

Naming and labelling fields

Pass form_fields on create to give each field a label (what the signer reads), and to set rules:

"form_fields": [
  { "name": "policy_number", "label": "Policy number" },
  { "name": "phone", "label": "Mobile phone", "format": "phone" },
  { "name": "state", "type": "select", "label": "State",
    "options": [{ "value": "FL", "label": "Florida" }, { "value": "GA", "label": "Georgia" }] },
  { "name": "co_driver", "type": "checkbox", "label": "I have a co-driver" },
  { "name": "licence", "signer": 2, "label": "Co-driver's licence number",
    "show_if": { "field": "co_driver", "checked": true } }
]

Here policy_number, phone and state are ^M or ^T tags, co_driver is a ^C1:co_driver tag, and licence is a ^M2:licence tag.

  • name (required): matches a tag’s name.
  • signer: optional, but if given it must match the tag.
  • type: text (the default on a ^M or ^T tag), select (a ^M or ^T tag that shows a pick-one list; the chosen option’s label is what prints), checkbox (one ^C tag), checkbox_group (several ^C tags sharing a name, each with a value), radio (an ^R group). The type has to match the tag. A mismatch is refused, naming the tag.
  • options: for select, checkbox_group and radio: [{ "value": "FL", "label": "Florida" }]. For a group or a radio, every value must match a box on the page, and the page’s words to the right of each box are used when no label is given. A select has 2 to 100 options and takes its options from this list alone.
  • format: on a text field, email, phone, number, date, zip or ssn. Checked as the signer types, with a plain message. Stored in one shape each (phone as 10 digits, date as YYYY-MM-DD, ssn as 123-45-6789), printed as (813) 555-0142 and 3/14/2026. The API returns the stored value in full with format beside it.
  • label: up to 80 characters. Without it, Siglio uses the words just before the tag on the page, else the name.
  • required: overrides the tag’s own ^M (required) or ^T (optional).
  • max_length: 1 to 500, on text fields.
  • width: 60 to 540 points, on text and select fields.
  • show_if / required_if: { "field": "<name>", ... } with exactly one of equals (a value), not_empty (true), in (a list of up to 50 values), checked (true or false, on a checkbox) or includes (a value, on a checkbox group). Combine two to ten with { "all": [...] } or { "any": [...] }, one level deep. Comparisons ignore case and extra spaces. A radio or select compares by value. A group matches equals or in when any ticked value does.

Up to 100 entries.

How rules behave

  • A rule can use the same signer’s fields, or signer 1’s fields from signer 2.
  • A hidden field is skipped, never required, and stored blank.
  • Rules can’t loop.
  • Every rule is checked again when the signer signs.

Group rules

constraints, next to form_fields on create, holds rules across fields:

"constraints": [
  { "type": "exactly_one", "fields": ["status"] },
  { "type": "at_least", "n": 1, "fields": ["has_license", "newsletter"] },
  { "type": "at_most",  "n": 2, "fields": ["plan", "paper_copy", "extras"] },
  { "type": "one_of",   "fields": ["ssn", "no_ssn_reason"] },
  { "type": "requires", "field": "address", "when": { "field": "plan", "equals": "annual" } }
]
  • fields lists 1 to 20 of one signer’s fields. A lone field is allowed only when it is a checkbox group: exactly_one over the group means tick exactly one of its boxes.
  • Counting: a ticked checkbox is 1, a group counts its ticked boxes, a radio or text with an answer is 1. A hidden field counts 0.
  • one_of: filling one field clears and greys out the others.
  • requires is a required_if by another name. when takes any condition.
  • Up to 50 constraints. A bad one is refused with 422 invalid_constraints, naming the entry.

The signer sees each rule in plain words built from your labels (“Choose one of: Single, Married, Divorced.”), as they tap and again if they try to sign with one unmet. They can’t sign until every rule is met.

Answers are printed on the document

Each answer prints from the tag’s left edge, on its line, at 11 pt, shrinking to 8 pt and then wrapping to a second line. An answer must fit its space. The space runs 200 points wide by default (or width), and stops at the next tag on the same line or the right margin.

A ticked checkbox or a chosen option prints as an X in its box. A dropdown prints the chosen option’s label.

Answers are printed in a font that covers Latin, Greek, Cyrillic and Vietnamese. Other scripts (for example Chinese, Arabic, Hebrew or emoji) are refused as the signer types, with a plain message.

Signer 2 sees signer 1’s answers on the document they review. Plan forms with that in mind.

Reading answers

field_values appears on GET /v1/envelopes/{id} and on every webhook, only for envelopes with answer fields:

"field_values": [
  { "name": "status",      "signer": 1, "label": "Marital status", "type": "checkbox_group", "value": ["married"], "submitted_at": "..." },
  { "name": "has_license", "signer": 1, "label": "Current licence", "type": "checkbox", "value": true, "submitted_at": "..." },
  { "name": "plan",        "signer": 1, "label": "Billing", "type": "radio", "value": "annual", "submitted_at": "..." },
  { "name": "phone",       "signer": 1, "label": "Phone", "type": "text", "format": "phone", "value": "8135550142", "submitted_at": "..." }
]
  • A text, select or radio is a string or null. A checkbox is true or false. A group is a list, empty when nothing was ticked.
  • value is null until that signer has signed.
  • envelope.partially_signed carries signer 1’s answers, and envelope.completed carries everyone’s.
  • Answers are deleted 30 days after the envelope closes. After that, value is null and "deleted": true appears.
  • GET /v1/envelopes/{id} also returns form: { fields, constraints }, the definitions and rules the envelope was created with, so an integration can rebuild the form it sent.

Answers are personal data

They arrive in your webhooks and API responses. Store and protect them like any other customer data.

The certificate lists which fields each signer completed and a fingerprint of the answers. It never shows the values. A ticked box or a choice counts as answered.

10Signers

An envelope supports a maximum of two signers. Signer 1 is required, signer 2 is optional. Three or more signers is not supported.

Supplying more than two signers, or tagging for signer 3 and beyond, is rejected at creation and is not billed.

Sending two signers

One signer sends as a signer object. Two signers send as a signers array, in signing order:

"signers": [
  { "name": "Jane Smith",  "email": "jane@example.com" },
  { "name": "Sam Carter",  "phone": "+18135551212", "delivery": "sms" }
]

Send signer or signers, never both. Each signer can carry its own delivery; leave it off and the envelope’s delivery applies (on auto, each signer is resolved from their own details). The create response returns a signers array with a separate signing_url for each signer, minted up front even though notifications go out one at a time.

The partially signed state

A two-signer envelope passes through one extra state. When signer 1 finishes, the envelope moves to partially_signed and an envelope.partially_signed webhook event fires, so your system knows exactly where a document stands while it waits on the second signature. Sequential signings can span days; this state is how you see that without polling.

Only completed means both signatures are on the document. Never treat partially_signed as done: the signed PDF at that point is half-executed, and the final document only exists once the envelope completes.

Signing is sequential: signer 1, then signer 2.

On a two-signer envelope, signer 2 is not notified until signer 1 has signed, and cannot sign before then either. Signer 2’s signing_url is minted with the envelope and returned in the create response, but until signer 1 has signed it opens on a page saying the document is waiting on the first signer. The order holds even if you hand the link out yourself.

One exception, for now. When a signer’s name is written in a non-Latin script, notification is still sequential but signer 2’s signing_url works from creation. On those envelopes, if one party must sign strictly before the other, keep signer 2’s link to yourself until envelope.partially_signed fires.

You choose which signer goes first, per envelope. An agreement that needs your side to sign before it reaches the customer works the same way as one that needs the customer first.

Design for this. If your integration assumes both signers are notified at creation, it will not behave the way you expect.

Each signer gets the signed PDF

When the envelope completes, every signer is sent the signed PDF, certificate page included: attached to an email when they were reached by email, and by text with a download link when they were reached by text. You do not need to send it yourself. Your copy still comes from GET /v1/envelopes/:id/document when envelope.completed fires.

Tagging for two signers means sending two signers

If your document carries signer-2 tags (^S2, ^M2, and so on) but you create the envelope with only one signer, the request is rejected with an error naming the mismatch.

It is not sent as a one-signer document. That would leave the second signer’s fields on the page with nobody able to fill them, and you would not find out until someone read the finished PDF. A rejection at creation is the cheaper failure, and it is not billed.

11Delivery

You choose how the signing link reaches your signer, at creation time:

  • Auto, the default: email and text when the signer has both an email and a phone, otherwise whichever one they have
  • Email
  • SMS
  • Both, at the same time
  • None: you hand out the link yourself and Siglio contacts nobody (below)

Leave delivery out and you get auto. Send an email and a phone and the signer gets both; send only one and that one is used. email, sms and both stay strict: ask for both without a phone and the call is refused, so you find out rather than silently losing the text. The create response, GET and every webhook carry the resolved value (email, sms, both or none), never auto; with two signers, each entry in signers has its own delivery.

Both means both, at the same time, to the same signer. It is not a fallback after email bounces, and it is not a paid add-on. SMS delivery is included in the 25 cents.

This matters if your signers are contractors, tenants, patients, field staff, or anyone who does not sit in an inbox all day. The link that arrives by text gets opened.

Nothing about this is configured at the account level. You choose fresh on every envelope, so email for one and both channels for the next takes no setup and no support ticket.

On two signers, the choice is per signer

Each signer’s delivery channel is chosen independently. Signer 1 by text and signer 2 by email is a supported combination, as is any other pairing, including both channels for one and a single channel for the other.

This is the answer to a case that comes up constantly: the contractor you only have a mobile number for, and the office manager you only have an email address for, on the same agreement. You do not have to find a channel that works for both of them.

This is about who gets contacted and how. It does not change who is notified when: with two signers, signer 2 is not notified until signer 1 has finished. See signers.

Send "delivery": "none" when your own app shows the signing link: in your portal, in a chat, on a screen in front of the signer. Siglio sends no request, no reminder and no signed copy to the signer, by email or text. Everything else works as usual: the envelope, its states, the webhooks and the signed PDF you download.

{
  "document_name": "Service agreement",
  "document_base64": "JVBERi0xLjcK...",
  "delivery": "none",
  "signer": { "name": "Dana Reyes", "email": "dana@example.com" }
}
  • The links come back in the response. A none envelope always has a signers array in the create response, each entry with its own signing_url. Signer one’s link is also signing_url on the envelope, on every GET.
  • Each signer still needs an email or a phone. Nobody is contacted at it; it is recorded on the signing certificate.
  • It is for the whole envelope. With two signers, set it at the top level. One signer on none and the other on a channel is refused. Signing is still in order: signer two’s link shows a waiting page until signer one has signed, and envelope.partially_signed is your cue to hand it over.
  • No payment or attachments. Both need a channel to send their link on, so either one with none is a 400.
  • Reminders are skipped; expiry is not. An unsigned none envelope is still voided after 30 days.
  • The certificate says so. It records the delivery as “Link provided by sender”, the signer’s email or phone as not contacted by Siglio, and claims no channel authentication.
  • A document that only the older signing page can handle, for example one with a signer name in a non-Latin script, can’t go link-only: 422 unsupported_for_link_only, not billed. Send it with a channel instead.

The price is the same 25 cents. none works with templates too.

Automatic reminders

A signer who has not signed is reminded automatically, on the same channels they were sent the document on. Reminders go out on days 1, 2, 3, 5, 7, 10, 14 and 21 after that signer was asked, then a last reminder on day 28 that states the expiry date: nine at most. Signer 2’s schedule starts when signer 1 signs.

Reminders are sent only between 11:00 and 19:00 US Eastern, and text reminders end with “Reply STOP to opt out.” They are on by default for every account and have no webhook events of their own. There is no API parameter to turn them off; contact support to turn reminders off for your account.

Expiry after 30 days

An envelope that is not completed 30 days after it was sent is voided automatically. It moves to voided and envelope.voided fires, exactly as for a void you make yourself. There is no separate reason field: voided means either you voided it or it expired unsigned after 30 days. Its signing links then show that the document is no longer available.

Reminders and expiry apply to envelopes created from 28 September 2026 on.

12Idempotency

Envelope creation accepts an idempotency key. Send the same key with the same request and you get the original result back instead of a second envelope.

Use it

Envelope creation is the billed operation. A retry on a network timeout without an idempotency key is how you accidentally create and pay for two envelopes.

You generate the key yourself and send it in the Idempotency-Key header. Any unique string up to 255 characters works. Use something derived from your own record, like order-41882-contract-1.

Idempotency-Key: order-41882-contract-1

Records are kept for 30 days, so a retry days later still resolves correctly rather than creating a second billable envelope.

The pattern

Generate one key per logical envelope in your own system, store it alongside your record, and reuse it on every retry of that same envelope.

Reusing a key with a different body is an error

It is not a silent overwrite. You get a 422 with type: invalid_request and code: idempotency_key_reuse. That is deliberate: it catches the bug where a key gets recycled across two genuinely different envelopes, which would otherwise mean the second one silently never gets sent.

13Webhooks

Webhooks are included on every account. They are not a paid tier, not an add-on, and not gated by volume. Every account, from the first free document.

Configuration

EndpointsOne per account
Event typesAll of them. There are no per-event subscriptions.
Webhook IDswh_...
Event IDsevt_...

You configure one endpoint for your account and receive every event type on it. Filter by event type in your handler.

Setting one up

Endpoints are managed in your dashboard, under Webhook endpoints. Paste an HTTPS URL, save, and the signing secret is shown to you once. Send test posts a real signed webhook.test event to your handler so you can prove both your route and your signature check work before a real envelope depends on them.

If an endpoint fails for long enough to be marked failed, delivery to it stops entirely. Fix the URL and save again from the dashboard to switch it back on.

Verifying a delivery

Every request we send carries an X-Siglio-Signature header. Verify it and reject anything that does not match, otherwise anyone who learns your endpoint URL can post you a fake completion event.

X-Siglio-Signature: t=1756645701,v1=1f8b...c3d9

t is the Unix timestamp we signed at. v1 is the HMAC-SHA256 of the string t, a literal full stop, and the raw request body, keyed with your signing secret. Sign the bytes you received, not a re-serialized object: re-encoding JSON changes whitespace and key order, and the signature will not match.

// Express. Note express.raw, not express.json.
const crypto = require("crypto");

app.post("/webhooks/siglio", express.raw({ type: "application/json" }), (req, res) => {
  const header = req.get("X-Siglio-Signature") || "";
  const m = header.match(/^t=(\d+),v1=([0-9a-f]+)$/);
  if (!m) return res.status(400).end();

  const expected = crypto
    .createHmac("sha256", process.env.SIGLIO_WEBHOOK_SECRET)
    .update(m[1] + "." + req.body)
    .digest("hex");

  // Constant time, so a wrong signature cannot be guessed a byte at a time.
  const ok = m[2].length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(m[2]), Buffer.from(expected));
  if (!ok) return res.status(401).end();

  // Reject anything older than five minutes: a valid signature stays valid
  // forever, so the timestamp is what stops an old request being replayed.
  if (Math.abs(Date.now() / 1000 - Number(m[1])) > 300) return res.status(400).end();

  const event = JSON.parse(req.body);
  // Acknowledge first, work afterwards.
  res.status(200).end();
  queue.add(event);
});

Rotating the secret in the dashboard takes effect on the next delivery, so update your handler first, then rotate.

Event types

EventFires when
envelope.deliveredThe envelope is created and handed to delivery
envelope.viewedA signer opens the document
envelope.partially_signedSigner 1 of 2 has finished. Two-signer envelopes only.
envelope.completedEvery signature is on the document. This is your cue to download it.
envelope.voidedThe envelope was voided: by you, from the studio, or automatically because it was not completed 30 days after it was sent.
envelope.paidA requested payment was recorded (paid, or waived by the sender). The envelope in the payload carries payment.
envelope.attachments_receivedThe signer uploaded every required file. The envelope in the payload carries attachments with the file ids.

Events fire on state transitions, not on raw signing activity, so you never receive the same event twice for one envelope and you never receive them out of order relative to the envelope’s state. Switch on the type field.

Retries

Failed deliveries are retried on an exponential backoff with jitter: immediately, then at roughly 1 minute, 5 minutes, 15 minutes, 1 hour, 3 hours, 6 hours, 12 hours, then once every 24 hours, stopping after 7 days. Any 2xx response counts as success.

Every attempt is recorded with its HTTP status and response body, and the full delivery history is visible in the portal. An endpoint that fails every attempt for 7 days is marked failed and retries stop.

Not every failure is treated the same

Your responseWhat we doWhy
408, 429, any 5xxFull seven-day retry scheduleThese usually resolve on their own
401, 403, 404, 410Three attempts, then marked failedYour endpoint is rejecting us, not struggling. A week of retries will not fix a deleted route or a bad auth rule.

You hear about it early

After three consecutive delivery failures on an endpoint, Siglio emails your technical-alert address. You do not have to wait for the retry window to exhaust itself to find out something is broken, and you do not have to poll the delivery history to notice.

Handler expectations

Return a 2xx quickly and do your work asynchronously. A handler that takes a long time to respond looks like a failing endpoint, and will be treated as one.

There is no manual replay. Once you return a 2xx, that event is delivered and will not be sent again. Acknowledge first and process from your own durable queue, so a crash after the 2xx costs you a retry rather than the event.

14Signed documents

Read this before you build

Siglio deletes an envelope’s files 30 days after it closes. Download the signed PDF, and any files the signer uploaded, when the completion webhook fires, and keep your own copy. That is not a suggestion, it is the integration requirement.

The arrangement, stated plainly because it affects how you build:

  • Signers are sent their copy when the envelope completes, with a download link that works for 30 days.
  • You, the developer, receive the signed result through the completion webhook.

Downloading the signed PDF

GEThttps://api.esigndev.com/v1/envelopes/{id}/document

Available once the envelope is completed; before that it answers not-found, and 30 days after completion it answers 410 with code document_deleted. The response streams the PDF bytes directly, no redirect to follow. Call it from your completion-webhook handler and write the file to your own storage.

What is kept, and for how long

While an envelope is in progress, Siglio keeps its files. Thirty days after the envelope reaches completed, voided (including expiry) or failed, its files are deleted: the PDF you uploaded, the signed PDF, and any files the signer uploaded.

The envelope record stays readable through GET /v1/envelopes/{id}: its state, signers, timestamps, and the payment and attachments metadata. Once the files are gone, GET /v1/envelopes/{id}/document and the attachment download both return 410 with code document_deleted.

The signer’s own download link, sent with their copy, works for the same 30 days.

The pattern, stated plainly: on envelope.completed, download the signed PDF (and any attachments) and store them in your system. The copy you keep is the one you will still have in three years, and it is the one your own retention obligations run against.

15Errors

Every API response carries a request ID (req_...), in the response body on errors and in a response header on every request, successful or not. Log it.

Error shape

{
  "error": {
    "type":       "invalid_document",
    "code":       "missing_required_signature_tag",
    "message":    "The PDF must include a ^S1 signature tag.",
    "request_id": "req_01ABC..."
  }
}

How to handle these

Switch on type, log code, never parse message. type is the broad class and is stable. code is the specific reason and new ones may be added over time. message is written for a human reading a log and its wording may change.

Error types

typeHTTPWhen
authentication_error401Missing, malformed, revoked or expired key
authorization_error403Valid key, but this call is not allowed: wrong scope, a feature the account doesn’t have, or sending paused while the company name is reviewed
invalid_request400Malformed request, bad or missing parameters
invalid_document422PDF present but unusable
unsupported_document415Not a supported file type
missing_required_tag422Required signing tag absent
invalid_signer422Signer details missing or unusable for the chosen delivery method
new_envelopes_paused403Pause New Envelopes is on
account_paused403Account fully paused
usage_limit_reached403Approved monthly limit ceiling hit
self_imposed_cap_reached403Your own cap hit. Hard stop, no grace.
payment_required402Your 25 free documents are used and there is no card on file
rate_limited429The limit is 120 requests per minute per API key, across all endpoints. The Retry-After header says how many seconds until the window resets.
service_unavailable503Temporary. Safe to retry with your idempotency key.
internal_error500Our fault. Send us the request_id. If it happens while an envelope is being created, nothing is billed: the envelope is marked failed and a free document is given back.

One code arrives with a different status: document_deleted comes back as HTTP 410 (type invalid_request) from the signed PDF and attachment downloads once the envelope’s files have been deleted, 30 days after it closed. See signed documents.

Account errors on a send

These come back from POST /v1/envelopes before anything is created. None of them is billed. The message is the exact text you will see, and it says what to do.

HTTPtype / codeMessage
402payment_required / payment_requiredYour 25 free documents are used. Add a card to keep sending.
422invalid_request / company_name_requiredYour account has no company name yet. Recipients see it as the sender. Add it in your dashboard at https://esigndev.com/app and send again.
403authorization_error / account_under_reviewYour company name is being reviewed, so sending is paused for now. Contact support at https://esigndev.com/contact and we will sort it out.
422invalid_request / invalid_requestYour free trial is over, so your business profile must be complete. Missing: … (the fields are named)
422invalid_request / email_unverifiedConfirm your email address before sending billed envelopes: …

A sender.company_name on the request satisfies company_name_required for that envelope. A request that still sends environment is accepted and the field is ignored.

Features switched off on the service

Now and then we switch a feature off across the service while we fix something. A request that uses it is refused with its own code rather than a vague error, so you can tell which part to leave out. All HTTP 422, type invalid_request, not billed, nothing created.

codeWhat to do
link_only_disabledSend with email, sms or both delivery instead of none
sender_branding_disabledLeave sender out; your account’s company name is used
payments_disabledLeave payment out to send for signature only
attachments_disabledLeave attachments out to send for signature only
two_signer_disabledSend one signer per envelope

Template sends have their own codes, such as template_not_found and missing_merge_fields. See template errors.

feature_not_enabled (HTTP 403, type authorization_error): the document has ^M, ^T, ^C or ^R tags, or the request has form_fields, and the account doesn’t have data collection. Message: “Collecting answers before signing (^M, ^T, ^C or ^R tags, or form_fields) is an Enterprise feature. Contact us to turn it on.” Not billed, nothing created. See collecting answers.

invalid_form_fields and invalid_constraints (HTTP 422, type invalid_request): an entry in form_fields or constraints doesn’t fit the document. For example a name with no matching tag, a type that doesn’t match its tag, a group rule that names a missing field or mixes two signers’ fields, or an n out of range. The message names the entry (constraints[2] ...).

Is it you or is it us?

If calls are failing and the error does not tell you why, check esigndev.com/status. It reports each part of the service separately — the API, sending for signature, the signing pages and webhook delivery — and it is measured every five minutes, so it will not tell you everything is fine while nothing has been checked for an hour.

Which errors cost you money

None of the 4xx classes above. They mean the request did not create an envelope and was not billed.

A 500 or 503 is the ambiguous case, and that is exactly what idempotency keys are for. Retry with the same key and you get either the original result or a fresh attempt, never a double charge.

Common causes of a rejected creation

  • The document is not a PDF, is over 15 MB, or is encrypted
  • The document has no ^S1 anchor
  • More than two signers were supplied
  • The document carries signer-2 tags but only one signer was supplied
  • The document has ^M, ^T, ^C or ^R tags, or the request has form_fields, on an account without data collection (Enterprise)
  • form_fields or constraints don’t match the document’s tags
  • The account has no company name yet, or its free documents are used and there is no card
  • The account is at a hard stop on its limit, or paused
  • The bearer token is missing, malformed, or revoked

16Limits

Every account has an approved monthly envelope limit. There is no arbitrary default. When you activate paid usage you declare your estimated monthly envelope volume, and that estimate becomes your initial approved limit.

Self-service increases go up to 10,000 envelopes per month. You can raise your own limit in the portal at any time up to that ceiling. Above 10,000, the request goes to a person.

Approaching and passing the limit

PointBehavior
90% of limitWarning, with a 24-hour cure window to raise the limit or reduce sending
100% of limitSending continues. You are not cut off at exactly 100%.
110% of limitHard stop. Envelope creation is refused.

The 10% band exists so a busy Friday does not break your integration. It is headroom, not an allowance to plan against.

Self-imposed cap

You can set your own cap below your approved limit. A self-imposed cap is a hard stop, not a warning. When you hit it, envelope creation stops, and there is no 110% band above it.

This is the control to use if you want a guaranteed ceiling on spend, for example while a new integration runs unattended for the first time.

17Pause controls

The portal has three controls, all self-service and all immediate: Pause New Envelopes, Pause Account, and Unpause Account. They are independent of your self-imposed monthly cap.

Pause New Envelopes is the lighter one. It blocks new envelope creation while leaving the read API, existing envelopes, webhook delivery and billing all working normally.

What a full pause does

A full pause, whether you triggered it or it followed a payment default, behaves the same way. No new envelopes can be created. Envelopes already in flight stay live and their recipients can still sign them.

Pause suppresses delivery, not capture

Outbound webhook delivery to your endpoint stops, but Siglio keeps capturing every signing event and queues it durably. When the account unpauses, the missed events replay to your endpoint in chronological order, with their original event IDs and original occurrence timestamps. You lose nothing.

Support will not pause or unpause an account on a customer's behalf.

18Pricing

$0.25 per envelope. Flat. Every envelope, at every volume.

There are no volume tiers, no negotiated rates, and no annual commitment. 25 cents at ten envelopes a month, 25 cents at a hundred thousand.

There is no monthly fee at any volume. A month where you send nothing costs nothing. There are no seats and no per-user pricing. Billing is per envelope only. There is no contract and no minimum commitment.

SMS delivery is included. Webhooks are included. The first 25 documents are free and need no card.

19Billing cycle

Billing runs on a monthly anniversary cycle. Your cycle starts the day you activate paid billing and repeats on that same day each calendar month. Activate on March 14 and you are invoiced on the 14th of every month.

If your anniversary falls on a day a month does not have, the cycle bills on the closest last day of that month. A January 31 activation bills February 28, then March 31.

Cards

You keep a primary card and a backup card. If the primary fails, the backup is charged.

If both cards fail

StepWhat happens
1A 5-day cure period starts
2Daily reminders during those 5 days
3If payment has not succeeded by the end of the cure period, the account is fully paused

A full pause means the account stops. Fix the payment method to restore it. See pause controls for exactly what a pause does and does not affect.

Support cannot change a payment method on your behalf, and cannot issue a credit or a refund. Both are handled by a person.

20Getting help

Real questions get real answers from someone who knows the product, usually the same day.

If your question is about a specific API call, send the req_ ID. It is the fastest path to an actual answer, and it is the difference between a diagnosis and a conversation.

Open a support request

What support will not do

  • Create, rotate, or revoke an API key for you
  • Change a payment method on your behalf
  • Issue a credit or a refund (a person handles those)
  • Pause or unpause your account for you
  • Advise on whether a given signature is enforceable, whether a document type is eligible for electronic signature, or how e-signature law applies to your situation. That is a question for your counsel.