---
title: "Create and send a multi-document envelope"
method: POST
path: "/api/v1/firme/envelopes"
tags: ["Signatures (app routes)"]
---

# Create and send a multi-document envelope

`POST /api/v1/firme/envelopes`

## Request

- Base URL: `https://api.custodo.ai`
- URL: `https://api.custodo.ai/api/v1/firme/envelopes`
- Auth: HTTP bearer

One request creates the envelope and queues preparation and delivery (send defaults to true). Accepts 1–20 documents, 50 MB each and 100 MB total; use contentBase64 for a single call (8 MiB of base64 per file, 16 MiB JSON request), or sourceSha256 from POST /source, or documentId from the Archive. Poll GET /envelopes/{id}: preparation moves queued → ready or failed; invitations only leave after successful preparation. format auto chooses CAdES when ANY file is not PDF. Explicit pades then returns 400; cades also works for PDFs and produces attached .p7m containers. CAdES needs the configured digest seal provider. Recipients default to role=signer and must list every envelope document key in documents. Every signer signs every file; partial assignments and sign:false return 400. Omit sign or use true. Existing envelopes retain their original assignments. Add role=cc for an informed recipient: omit documents (or []), keep otp=none and timestamp=false. They receive a read-only link on dispatch and a completed copy on the selected delivery channel; sendCopy is always enabled for cc. They cannot sign or decline, do not consume timestamps and do not block sequential routing or completion. At least one signer is required. PDF boxes use bottom-left PDF points, pages from 1: coordinates, default bottom-right last page, or tag (case-sensitive PDF text layer, occurrence from 1 and x/y offsets). Missing tags and out-of-page boxes fail preparation. Saved templates and custom signature images are not accepted. Each visible signature reads Digitally signed by followed by the signer name. Each signer chooses delivery=email|whatsapp and otp=none|email|whatsapp, independent of delivery. Select mailAccountId and whatsappAccountId to choose the sending account. Insufficient timestamp credits return 409 LIMIT_REACHED on creation; balances are rechecked at signing. timestamp=true applies one RFC3161 timestamp per envelope file and consumes included units first, then purchased units. PAdES adds a document timestamp immediately after the signer’s revision; CAdES timestamps the new CMS signature before co-signing. The web composer places boxes by dragging; the API additionally supports default and tag placement. API keys prepare and send; they never supply a person’s consent.

## Headers

- `X-Tenant-Id` string, uuid
- `Idempotency-Key` string

## Request body

- object
  - `title` string, required
  - `message` string
  - `format` 'auto' | 'pades' | 'cades'
  - `routing` 'sequential' | 'parallel'
  - `archiveOnComplete` boolean
  - `mailAccountId` string, uuid
  - `whatsappAccountId` string, uuid
  - `send` boolean
  - `documents` object[], required
    - `key` string, required
    - `filename` string, required
    - `sourceSha256` string
    - `documentId` string, uuid
    - `contentBase64` string
    - `contentType` string
    - `sign` true
  - `signers` object[], required
    - `role` 'signer' | 'cc'
    - `name` string, required
    - `email` string, email
    - `whatsapp` string
    - `delivery` 'email' | 'whatsapp'
    - `otp` 'none' | 'email' | 'whatsapp'
    - `timestamp` boolean
    - `sendCopy` boolean
    - `documents` object[]
      - `key` string, required
      - `placement` union
        - object
          - `page` integer, required
          - `x` number, required
          - `y` number, required
          - `w` number, required
          - `h` number, required
          - `mode` 'coordinates', required
        - object
          - `mode` 'default', required
          - `w` number
          - `h` number
        - object
          - `mode` 'tag', required
          - `tag` string, required
          - `occurrence` integer
          - `w` number
          - `h` number
          - `offsetX` number
          - `offsetY` number

## Response `200`

Idempotent replay.

- object
  - `ok` true, required
  - `data` FirmeBundle, required
    - `hasCertificate` boolean
    - `certificateDocumentId` string, nullable: A UUID.
    - `id` string, required: A UUID.
    - `documentId` string, nullable, required: A UUID.
    - `title` string, required
    - `message` string, nullable, required
    - `level` 'ses', required
    - `status` 'draft' | 'sent' | 'partially_signed' | 'completed' | 'declined' | 'expired' | 'voided', required
    - `routing` 'sequential' | 'parallel', required
    - `source` object, required
      - `filename` string, required
      - `sizeBytes` number, required
      - `contentType` string, required
    - `bundle` boolean, required
    - `format` 'pades' | 'cades', required
    - `preparation` 'queued' | 'ready' | 'failed', required
    - `preparationError` string, nullable, required
    - `hasSignedArtifact` boolean, required: True once the first signature is on the PDF.
    - `validation` object, nullable, required: The ETSI verdict on the completed PDF: TOTAL_PASSED, INDETERMINATE, TOTAL_FAILED.
      - `indication` string, required
      - `subIndication` string, nullable, required
    - `archiveOnComplete` boolean, required
    - `mailAccountId` string, nullable, required: A UUID.
    - `whatsappAccountId` string, nullable, required: A UUID.
    - `expiresAt` string, nullable, required: ISO 8601, UTC.
    - `createdAt` string, required: ISO 8601, UTC.
    - `updatedAt` string, required: ISO 8601, UTC.
    - `completedAt` string, nullable, required: ISO 8601, UTC.
    - `signers` object[], required
      - `id` string, required: A UUID.
      - `seq` number, required: Signing order, from 1.
      - `name` string, required
      - `email` string, nullable, required
      - `whatsapp` string, nullable, required
      - `delivery` 'email' | 'whatsapp', required
      - `userId` string, nullable, required: A UUID.
      - `role` 'signer' | 'cc', required: `signer` signs; `cc` receives a read-only link when the envelope is sent and the signed copy when it is complete, and never signs.
      - `authMethod` 'none' | 'otp_email' | 'in_person' | 'otp_whatsapp' | 'code_email', required
      - `status` 'pending' | 'sent' | 'viewed' | 'signed' | 'declined', required
      - `fields` object[], required
        - `type` 'signature' | 'initial' | 'date' | 'text', required
        - `page` number, required
        - `x` number, required
        - `y` number, required
        - `w` number, required
        - `h` number, required
        - `required` boolean, required
        - `documentKey` string
      - `declineReason` string, nullable, required
      - `sendCopy` boolean, required
      - `signedAt` string, nullable, required: ISO 8601, UTC.
      - `timestamp` boolean, required
      - `documents` object[], required
        - `key` string, required
        - `placement` union
          - object
            - `page` integer, required
            - `x` number, required
            - `y` number, required
            - `w` number, required
            - `h` number, required
            - `mode` 'coordinates', required
          - object
            - `mode` 'default', required
            - `w` number, required
            - `h` number, required
          - object
            - `mode` 'tag', required
            - `tag` string, required
            - `occurrence` integer, required
            - `w` number, required
            - `h` number, required
            - `offsetX` number, required
            - `offsetY` number, required
      - `signingPending` boolean, required
      - `signingError` string, nullable, required
    - `documents` object[], required
      - `key` string, required
      - `filename` string, required
      - `contentType` string, required
      - `sizeBytes` number, required
      - `sign` boolean, required
      - `hasSignedArtifact` boolean, required
      - `documentId` string, nullable, required: A UUID.

## Other responses

- `202`: Accepted; poll preparation.
- `400`: Invalid document combination or placement.
- `401`: No API key, or one that is malformed, unknown, revoked or expired.
- `403`: The module is off for this organisation, the credential lacks the permission, or the tier does not cover it.
- `429`: The API key has spent its minute, or its day. See `Retry-After`.
- `503`: Required signature or timestamp provider is not configured.

---

[API](https://skmtc.dev/custodo/apis/custodo-integrazioni.md) · [All operations](https://skmtc.dev/custodo/apis/custodo-integrazioni/llms.txt) · [OpenAPI document](https://skmtc.dev/custodo/apis/custodo-integrazioni/revisions/16d336d3ec2a?raw)
