SignEnvoy docs

Templates

A template is a PDF with roles ("Client", "Manager") and fields placed once. Using it starts a normal signature request: you name the real people for each role, optionally prefill fields, and the document goes out like any other. The dashboard's visual editor and POST /v1/templates write the same definition, so what you build in one you can read, diff, and push from the other.

Create one

In the dashboard: Templates, New template, upload the PDF, then place fields on the page (drag, or keyboard: arrow keys move a selected field by 0.5% of the page, Shift by 2%, Alt resizes). Every field belongs to a role; a template with an unassigned field cannot be saved, and the error names the field and page.

Over the API, the PDF travels base64-encoded and the definition is JSON:

curl -s -X POST https://signenvoystaging.fly.dev/v1/templates \
  -H "Authorization: Bearer $SENV_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Consulting agreement",
    "pdf_base64": "JVBERi0xLjQK...",
    "recipients": [
      {"name": "Client", "email": "client@placeholders.example", "role": "signer", "signing_order": 1},
      {"name": "Manager", "email": "manager@placeholders.example", "role": "approver", "signing_order": 2}
    ],
    "fields": [
      {"type": "signature", "recipient_index": 0, "page": 1, "x": 0.1, "y": 0.75, "w": 0.3, "h": 0.05, "name": "client_sig"},
      {"type": "text", "recipient_index": 1, "page": 2, "x": 0.1, "y": 0.2, "w": 0.3, "h": 0.03,
       "name": "po_number", "required": false, "settings": {"max_length": 20}}
    ]
  }'
{
  "id": "tpl_...",
  "name": "Consulting agreement",
  "version": 1,
  "updated_at": null,
  "recipients": [...],
  "fields": [...],
  "sha256": "..."
}

recipients are placeholder identities, bound by position: the first real recipient you pass at use time becomes role 0, the second role 1, and so on. Their role and signing order come from the template. The placeholder email is never mailed.

Fields

Use one

curl -s -X POST https://signenvoystaging.fly.dev/v1/templates/tpl_.../use \
  -H "Authorization: Bearer $SENV_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Consulting agreement: Acme",
    "recipients": [
      {"name": "Ada Lovelace", "email": "ada@acme.example"},
      {"name": "Bob Byrne", "email": "bob@acme.example"}
    ],
    "form_values": {"po_number": "PO-88213"},
    "display_timezone": "Europe/London"
  }'

The response is a draft document (doc_..., status draft) with the template's fields copied in. Send it with POST /v1/documents/{id}/send.

form_values keys resolve by field name first, then by field index as a string ("0", "1", in the template's field order). An unknown key fails the whole request:

HTTP/1.1 422 Unprocessable Content
Content-Type: application/problem+json

{
  "type": "https://docs.signenvoy.com/errors/validation-failed",
  "title": "Validation failed",
  "status": 422,
  "detail": "form_values: unknown field key(s) 'po_numbre'",
  "docs_url": "https://docs.signenvoy.com/errors/validation-failed"
}

Silently dropping a prefill would be the worst outcome (a document goes out with a blank where a value was meant to be), so a typo is refused rather than ignored. See validation-failed.

display_timezone, date_format, and redirect_url on the use request set the document's display preferences. Leave them out and the workspace's team defaults apply, the same as for any other new document.

Change one: versions

curl -s -X PATCH https://signenvoystaging.fly.dev/v1/templates/tpl_... \
  -H "Authorization: Bearer $SENV_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"fields": [ ... the full field list ... ]}'

PATCH replaces the parts you send (name, recipients, fields) and bumps version; updated_at moves with it. Documents already created from the template carry their own copy of the definition and are unaffected. The next use takes the new version. The dashboard says the same thing on every save.

Templates as code

GET /v1/templates/{id} returns the complete definition, fields and recipients included, exactly as stored. The dashboard editor reads and writes the same shape: a field placed in the editor and a field pushed over the API are the same field, and a setting the editor cannot display is kept rather than dropped.

From senv 0.2.0, senv template pull <id> writes that definition to a file and senv template push sends it back as a PATCH (a new version); senv template use <id> --var po_number=PO-88213 prefills by name. Until then the same round trip is the two API calls above.

Who can use templates

Personal workspaces have a template library and the editor in the dashboard but no API. Pro workspaces share templates across the team: every member sees the team's templates, and GET /v1/templates lists them.