> ## Documentation Index
> Fetch the complete documentation index at: https://docs.firma.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Finalize domain setup

> Finalize domain setup by registering with the email provider. This returns the DNS records (SPF, DKIM, DMARC) that must be added to enable email sending. Can only be called after domain ownership is verified.



## OpenAPI

````yaml post /company/domains/{id}/finalize
openapi: 3.0.3
info:
  title: Firma Partner API
  description: >-
    RESTful API for document signing and template management.


    **Authentication**: All endpoints require API key authentication via the
    `Authorization` header. Use your API key directly without any prefix (e.g.,
    `your-api-key`). The Bearer prefix is optional but not required.


    **Security Features**:

    - Input validation using Zod schemas with detailed field-level error
    messages

    - RSA-256 signed JWT tokens for embedded template access


    **Rate Limiting**: Rate limits are tiered based on operation type:

    - Read operations (GET): 200 requests per minute

    - Write operations (POST/PUT/PATCH/DELETE): 120 requests per minute

    - Webhook CRUD operations: 60 requests per minute

    - Webhook test: 10 requests per minute

    - API key regeneration/expiration: 1 request per minute

    - Webhook secret rotation: 1 request per minute


    When rate limits are exceeded, the API returns a `429 Too Many Requests`
    response with headers:

    - `X-RateLimit-Limit`: Maximum requests per minute for this endpoint

    - `X-RateLimit-Remaining`: Requests remaining in current window

    - `X-RateLimit-Reset`: Unix timestamp when limit resets

    - `Retry-After`: Seconds until retry is allowed


    **Error Handling**: All errors return structured JSON responses with `error`
    (human-readable message), `code` (machine-readable identifier), and
    `details` (field-level validation errors when applicable).


    **Embedded Template Integration**: The Firma Template Editor can be embedded
    in your application using a standalone JavaScript library.


    ```html

    <!-- Load the Firma Template Editor library -->

    <script
    src="https://api.firma.dev/functions/v1/embed-proxy/template-editor.js"></script>


    <script>

    // Generate JWT token via API first

    fetch('https://api.firma.dev/functions/v1/signing-request-api/generate-template-token',
    {
      method: 'POST',
      headers: {
        'Authorization': 'YOUR_API_KEY',
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        companies_workspaces_templates_id: 'template-id'
      })
    })

    .then(res => res.json())

    .then(data => {
      // Initialize editor with JWT token
      window.FirmaTemplateEditor.init({
        container: '#firma-editor-container',
        jwt: data.token,
        templateId: 'template-id',
        theme: 'dark',
        readOnly: false,
        onSave: (savedData) => {
          console.log('Template saved:', savedData);
        },
        onError: (error) => {
          console.error('Editor error:', error);
        },
        onLoad: (template) => {
          console.log('Template loaded:', template);
        }
      });
    });

    ```
  version: 01.03.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: Company
    description: Company information and settings
  - name: Workspaces
    description: Workspace management operations
  - name: Templates
    description: Template management operations
  - name: Signing Requests
    description: Document signing request operations
  - name: Custom Fields
    description: >-
      Custom field definition management for workspaces, templates, and signing
      requests
  - name: Webhooks
    description: Webhook configuration and management
  - name: JWT Management
    description: JWT token generation and revocation for embedded templates
  - name: Workspace Settings
    description: Workspace configuration and settings
  - name: Email Domains
    description: >-
      Email domain setup and verification for sending signing request emails
      from custom domains
  - name: Legacy
    description: Deprecated endpoints maintained for backward compatibility
paths:
  /company/domains/{id}/finalize:
    post:
      tags:
        - Email Domains
      summary: Finalize domain setup
      description: >-
        Finalize domain setup by registering with the email provider. This
        returns the DNS records (SPF, DKIM, DMARC) that must be added to enable
        email sending. Can only be called after domain ownership is verified.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: Domain ID
      responses:
        '200':
          description: Domain finalized successfully. Add the returned DNS records.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  domain:
                    $ref: '#/components/schemas/Domain'
                  dns_records:
                    type: array
                    items:
                      $ref: '#/components/schemas/DomainDnsRecord'
                    description: DNS records to add for email sending
                  next_step:
                    type: string
              example:
                message: >-
                  Domain finalized. Add the following DNS records to enable
                  email sending.
                domain:
                  id: 123e4567-e89b-12d3-a456-426614174000
                  domain: acme.com
                  verification_status: 2
                  domain_status: 0
                dns_records:
                  - type: TXT
                    name: '@'
                    value: v=spf1 include:amazonses.com ~all
                    ttl: Auto
                    status: pending
                  - type: CNAME
                    name: resend._domainkey
                    value: resend._domainkey.amazonses.com
                    ttl: Auto
                    status: pending
                  - type: TXT
                    name: _dmarc
                    value: v=DMARC1; p=none;
                    ttl: Auto
                    status: pending
                next_step: >-
                  Add these DNS records, then call POST
                  /company/domains/{id}/verify-dns to complete verification
        '400':
          description: Cannot finalize
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                notVerified:
                  value:
                    error: Ownership not verified
                    message: >-
                      Please verify domain ownership first by calling POST
                      /company/domains/{id}/verify-ownership
                alreadyFinalized:
                  value:
                    error: Already finalized
                    message: Domain has already been finalized
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
        '429':
          $ref: '#/components/responses/RateLimitError'
      security:
        - ApiKeyAuth: []
components:
  schemas:
    Domain:
      type: object
      description: Email domain configuration for sending signing request emails
      properties:
        id:
          type: string
          format: uuid
          description: Unique identifier for the domain
        domain:
          type: string
          description: The domain name (e.g., 'example.com')
        verification_status:
          type: integer
          enum:
            - 0
            - 1
            - 2
          description: >-
            Domain ownership verification status: 0=pending, 1=ownership
            verified (TXT record confirmed), 2=finalized (registered with email
            provider)
        domain_status:
          type: integer
          enum:
            - 0
            - 1
          description: >-
            Email sending status: 0=DNS records pending verification, 1=fully
            verified and ready to send
        is_primary:
          type: boolean
          description: >-
            Whether this is the primary domain for sending emails from this
            workspace
        verification_token:
          type: string
          description: >-
            Token to add as TXT record for domain ownership verification. Only
            returned when verification_status=0.
        resend_domain_id:
          type: string
          nullable: true
          description: External email provider domain ID (internal use)
        dns_records:
          type: array
          nullable: true
          description: >-
            Required DNS records for email sending. Only returned after domain
            finalization (verification_status=2).
          items:
            $ref: '#/components/schemas/DomainDnsRecord'
        date_created:
          type: string
          format: date-time
          description: Domain creation timestamp
        date_changed:
          type: string
          format: date-time
          description: Domain last update timestamp
    DomainDnsRecord:
      type: object
      description: DNS record required for email domain verification
      properties:
        type:
          type: string
          enum:
            - TXT
            - CNAME
            - MX
          description: DNS record type
        name:
          type: string
          description: DNS record name/host (e.g., 'resend._domainkey' or '@')
        value:
          type: string
          description: DNS record value
        ttl:
          type: string
          description: Time to live (e.g., 'Auto' or seconds)
        priority:
          type: integer
          nullable: true
          description: Priority for MX records
        status:
          type: string
          enum:
            - pending
            - verified
            - failed
          description: Verification status of this specific record
    Error:
      type: object
      properties:
        error:
          type: string
          description: Human-readable error message
        message:
          type: string
          description: Detailed error description
        details:
          type: object
          description: Additional error details
          additionalProperties: true
  responses:
    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
    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
  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.

````