openapi: 3.2.0 info: title: Firma Partner Templates API description: RESTful API for document signing and template management. version: 01.38.00 contact: name: API Support url: https://firma.com/support servers: - url: https://api.firma.dev/functions/v1/signing-request-api description: Production API - Recommended (Current) - url: https://api.firma.dev/api/v1 description: Production API - Planned security: - ApiKeyAuth: [] tags: - name: Templates description: Template management operations paths: /templates: get: summary: List Templates description: Retrieve a paginated list of templates tags: - Templates security: - ApiKeyAuth: [] parameters: - name: page in: query schema: type: integer minimum: 1 default: 1 description: Page number - name: page_size in: query schema: type: integer minimum: 1 maximum: 200 default: 50 description: Items per page - name: name in: query schema: type: string description: Filter by template name (partial match, case-insensitive) - name: created_after in: query schema: type: string format: date-time description: Filter templates created after this date (ISO 8601 format) - name: created_before in: query schema: type: string format: date-time description: Filter templates created before this date (ISO 8601 format) - name: sort_by in: query schema: type: string enum: - name - created_on - last_changed_on default: created_on description: Field to sort by - name: sort_order in: query schema: type: string enum: - asc - desc default: desc description: Sort order responses: '200': description: Templates retrieved successfully headers: X-RateLimit-Limit: schema: type: integer description: 'Rate limit: 200 requests per minute' X-RateLimit-Remaining: schema: type: integer X-RateLimit-Reset: schema: type: integer content: application/json: schema: $ref: '#/components/schemas/TemplateListResponse' '401': $ref: '#/components/responses/UnauthorizedError' '429': $ref: '#/components/responses/RateLimitError' operationId: listTemplates x-codeSamples: - lang: TypeScript label: '@firma-dev/sdk' source: 'import { FirmaClient } from "@firma-dev/sdk"; const firma = new FirmaClient({ apiKey: "YOUR_API_KEY" }); const response = await firma.templates.listTemplates(); console.log(response);' post: summary: Create Template description: Create a new template with a base64-encoded PDF document. The API automatically extracts the page count from the document. tags: - Templates security: - ApiKeyAuth: [] requestBody: required: true content: application/json: schema: type: object required: - name - document properties: name: type: string maxLength: 255 description: Template name example: Employment Contract Template description: type: string description: Template description example: Standard employment contract for new hires document: type: string format: byte description: Base64-encoded PDF or DOCX document. DOCX files are automatically converted to PDF. The API will automatically extract the page count from the document. For documents larger than 5 MB, use POST /documents and pass the document_id instead. (mutually exclusive with document_id) example: JVBERi0xLjQKJeLjz9MKMyAwIG9iago8PC9UeXBlIC9QYWdlCi9QYXJlbnQgMSAwIFIKL1Jlc291c... expiration_hours: type: integer description: Hours until signing request expires default: 168 example: 168 settings: type: object properties: allow_editing_before_sending: type: boolean default: false description: Allow editing fields before sending attach_pdf_on_finish: type: boolean default: true description: Attach completed PDF to completion email allow_download: type: boolean default: true description: Allow recipients to download the document hand_drawn_only: type: boolean default: false description: Require signers to hand-draw their signatures instead of using typed signatures require_otp_verification: type: - boolean - 'null' default: null description: Require signers to verify their email with a one-time code. null = inherit from workspace/company. disable_guided_navigation: type: - boolean - 'null' description: Disable automatic scrolling to the next required field during signing. Inherits from workspace or company if not set. allow_presigning_download: type: - boolean - 'null' description: Allow signers to download the original document before signing. Inherits from workspace or company setting when null. show_qr_code: type: - boolean - 'null' description: Show a QR code on the signing page that lets signers continue on their phone. Inherits from workspace or company setting when null. document_id: type: string format: uuid description: ID of a previously uploaded document (mutually exclusive with document). Obtain by calling POST /documents first. example: 123e4567-e89b-12d3-a456-426614174000 responses: '201': description: Template created successfully headers: X-RateLimit-Limit: schema: type: integer description: 'Rate limit: 120 requests per minute' X-RateLimit-Remaining: schema: type: integer X-RateLimit-Reset: schema: type: integer content: application/json: schema: $ref: '#/components/schemas/Template' '400': $ref: '#/components/responses/ValidationError' '401': $ref: '#/components/responses/UnauthorizedError' '429': $ref: '#/components/responses/RateLimitError' operationId: createTemplate x-codeSamples: - lang: TypeScript label: '@firma-dev/sdk' source: "import { FirmaClient } from \"@firma-dev/sdk\";\n\nconst firma = new FirmaClient({ apiKey: \"YOUR_API_KEY\" });\n\nconst response = await firma.templates.createTemplate({\n name: \"Employment Contract Template\",\n document: \"JVBERi0xLjQKJeLjz9MKMyAwIG9iago8PC9UeXBlIC9QYWdlCi9QYXJlbnQgMSAwIFIKL1Jlc291c...\"\n});\nconsole.log(response);" /templates/{id}: get: summary: Get Template description: Retrieve a specific template by ID tags: - Templates security: - ApiKeyAuth: [] parameters: - name: id in: path required: true schema: type: string format: uuid responses: '200': description: Template retrieved successfully headers: X-RateLimit-Limit: schema: type: integer description: 'Rate limit: 200 requests per minute' X-RateLimit-Remaining: schema: type: integer X-RateLimit-Reset: schema: type: integer content: application/json: schema: $ref: '#/components/schemas/Template' '401': $ref: '#/components/responses/UnauthorizedError' '404': $ref: '#/components/responses/NotFoundError' '429': $ref: '#/components/responses/RateLimitError' operationId: getTemplate x-codeSamples: - lang: TypeScript label: '@firma-dev/sdk' source: "import { FirmaClient } from \"@firma-dev/sdk\";\n\nconst firma = new FirmaClient({ apiKey: \"YOUR_API_KEY\" });\n\nconst response = await firma.templates.getTemplate({\n id: \"id\"\n});\nconsole.log(response);" patch: summary: Partially Update Template description: Update template properties, a single user, OR a single field. Cannot mix multiple entity types in one request. Use PUT for comprehensive updates including users, fields, and reminders. tags: - Templates security: - ApiKeyAuth: [] parameters: - name: id in: path required: true schema: type: string format: uuid requestBody: required: true content: application/json: schema: oneOf: - type: object description: Update template properties properties: name: type: string maxLength: 255 description: Template name description: type: string description: Template description document: type: string format: byte description: Base64-encoded PDF or DOCX to replace document. DOCX files are automatically converted to PDF. For documents larger than 5 MB, use POST /documents and pass the document_id instead. (mutually exclusive with document_id) document_id: type: string format: uuid description: ID of a previously uploaded document (mutually exclusive with document). Obtain by calling POST /documents first. example: 123e4567-e89b-12d3-a456-426614174000 expiration_hours: type: integer minimum: 1 description: Hours until expiration settings: type: object properties: allow_editing_before_sending: type: boolean attach_pdf_on_finish: type: boolean allow_download: type: boolean hand_drawn_only: type: boolean require_otp_verification: type: - boolean - 'null' disable_guided_navigation: type: - boolean - 'null' allow_presigning_download: type: - boolean - 'null' description: Allow signers to download the original document before signing. Inherits from workspace or company setting when null. show_qr_code: type: - boolean - 'null' description: Show a QR code on the signing page that lets signers continue on their phone. Inherits from workspace or company setting when null. - type: object description: Update or create a single user required: - user properties: user: type: object required: - first_name - email - designation - order properties: id: type: string format: uuid description: Include to update existing user, omit to create new. An existing recipient cannot be changed between CC and Signer/Approver (400); delete it and create it again. first_name: type: string maxLength: 255 last_name: type: string maxLength: 255 description: Optional, but required if using full_name or last_name prefilled variables email: type: string format: email designation: type: string enum: - Signer - Approver - CC order: type: integer minimum: 1 phone_number: type: string street_address: type: string city: type: string state_province: type: string postal_code: type: string country: type: string title: type: string company: type: string - type: object description: Update or create a single field required: - field properties: field: type: object properties: id: type: string format: uuid description: Include to update existing field, omit to create new type: type: string enum: - text - signature - date - checkbox - initial - initials - dropdown - radio_buttons - textarea - text_area - url - file - stamp - approval_signature - approval_checkmark - approval_date description: Field type. Accepts 'initial' or 'initials', 'textarea' or 'text_area'. Required for new fields. url fields are automatically read-only. file fields allow signers to upload attachments (images/PDF). stamp fields display a pre-configured image. x: type: number description: X position on document. Required for new fields. y: type: number description: Y position on document. Required for new fields. width: type: number description: Field width. Required for new fields. height: type: number description: Field height. Required for new fields. page: type: integer minimum: 1 description: Page number (1-indexed). Required for new fields. required: type: boolean description: Whether field is required assigned_to_user_id: type: - string - 'null' format: uuid description: Template user ID to assign field to variable_name: type: string description: Variable name for prefilled data mapping variable_defined_name: type: - string - 'null' maxLength: 100 description: Human-readable custom field definition name. Can be used as an alternative to variable_name for targeting fields in template-based creation. options: type: array items: type: string description: Options for dropdown fields format_rules: type: object description: Format rules (e.g., date format, urlDisplayText for url fields, acceptedFileTypes for file fields) multi_group_id: type: string format: uuid description: Group ID for radio button groups default_to_signing_date: type: boolean description: For date fields, use signing date as default read_only: type: boolean description: Whether field is read-only (automatically true for url fields) read_only_value: type: string description: Static value for read-only fields. For url fields, this is the URL to link to. - type: object required: - seal_participant description: Swap or assign a seal participant on a sent signing request. The seal_participant object identifies the participant slot and the target seal to apply. properties: seal_participant: type: object required: - participant_id - swap_to_seal_id description: Seal participant swap. Replaces the seal assigned to a participant slot with a different seal. properties: participant_id: type: string format: uuid description: ID of the seal participant slot to update swap_to_seal_id: type: string format: uuid description: ID of the new organization seal to assign to the slot examples: update-properties: summary: Update properties value: name: Updated Template Name expiration_hours: 72 create-url-field: summary: Create URL field value: field: type: url x: 100 y: 200 width: 150 height: 30 page: 1 read_only_value: https://example.com/terms format_rules: urlDisplayText: View Terms & Conditions create-file-field: summary: Create file upload field value: field: type: file x: 100 y: 300 width: 200 height: 40 page: 1 required: true format_rules: acceptedFileTypes: image_and_pdf update-field: summary: Update existing field value: field: id: field123-e89b-12d3-a456-426614174000 x: 120 y: 220 responses: '200': description: Template partially updated successfully headers: X-RateLimit-Limit: schema: type: integer description: 'Rate limit: 120 requests per minute' X-RateLimit-Remaining: schema: type: integer X-RateLimit-Reset: schema: type: integer content: application/json: schema: $ref: '#/components/schemas/TemplatePatchResponse' '400': $ref: '#/components/responses/ValidationError' '401': $ref: '#/components/responses/UnauthorizedError' '404': description: Template or seal participant not found content: application/json: schema: $ref: '#/components/schemas/Error' examples: not_found: value: error: Template not found code: NOT_FOUND seal_not_found: value: error: Organization seal not found or unavailable in this workspace code: NOT_FOUND '429': $ref: '#/components/responses/RateLimitError' operationId: patchTemplate x-participant-order-contract: membership: Signer and Approver recipients plus organization seal participants share one contiguous 1-based order space. CC recipients use a separate sequence and never consume a participant position. patch: 'On an unsent template, order must be in [1..n] for a move and [1..n+1] for a create. A move is shift-insert: every participant between the old and new positions is renumbered. A create with omitted order appends. Explicit order 0 is invalid.' lockedStates: An applied participant on an aborted-send request can narrow the reachable interval; this template operation has no sent state. create: When no seal is present, tied recipient order values are resolved deterministically and compacted to [1..n]. A seal-bearing create rejects a non-contiguous space or collision with INVALID_SIGNING_ORDER. When use_signing_order is false, or any recipient omits order, participant orders follow array order. sideEffects: Retrying a create after a later field write fails creates a second participant, matching the existing non-idempotent create contract. errors: - INVALID_SIGNING_ORDER - PARTICIPANTS_CHANGED x-codeSamples: - lang: TypeScript label: '@firma-dev/sdk' source: "import { FirmaClient } from \"@firma-dev/sdk\";\n\nconst firma = new FirmaClient({ apiKey: \"YOUR_API_KEY\" });\n\nconst response = await firma.templates.patchTemplate({\n id: \"id\",\n body: {\n name: \"Updated Template Name\",\n expiration_hours: 72\n }\n});\nconsole.log(response);" put: summary: Comprehensive Template Update description: Comprehensive update of template including properties, users, fields, and reminders. Supports user deletion with field reassignment or deletion. All sections are optional but at least one must be provided. tags: - Templates security: - ApiKeyAuth: [] parameters: - name: id in: path required: true schema: type: string format: uuid requestBody: required: true content: application/json: schema: type: object properties: template_properties: type: object description: Update template metadata and settings properties: name: type: string maxLength: 255 description: type: string document: type: string format: byte description: Base64-encoded PDF or DOCX to replace document. DOCX files are automatically converted to PDF. For documents larger than 5 MB, use POST /documents and pass the document_id instead. (mutually exclusive with document_id) document_id: type: string format: uuid description: ID of a previously uploaded document (mutually exclusive with document). Obtain by calling POST /documents first. example: 123e4567-e89b-12d3-a456-426614174000 expiration_hours: type: integer minimum: 1 settings: type: object properties: allow_editing_before_sending: type: boolean attach_pdf_on_finish: type: boolean allow_download: type: boolean hand_drawn_only: type: boolean require_otp_verification: type: - boolean - 'null' disable_guided_navigation: type: - boolean - 'null' allow_presigning_download: type: - boolean - 'null' description: Allow signers to download the original document before signing. Inherits from workspace or company setting when null. show_qr_code: type: - boolean - 'null' description: Show a QR code on the signing page that lets signers continue on their phone. Inherits from workspace or company setting when null. users: type: array description: Upsert users (include id to update, omit to create). An existing recipient cannot be changed between CC and Signer/Approver (400); delete it and create it again. items: type: object required: - first_name - email - designation - order properties: id: type: string format: uuid description: Omit for new users first_name: type: string last_name: type: string description: Optional, but required if using full_name or last_name prefilled variables email: type: string format: email designation: type: string enum: - Signer - Approver - CC order: type: integer minimum: 1 phone_number: type: string street_address: type: string city: type: string state_province: type: string postal_code: type: string country: type: string title: type: string company: type: string force_remove_conditions: type: boolean default: false description: 'When deleting users whose fields are referenced by conditions in other fields: if true, automatically remove the condition references; if false (default), the request will be rejected with an error.' deleted_users: type: array description: Users to delete with field handling strategy items: type: object required: - user_id - field_action properties: user_id: type: string format: uuid field_action: type: string enum: - delete - reassign description: What to do with fields assigned to this user reassign_to_user_id: type: string format: uuid description: Required when field_action is 'reassign'. Target user must have same designation. fields: type: array description: Upsert fields (include id to update, omit to create) items: type: object required: - type - x - y - width - height - page properties: id: type: string format: uuid description: Omit for new fields type: type: string enum: - signature - text - date - checkbox - dropdown - approval_signature - approval_checkmark - approval_date x: type: number minimum: 0 maximum: 100 description: X position as percentage y: type: number minimum: 0 maximum: 100 description: Y position as percentage width: type: number minimum: 0 maximum: 100 height: type: number minimum: 0 maximum: 100 page: type: integer minimum: 1 required: type: boolean default: false assigned_to_user_id: type: string format: uuid options: type: array items: type: string description: For dropdown fields default_to_signing_date: type: boolean description: For date fields multi_group_id: type: string format: uuid description: Group ID for mutually exclusive checkbox/radio button groups variable_name: type: string variable_defined_name: type: - string - 'null' maxLength: 100 description: Human-readable custom field definition name. Can be used as an alternative to variable_name for targeting fields in template-based creation. required_conditions: $ref: '#/components/schemas/ConditionSet' visibility_conditions: $ref: '#/components/schemas/ConditionSet' reminders: type: array description: Upsert reminders (include id to update, omit to create) items: type: object required: - hours - subject - message properties: id: type: string format: uuid description: Omit for new reminders hours: type: integer minimum: 1 description: Hours after sending before reminder all_users: type: boolean default: false user_id: type: string format: uuid description: Required if all_users is false subject: type: string maxLength: 255 message: type: string maxLength: 5000 responses: '200': description: Template updated successfully. Returns full template with all relationships. headers: X-RateLimit-Limit: schema: type: integer description: 'Rate limit: 120 requests per minute' X-RateLimit-Remaining: schema: type: integer X-RateLimit-Reset: schema: type: integer content: application/json: schema: $ref: '#/components/schemas/Template' '400': $ref: '#/components/responses/ValidationError' '401': $ref: '#/components/responses/UnauthorizedError' '404': $ref: '#/components/responses/NotFoundError' '429': $ref: '#/components/responses/RateLimitError' operationId: updateTemplate x-participant-order-contract: membership: Signer and Approver users plus organization seal participants share one contiguous 1-based order space. CC users use a separate sequence and never consume a participant position. users and deleted_users participate in the same atomic participant-set update. patch: 'On an unsent template, order must be in [1..n] for a move and [1..n+1] for a create. A move is shift-insert: every participant between the old and new positions is renumbered. A create with omitted order appends. Explicit order 0 is invalid.' lockedStates: An applied participant on an aborted-send request can narrow the reachable interval; this template operation has no sent state. create: When no seal is present, tied user order values are resolved deterministically and compacted to [1..n]. A seal-bearing create rejects a non-contiguous space or collision with INVALID_SIGNING_ORDER. When signing order is disabled, or any user omits order, participant orders follow array order. sideEffects: Shift-insert changes every participant between the old and new positions. Retrying a create after a later field write fails creates a second participant, matching the existing non-idempotent create contract. errors: - INVALID_SIGNING_ORDER - PARTICIPANTS_CHANGED x-codeSamples: - lang: TypeScript label: '@firma-dev/sdk' source: "import { FirmaClient } from \"@firma-dev/sdk\";\n\nconst firma = new FirmaClient({ apiKey: \"YOUR_API_KEY\" });\n\nconst response = await firma.templates.updateTemplate({\n id: \"id\"\n});\nconsole.log(response);" delete: summary: Delete a template description: Soft delete a template by ID. This marks the template as deleted but retains the data. tags: - Templates security: - ApiKeyAuth: [] parameters: - name: id in: path required: true description: Template ID schema: type: string format: uuid responses: '200': description: Template deleted successfully headers: X-RateLimit-Limit: schema: type: integer description: 'Rate limit: 120 requests per minute' X-RateLimit-Remaining: schema: type: integer description: Remaining requests in current window X-RateLimit-Reset: schema: type: integer description: Unix timestamp when rate limit resets content: application/json: schema: $ref: '#/components/schemas/MessageResponse' example: message: Template deleted successfully '401': $ref: '#/components/responses/UnauthorizedError' '404': $ref: '#/components/responses/NotFoundError' '429': $ref: '#/components/responses/RateLimitError' operationId: deleteTemplate x-codeSamples: - lang: TypeScript label: '@firma-dev/sdk' source: "import { FirmaClient } from \"@firma-dev/sdk\";\n\nconst firma = new FirmaClient({ apiKey: \"YOUR_API_KEY\" });\n\nconst response = await firma.templates.deleteTemplate({\n id: \"id\"\n});\nconsole.log(response);" /templates/{id}/users: get: summary: Get template users description: Retrieve all recipients/users associated with a specific template tags: - Templates security: - ApiKeyAuth: [] parameters: - name: id in: path required: true description: Template ID schema: type: string format: uuid responses: '200': description: Template users retrieved successfully headers: X-RateLimit-Limit: schema: type: integer description: 'Rate limit: 200 requests per minute' X-RateLimit-Remaining: schema: type: integer description: Remaining requests in current window X-RateLimit-Reset: schema: type: integer description: Unix timestamp when rate limit resets content: application/json: schema: $ref: '#/components/schemas/TemplateUserListResponse' example: results: - id: abc12345-e89b-12d3-a456-426614174000 name: John Doe email: john@example.com first_name: John last_name: Doe designation: Signer order: 1 phone_number: null street_address: null city: null state_province: null postal_code: null country: null title: null company: null required_fields: - email - first_name missing_fields: [] required_read_only_fields: [] ready_to_send: true - id: def67890-e89b-12d3-a456-426614174000 name: null email: null first_name: null last_name: null designation: Signer order: 2 phone_number: null street_address: null city: null state_province: null postal_code: null country: null title: null company: null required_fields: - email - first_name - phone_number missing_fields: - email - first_name - phone_number required_read_only_fields: - variable_name: contract_date field_type: date ready_to_send: false '401': $ref: '#/components/responses/UnauthorizedError' '404': $ref: '#/components/responses/NotFoundError' '429': $ref: '#/components/responses/RateLimitError' operationId: listTemplateUsers x-codeSamples: - lang: TypeScript label: '@firma-dev/sdk' source: "import { FirmaClient } from \"@firma-dev/sdk\";\n\nconst firma = new FirmaClient({ apiKey: \"YOUR_API_KEY\" });\n\nconst response = await firma.templates.listTemplateUsers({\n id: \"id\"\n});\nconsole.log(response);" /templates/{id}/fields: get: summary: Get template fields description: Retrieve all fields configured for a specific template tags: - Templates security: - ApiKeyAuth: [] parameters: - name: id in: path required: true description: Template ID schema: type: string format: uuid responses: '200': description: Template fields retrieved successfully headers: X-RateLimit-Limit: schema: type: integer description: 'Rate limit: 200 requests per minute' X-RateLimit-Remaining: schema: type: integer description: Remaining requests in current window X-RateLimit-Reset: schema: type: integer description: Unix timestamp when rate limit resets content: application/json: schema: $ref: '#/components/schemas/TemplateFieldListResponse' example: results: - id: field123-e89b-12d3-a456-426614174000 type: signature required: true recipient_id: user123-uuid variable_name: null position: x: 100 y: 200 width: 200 height: 50 page_number: 1 dropdown_options: null multi_group_id: null date_signing_default: false format_rules: null validation_rules: null read_only: false read_only_value: null - id: field456-e89b-12d3-a456-426614174000 type: date required: true recipient_id: user123-uuid variable_name: null position: x: 100 y: 250 width: 150 height: 30 page_number: 1 dropdown_options: null multi_group_id: null date_signing_default: true format_rules: date_format: MM/DD/YYYY validation_rules: null read_only: false read_only_value: null '401': $ref: '#/components/responses/UnauthorizedError' '404': $ref: '#/components/responses/NotFoundError' '429': $ref: '#/components/responses/RateLimitError' operationId: listTemplateFields x-codeSamples: - lang: TypeScript label: '@firma-dev/sdk' source: "import { FirmaClient } from \"@firma-dev/sdk\";\n\nconst firma = new FirmaClient({ apiKey: \"YOUR_API_KEY\" });\n\nconst response = await firma.templates.listTemplateFields({\n id: \"id\"\n});\nconsole.log(response);" /templates/{id}/reminders: get: summary: Get template reminders description: Retrieve all reminders configured for a specific template tags: - Templates security: - ApiKeyAuth: [] parameters: - name: id in: path required: true description: Template ID schema: type: string format: uuid responses: '200': description: Template reminders retrieved successfully headers: X-RateLimit-Limit: schema: type: integer description: 'Rate limit: 200 requests per minute' X-RateLimit-Remaining: schema: type: integer description: Remaining requests in current window X-RateLimit-Reset: schema: type: integer description: Unix timestamp when rate limit resets content: application/json: schema: type: array items: $ref: '#/components/schemas/Reminder' example: - id: remind123-e89b-12d3-a456-426614174000 hours: 24 subject: 'Reminder: Please sign the document' message: This is a friendly reminder to complete your signature. all_users: true template_user_id: null created_date: '2024-01-15T10:30:00Z' updated_date: '2024-01-15T10:30:00Z' '401': $ref: '#/components/responses/UnauthorizedError' '404': $ref: '#/components/responses/NotFoundError' '429': $ref: '#/components/responses/RateLimitError' operationId: listTemplateReminders x-codeSamples: - lang: TypeScript label: '@firma-dev/sdk' source: "import { FirmaClient } from \"@firma-dev/sdk\";\n\nconst firma = new FirmaClient({ apiKey: \"YOUR_API_KEY\" });\n\nconst response = await firma.templates.listTemplateReminders({\n id: \"id\"\n});\nconsole.log(response);" /templates/{id}/replace-document: post: summary: Replace template document description: Replaces the PDF document of an existing template while preserving all field placements. The replacement document must have the same page count and matching page dimensions (within 1pt tolerance) as the original. tags: - Templates security: - ApiKeyAuth: [] parameters: - name: id in: path required: true schema: type: string format: uuid description: Template ID requestBody: required: true content: application/json: schema: type: object required: - document properties: document: type: string description: Base64-encoded PDF or DOCX document. DOCX files are automatically converted to PDF. For documents larger than 5 MB, use POST /documents and pass the document_id instead. (mutually exclusive with document_id) document_id: type: string format: uuid description: ID of a previously uploaded document (mutually exclusive with document). Obtain by calling POST /documents first. example: 123e4567-e89b-12d3-a456-426614174000 responses: '200': description: Document replaced successfully headers: X-RateLimit-Limit: schema: type: integer description: 'Rate limit: 120 requests per minute' X-RateLimit-Remaining: schema: type: integer X-RateLimit-Reset: schema: type: integer content: application/json: schema: $ref: '#/components/schemas/Template' '400': description: Validation error (page count mismatch, dimension mismatch, invalid document) content: application/json: schema: $ref: '#/components/schemas/Error' '401': $ref: '#/components/responses/UnauthorizedError' '404': $ref: '#/components/responses/NotFoundError' '429': $ref: '#/components/responses/RateLimitError' operationId: replaceTemplateDocument x-codeSamples: - lang: TypeScript label: '@firma-dev/sdk' source: "import { FirmaClient } from \"@firma-dev/sdk\";\n\nconst firma = new FirmaClient({ apiKey: \"YOUR_API_KEY\" });\n\nconst response = await firma.templates.replaceTemplateDocument({\n id: \"id\",\n document: \"document\"\n});\nconsole.log(response);" /templates/{id}/duplicate: post: summary: Duplicate template into signing request description: Creates a new signing request by duplicating an existing template, including all fields, users, reminders, and settings. tags: - Templates security: - ApiKeyAuth: [] parameters: - name: id in: path required: true schema: type: string format: uuid description: Template ID to duplicate requestBody: required: false content: application/json: schema: type: object properties: name: type: string maxLength: 255 description: Custom name for the new signing request (defaults to template name) example: name: Q4 2025 Contract responses: '201': description: Template duplicated successfully into a new signing request headers: X-RateLimit-Limit: schema: type: integer description: 'Rate limit: 120 requests per minute' X-RateLimit-Remaining: schema: type: integer X-RateLimit-Reset: schema: type: integer content: application/json: schema: $ref: '#/components/schemas/TemplateDuplicateResponse' '401': $ref: '#/components/responses/UnauthorizedError' '403': description: Template belongs to a different workspace content: application/json: schema: $ref: '#/components/schemas/Error' '404': $ref: '#/components/responses/NotFoundError' '429': $ref: '#/components/responses/RateLimitError' operationId: duplicateTemplate x-codeSamples: - lang: TypeScript label: '@firma-dev/sdk' source: "import { FirmaClient } from \"@firma-dev/sdk\";\n\nconst firma = new FirmaClient({ apiKey: \"YOUR_API_KEY\" });\n\nconst response = await firma.templates.duplicateTemplate({\n id: \"id\",\n name: \"Q4 2025 Contract\"\n});\nconsole.log(response);" /templates/{id}/copy: post: summary: Copy template to another workspace description: Deep-copies a template (including fields, recipients, CC, reminders, custom field definitions, and the PDF document) to a target workspace within the same company. Requires a company-level (protected) API key. tags: - Templates security: - ApiKeyAuth: [] parameters: - name: id in: path required: true schema: type: string format: uuid description: Template ID to copy requestBody: required: true content: application/json: schema: type: object required: - workspace_id properties: workspace_id: type: string format: uuid description: Target workspace ID to copy the template into name: type: string maxLength: 255 description: Name for the copied template (defaults to original name with " (copy)" suffix) example: workspace_id: 550e8400-e29b-41d4-a716-446655440000 name: My Template Copy responses: '201': description: Template copied successfully headers: X-RateLimit-Limit: schema: type: integer description: 'Rate limit: 120 requests per minute' X-RateLimit-Remaining: schema: type: integer X-RateLimit-Reset: schema: type: integer content: application/json: schema: $ref: '#/components/schemas/TemplateCopyResponse' '400': description: Missing workspace_id or invalid name content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': $ref: '#/components/responses/UnauthorizedError' '403': description: Protected API key required, or access denied content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' examples: protected_key_required: value: error: This operation requires a protected workspace API key code: PROTECTED_KEY_REQUIRED access_denied: value: error: Template not found or access denied code: ACCESS_DENIED '404': description: Template or target workspace not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '429': $ref: '#/components/responses/RateLimitError' x-participant-order-contract: membership: The copy preserves the source template's participant order. Seal participants whose seal is not in scope for the target workspace are dropped, along with their fields. The remaining participants are compacted to a contiguous [1..n] order. errors: - INVALID_SIGNING_ORDER - PARTICIPANTS_CHANGED operationId: postTemplatesByIdCopy x-operation-id-source: derived components: responses: RateLimitError: description: Too Many Requests - Rate limit exceeded headers: X-RateLimit-Limit: schema: type: integer description: Maximum requests per minute X-RateLimit-Remaining: schema: type: integer description: Requests remaining X-RateLimit-Reset: schema: type: integer description: Unix timestamp of reset Retry-After: schema: type: integer description: Seconds until retry allowed content: application/json: schema: $ref: '#/components/schemas/Error' example: error: Rate Limit Exceeded message: Too many requests. Please wait before retrying. details: retry_after: 45 UnauthorizedError: description: Unauthorized - Invalid or missing API key content: application/json: schema: $ref: '#/components/schemas/Error' example: error: Unauthorized message: Invalid API key NotFoundError: description: Not Found - Resource does not exist content: application/json: schema: $ref: '#/components/schemas/Error' example: error: Not Found message: The requested resource was not found ValidationError: description: Bad Request - Validation failed content: application/json: schema: $ref: '#/components/schemas/Error' example: error: Validation Error message: Invalid input data details: name: Name is required email: Invalid email format schemas: MessageResponse: type: object description: Simple success response with a message properties: message: type: string description: Success message required: - message Condition: type: object required: - field_id - operator description: A single condition that evaluates a field's value. properties: field_id: type: string format: uuid description: ID of the field to evaluate operator: type: string enum: - is_filled - is_empty - equals - not_equals - contains - not_contains - greater_than - less_than - greater_than_or_equal - less_than_or_equal description: 'Comparison operator. ''is_filled''/''is_empty'' don''t require a value. Text operators: equals, not_equals, contains, not_contains. Numeric/date operators: greater_than, less_than, greater_than_or_equal, less_than_or_equal.' value: oneOf: - type: string - type: number description: Value to compare against. Not required for is_filled/is_empty operators. TemplateFieldListResponse: type: object description: List of template fields properties: results: type: array items: $ref: '#/components/schemas/TemplateField' required: - results TemplatePatchResponse: type: object properties: message: type: string updated_fields: type: array items: type: string description: Returned when updating properties user: type: object description: Returned when updating/creating a user description: Template partial update result required: - message - updated_fields TemplateListResponse: type: object description: Paginated list of templates properties: results: type: array items: $ref: '#/components/schemas/Template' pagination: $ref: '#/components/schemas/Pagination' required: - results - pagination Error: type: object properties: error: type: string description: Human-readable error message code: type: string description: 'Machine-readable error code Seal-related codes: SEALS_DISABLED, SEAL_ALREADY_REVOKED, SEAL_CREATION_DISABLED_EDGE, SEAL_ERASE_NOT_ELIGIBLE, SEAL_IMAGE_INVALID, SEAL_MUTATION_NOT_ALLOWED, SEAL_NOT_FOUND, SEAL_ORDER_COLLISION, SEAL_PAUSED, SEAL_SCOPE_FORBIDDEN, SEAL_UNAVAILABLE' errors: type: array description: All validation errors when multiple failures are reported together. The top-level error repeats the first item for backward compatibility. items: type: object required: - message properties: message: type: string message: type: string description: Detailed error description details: type: object description: Additional error details additionalProperties: true required: - error description: ' Organization Seal error codes: SEALS_DISABLED, SEAL_ALREADY_REVOKED, SEAL_CREATION_DISABLED_EDGE, SEAL_ERASE_NOT_ELIGIBLE, SEAL_IMAGE_INVALID, SEAL_MUTATION_NOT_ALLOWED, SEAL_NOT_FOUND, SEAL_ORDER_COLLISION, SEAL_PAUSED, SEAL_SCOPE_FORBIDDEN, SEAL_UNAVAILABLE' FieldValidationRules: type: - object - 'null' description: Validation rules for field values. Reserved for future use - currently not enforced for any field types. additionalProperties: true TemplateUserListResponse: type: object description: List of template users properties: results: type: array items: $ref: '#/components/schemas/TemplateUser' required: - results Template: type: object properties: id: type: string format: uuid description: Unique identifier for the template name: type: string description: Template name maxLength: 255 description: type: - string - 'null' description: Template description document_url: type: string format: uri description: Pre-signed URL to the PDF document. This is a time-limited signed URL for secure access - see document_url_expires_at for expiration time. Initial URLs are valid for 7 days; refreshed URLs are valid for 1 hour. Request a new template retrieval to get a fresh URL if expired. document_url_expires_at: type: - string - 'null' format: date-time description: ISO 8601 timestamp when the document_url will expire. After this time, the URL will return an access denied error. Fetch the template again to receive a fresh signed URL. page_count: type: integer minimum: 1 description: Number of pages in the document expiration_hours: type: integer minimum: 1 default: 168 description: Hours until signing requests created from this template expire credit_cost: type: integer minimum: 1 default: 1 description: Number of credits consumed when a signing request is sent from this template. Minimum value is 1. settings: $ref: '#/components/schemas/SigningRequestSettings' recipients: type: array items: $ref: '#/components/schemas/TemplateUser' description: Template recipients (included in GET single template) fields: type: array items: $ref: '#/components/schemas/TemplateField' description: Template fields (included in GET single template) created_date: type: string format: date-time description: Template creation timestamp updated_date: type: string format: date-time description: Template last update timestamp required: - id - name - created_date TemplateCopyResponse: type: object properties: id: type: string format: uuid description: ID of the newly created template copy name: type: string description: Name of the copied template workspace_id: type: string format: uuid description: Target workspace the template was copied to created_date: type: string format: date-time description: Creation timestamp description: Template copy response required: - id - name - workspace_id - created_date Reminder: type: object properties: id: type: string format: uuid description: Unique identifier for the reminder hours: type: integer minimum: 1 description: Hours after sending before reminder is sent subject: type: string description: Email subject for the reminder maxLength: 255 message: type: string description: Email message body for the reminder maxLength: 5000 all_users: type: boolean description: Whether reminder applies to all users template_user_id: type: - string - 'null' format: uuid description: Specific user to send reminder to (used in template context) recipient_id: type: - string - 'null' format: uuid description: Specific recipient to send reminder to (used in signing request context, same as template_user_id) sent_on: type: - string - 'null' format: date-time description: Timestamp when the reminder was actually sent created_at: type: string format: date-time description: Reminder creation timestamp updated_at: type: string format: date-time description: Reminder last update timestamp required: - id - hours - subject - message ErrorResponse: type: object description: Referenced by this document but never defined in it. API Evangelist added this empty placeholder so the document resolves; the shape is unknown and is NOT a claim about the API. x-ae-placeholder: true TemplateUser: type: object properties: id: type: string format: uuid description: Unique identifier for the template user name: type: string description: Recipient name (combined first and last name) email: type: string format: email description: Recipient email address first_name: type: - string - 'null' description: Recipient first name last_name: type: - string - 'null' description: Recipient last name designation: type: string enum: - Signer - Approver - CC description: Role of the recipient. Signer signs the document, Approver approves with approval fields, CC receives a copy when complete. order: type: integer minimum: 1 description: Order in which the recipient should sign phone_number: type: - string - 'null' description: Recipient phone number street_address: type: - string - 'null' description: Recipient street address city: type: - string - 'null' description: Recipient city state_province: type: - string - 'null' description: Recipient state or province postal_code: type: - string - 'null' description: Recipient postal code country: type: - string - 'null' description: Recipient country title: type: - string - 'null' description: Recipient job title company: type: - string - 'null' description: Recipient company name required_fields: type: array items: type: string description: List of recipient data fields required for sending (based on template fields with variable_name mappings). Always includes 'email' and 'first_name'. missing_fields: type: array items: type: string description: List of required fields that are currently empty for this recipient required_read_only_fields: type: array items: type: object properties: variable_name: type: - string - 'null' description: Variable name of the read-only field variable_defined_name: type: - string - 'null' description: Human-readable field name from the custom field definition (e.g. 'artist_name'). Only present for fields linked to a custom field definition, null otherwise. field_type: type: string description: Type of the field (text, date, etc.) description: List of required read-only fields that need pre-filled values before sending ready_to_send: type: boolean description: Whether this recipient has all required data filled in for sending required: - id - first_name - email - designation - order Pagination: type: object properties: current_page: type: integer page_size: type: integer total_count: type: integer total_pages: type: integer description: Pagination metadata for list responses required: - current_page - page_size - total_count - total_pages ConditionGroup: type: object required: - conditions properties: conditions: type: array items: $ref: '#/components/schemas/Condition' description: Array of conditions within this group. Combined using the opposite of the parent ConditionSet's logic operator. ConditionSet: type: object required: - logic - groups description: 'A set of condition groups with nested logic. The outer ''logic'' operator combines groups, while each group''s conditions use the opposite operator. Example: logic=''and'' means all groups must match, and within each group any condition can match (OR).' properties: logic: type: string enum: - and - or description: Logical operator to combine groups. 'and' = all groups must match, 'or' = any group can match. groups: type: array items: $ref: '#/components/schemas/ConditionGroup' description: Array of condition groups DateFormatRules: type: object description: Formatting rules for date fields. Specifies how date values should be displayed and formatted. properties: dateFormat: type: string description: 'Date format pattern. Use predefined formats or custom patterns with: yyyy (4-digit year), MM (2-digit month), dd (2-digit day), MMMM (full month name), MMM (abbreviated month name), HH (24-hour), mm (minute), ss (second). Examples: ''MM/dd/yyyy'' displays as 01/31/2024, ''MMMM dd, yyyy'' displays as January 31, 2024.' enum: - MM/dd/yyyy - dd/MM/yyyy - yyyy-MM-dd - MMMM dd, yyyy - MMM dd, yyyy - dd MMMM yyyy default: MM/dd/yyyy fontSize: type: integer minimum: 8 maximum: 48 description: Optional starting/maximum font size in pixels for the rendered field value. Text still auto-shrinks to fit the field box. Omit for automatic sizing. Values outside 8-48 are clamped. example: dateFormat: MMMM dd, yyyy TemplateDuplicateResponse: type: object properties: id: type: string format: uuid description: ID of the newly created signing request name: type: string description: Name of the new signing request description: type: - string - 'null' description: Description of the new signing request status: type: string description: Status of the new signing request example: draft workspace_id: type: string format: uuid description: Workspace the signing request belongs to created_date: type: string format: date-time description: Creation timestamp description: Duplicated template details required: - id - name - status - workspace_id TemplateField: type: object description: A field placed on a template document properties: id: type: string format: uuid description: Unique identifier for the field type: type: string enum: - text - signature - date - checkbox - dropdown - radio_buttons - number - text_area - file - initial - stamp - approval_signature - approval_checkmark - approval_date description: Type of the field required: type: boolean description: Whether the field is required recipient_id: type: - string - 'null' format: uuid description: ID of assigned recipient variable_name: type: - string - 'null' description: Variable name for field (used in templates) variable_defined_name: type: - string - 'null' description: Human-readable field name from the custom field definition (e.g. 'artist_name'). Only present for fields linked to a custom field definition, null otherwise. position: type: object description: 'Position and dimensions of the field on the document. All values are percentages (0-100). The field must fit within the page: x + width <= 100 and y + height <= 100.' properties: x: type: number minimum: 0 maximum: 100 description: X coordinate of field position (percentage, 0-100) y: type: number minimum: 0 maximum: 100 description: Y coordinate of field position (percentage, 0-100) width: type: number minimum: 0 maximum: 100 description: 'Width of the field (percentage, 0-100). Note: x + width must be <= 100' height: type: number minimum: 0 maximum: 100 description: 'Height of the field (percentage, 0-100). Note: y + height must be <= 100' page_number: type: - integer - 'null' minimum: 1 description: Page number where the field is located (1-indexed). Must not exceed the document's total page count. dropdown_options: description: Options for dropdown fields oneOf: - type: array items: type: string - type: object multi_group_id: type: - string - 'null' format: uuid description: Group ID for linking multiple checkbox or radio button fields together. Fields sharing the same multi_group_id behave as a mutually exclusive group (like radio buttons) - selecting one automatically deselects the others in the group. Use the same UUID across multiple fields to create a group where only one option can be selected at a time. date_default: type: - string - 'null' format: date description: Default date value for date fields (ISO 8601 format, e.g., '2024-01-15') date_signing_default: type: boolean description: Use signing date as default for date fields format_rules: $ref: '#/components/schemas/DateFormatRules' description: Formatting rules - currently used for date fields to specify display format validation_rules: $ref: '#/components/schemas/FieldValidationRules' read_only: type: boolean default: false description: Whether this field is read-only (pre-filled before signing) read_only_value: type: - string - 'null' description: Static value for read-only fields required: - id - type - page_number SigningRequestSettings: type: object description: Settings returned by the signing request list and detail endpoints. Templates use the TemplateSettings schema (no identity fields). properties: allow_download: type: boolean description: Whether recipients can download the document default: true attach_pdf_on_finish: type: boolean description: Whether to attach PDF when signing is complete default: true allow_editing_before_sending: type: boolean description: Whether the signing request can be edited before sending default: false use_signing_order: type: boolean description: Whether signing order is enforced among recipients. When true, signers receive the document in sequence based on their order. When false, all signers receive the document simultaneously. default: true hand_drawn_only: type: boolean description: When enabled, signers can only hand-draw their signatures and cannot use typed/font-based signatures default: false send_signing_email: type: boolean description: Whether to send signing request notification emails to signers default: true send_finish_email: type: boolean description: Whether to send completion email when all signers finish default: true send_expiration_email: type: boolean description: Whether to send expiration notification email when request expires default: true send_cancellation_email: type: boolean description: Whether to send cancellation notification email when request is cancelled default: true require_otp_verification: type: - boolean - 'null' description: Whether signers must verify their email with a one-time code before accessing the document. null = inherit from workspace/company setting. default: null disable_guided_navigation: type: - boolean - 'null' description: Disable automatic scrolling to the next required field during signing. Inherits from workspace or company if not set. allow_presigning_download: type: - boolean - 'null' description: Allow signers to download the original document before signing. Inherits from workspace or company setting when null. show_qr_code: type: - boolean - 'null' description: Show a QR code on the signing page that lets signers continue on their phone. Inherits from workspace or company setting when null. identity_editable_fields: type: - array - 'null' items: type: string description: Identity fields signers may edit before signing (e.g. ["name", "company"]). null = disabled. When set, a confirmation dialog lets signers edit the specified fields. notify_identity_change_email: type: boolean default: false description: Send an email notification when a signer changes their identity. securitySchemes: ApiKeyAuth: type: apiKey in: header name: Authorization description: API key for authentication. Use your API key directly without any prefix (e.g., 'your-api-key'). Bearer prefix is optional but not required.