Skip to content

Template Controllers

Overview

Template controllers manage renderable template resources and provide document generation and delivery endpoints. All template controllers inherit the full Resource Controller endpoint set plus the template-specific operations documented here.

The following controllers are covered by this page:

Controller Base Path Resource Type
TemplateController /api/templates TEMPLATE (HTML/document)
EmailTemplateController /api/email-templates EMAIL_TEMPLATE
FopTemplateController /api/fop-templates FOP_TEMPLATE (XSL-FO)
OfficeTemplateController /api/office-templates OFFICE_TEMPLATE (DOCX/XLSX)
ModificationTemplateController /api/modificationTemplates MODIFICATION_TEMPLATE

Each controller also inherits all endpoints documented in Resource Controller.

Authentication

All endpoints require the X-API-KEY header for authentication.


Template-Specific Endpoints

These endpoints are available on all five template controllers listed above (substitute the appropriate base path).

Generate Document

POST /{base-path}/{id}/generate-document

Generates a document from the template using the supplied data, and returns it as raw bytes, base64-encoded JSON, or routes it to the archive output channel (depending on outputMode).

Parameters

Name Type In Required Description
id integer (long) path Yes Template resource ID
X-API-KEY string header Yes API authentication key

Request Body

multipart/form-data:

Part Type Required Description
data file No Input data file to merge with the template
params JSON Yes GenerationParams object (see schema below)

GenerationParams schema (extends DataParams):

Field Type Required Default Description
name string No Output file name
outputFormat string (enum) No PDF Output format. See OutputFormat values
outputMode string (enum) No RAW Output mode. See OutputMode values
data object No Key-value map of template variables
sampleUUID string (UUID) No UUID of sample data to use
resourceType string (enum) No Resource type hint

OutputFormat values:

Value Content-Type Description
PDF application/pdf Generate as PDF
HTML text/html Generate as HTML
RAW application/octet-stream Generate in native/raw format

OutputMode values:

Value Description
RAW Return document bytes directly in the HTTP response
BASE64 Return document as base64-encoded string in JSON
ARCHIVE Route to the archive output channel (no document returned in response)

Example params JSON:

{
  "name": "invoice-2024.pdf",
  "outputFormat": "PDF",
  "outputMode": "RAW",
  "data": {
    "customerName": "Acme Corp",
    "invoiceNumber": "INV-2024-001",
    "amount": 1250.00
  }
}

Response

Status Description
200 OK Document bytes (when outputMode=RAW) or GenerationResult JSON (when outputMode=BASE64)
200 OK Empty body (when outputMode=ARCHIVE)

GenerationResult schema (BASE64 mode):

{
  "document": "<base64-encoded document content>",
  "data": null,
  "metadata": {
    "uid": "abc123",
    "name": "invoice-2024.pdf",
    "fileName": "invoice-2024.pdf",
    "contentType": "application/pdf",
    "outputMode": "BASE64"
  }
}

Error response (400):

{
  "status": 400,
  "message": "Template variable 'customerName' is required but was not provided"
}

Code Examples

package main

import (
    "bytes"
    "fmt"
    "io"
    "mime/multipart"
    "net/http"
    "os"
    "strings"
)

func main() {
    apiKey  := "your-api-key"
    baseURL := "https://your-comfly-instance.com"
    templateID := "42"

    params := `{
        "name": "invoice-2024.pdf",
        "outputFormat": "PDF",
        "outputMode": "RAW",
        "data": {"customerName": "Acme Corp", "invoiceNumber": "INV-2024-001"}
    }`

    var buf bytes.Buffer
    w := multipart.NewWriter(&buf)

    // Optional data file
    if _, err := os.Stat("data.xml"); err == nil {
        fw, _ := w.CreateFormFile("data", "data.xml")
        f, _ := os.Open("data.xml")
        defer f.Close()
        io.Copy(fw, f)
    }

    pw, _ := w.CreateFormField("params")
    io.Copy(pw, strings.NewReader(params))
    w.Close()

    url := fmt.Sprintf("%s/api/templates/%s/generate-document", baseURL, templateID)
    req, _ := http.NewRequest("POST", url, &buf)
    req.Header.Set("Content-Type", w.FormDataContentType())
    req.Header.Set("X-API-KEY", apiKey)

    resp, err := http.DefaultClient.Do(req)
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()

    if resp.StatusCode == http.StatusOK {
        out, _ := os.Create("output.pdf")
        defer out.Close()
        io.Copy(out, resp.Body)
        fmt.Println("Document saved to output.pdf")
    } else {
        body, _ := io.ReadAll(resp.Body)
        fmt.Printf("Error %d: %s\n", resp.StatusCode, string(body))
    }
}
import java.io.*;
import java.net.URI;
import java.net.http.*;
import java.nio.file.*;

public class GenerateDocument {
    public static void main(String[] args) throws Exception {
        String boundary = "----Boundary" + System.currentTimeMillis();
        String params = """
                {
                    "name": "invoice-2024.pdf",
                    "outputFormat": "PDF",
                    "outputMode": "RAW",
                    "data": {"customerName": "Acme Corp"}
                }
                """;

        byte[] paramsHeader = ("--" + boundary + "\r\n"
                + "Content-Disposition: form-data; name=\"params\"\r\n"
                + "Content-Type: application/json\r\n\r\n").getBytes();
        byte[] paramsBody   = params.getBytes();
        byte[] footer       = ("\r\n--" + boundary + "--\r\n").getBytes();

        int len = paramsHeader.length + paramsBody.length + footer.length;
        byte[] body = new byte[len];
        int pos = 0;
        for (byte[] part : new byte[][]{paramsHeader, paramsBody, footer}) {
            System.arraycopy(part, 0, body, pos, part.length);
            pos += part.length;
        }

        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(
                    "https://your-comfly-instance.com/api/templates/42/generate-document"))
                .header("Content-Type", "multipart/form-data; boundary=" + boundary)
                .header("X-API-KEY", "your-api-key")
                .POST(HttpRequest.BodyPublishers.ofByteArray(body))
                .build();

        HttpResponse<byte[]> response = client.send(request,
                HttpResponse.BodyHandlers.ofByteArray());

        if (response.statusCode() == 200) {
            Files.write(Path.of("output.pdf"), response.body());
            System.out.println("Document saved to output.pdf");
        } else {
            System.err.println("Error " + response.statusCode());
        }
    }
}
import json
import requests

api_key   = "your-api-key"
base_url  = "https://your-comfly-instance.com"
template_id = 42

params = {
    "name": "invoice-2024.pdf",
    "outputFormat": "PDF",
    "outputMode": "RAW",
    "data": {"customerName": "Acme Corp", "invoiceNumber": "INV-2024-001"}
}

url = f"{base_url}/api/templates/{template_id}/generate-document"
files = {
    "params": (None, json.dumps(params), "application/json"),
    # Optionally: "data": ("data.xml", open("data.xml", "rb"), "application/xml"),
}

try:
    response = requests.post(url, files=files, headers={"X-API-KEY": api_key})
    response.raise_for_status()

    with open("output.pdf", "wb") as f:
        f.write(response.content)
    print("Document saved to output.pdf")
except requests.HTTPError as e:
    print(f"Error {e.response.status_code}: {e.response.text}")
<?php

$apiKey     = 'your-api-key';
$baseUrl    = 'https://your-comfly-instance.com';
$templateId = 42;

$params = json_encode([
    'name'         => 'invoice-2024.pdf',
    'outputFormat' => 'PDF',
    'outputMode'   => 'RAW',
    'data'         => ['customerName' => 'Acme Corp'],
]);

$boundary = '----Boundary' . uniqid();

$body  = "--{$boundary}\r\n";
$body .= "Content-Disposition: form-data; name=\"params\"\r\n";
$body .= "Content-Type: application/json\r\n\r\n";
$body .= $params . "\r\n";
$body .= "--{$boundary}--\r\n";

$ch = curl_init("{$baseUrl}/api/templates/{$templateId}/generate-document");
curl_setopt_array($ch, [
    CURLOPT_POST           => true,
    CURLOPT_POSTFIELDS     => $body,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => [
        "Content-Type: multipart/form-data; boundary={$boundary}",
        "X-API-KEY: {$apiKey}",
    ],
]);

$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($httpCode === 200) {
    file_put_contents('output.pdf', $response);
    echo "Document saved to output.pdf\n";
} else {
    echo "Error {$httpCode}: {$response}\n";
}
using System;
using System.IO;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        var apiKey     = "your-api-key";
        var baseUrl    = "https://your-comfly-instance.com";
        var templateId = 42;

        var paramsObj = new
        {
            name         = "invoice-2024.pdf",
            outputFormat = "PDF",
            outputMode   = "RAW",
            data         = new { customerName = "Acme Corp" }
        };

        using var client = new HttpClient();
        client.DefaultRequestHeaders.Add("X-API-KEY", apiKey);

        var multipart = new MultipartFormDataContent();
        multipart.Add(
            new StringContent(JsonSerializer.Serialize(paramsObj),
                Encoding.UTF8, "application/json"),
            "params");

        var response = await client.PostAsync(
            $"{baseUrl}/api/templates/{templateId}/generate-document", multipart);

        if (response.IsSuccessStatusCode)
        {
            var bytes = await response.Content.ReadAsByteArrayAsync();
            await File.WriteAllBytesAsync("output.pdf", bytes);
            Console.WriteLine("Document saved to output.pdf");
        }
        else
        {
            var body = await response.Content.ReadAsStringAsync();
            Console.Error.WriteLine($"Error {(int)response.StatusCode}: {body}");
        }
    }
}
require 'net/http'
require 'json'
require 'uri'

api_key     = 'your-api-key'
base_url    = 'https://your-comfly-instance.com'
template_id = 42

params = JSON.generate(
  name:         'invoice-2024.pdf',
  outputFormat: 'PDF',
  outputMode:   'RAW',
  data:         { customerName: 'Acme Corp' }
)

boundary = "----Boundary#{Time.now.to_i}"
body  = "--#{boundary}\r\n"
body += "Content-Disposition: form-data; name=\"params\"\r\n"
body += "Content-Type: application/json\r\n\r\n"
body += "#{params}\r\n"
body += "--#{boundary}--\r\n"

uri  = URI("#{base_url}/api/templates/#{template_id}/generate-document")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = uri.scheme == 'https'

request = Net::HTTP::Post.new(uri)
request['Content-Type'] = "multipart/form-data; boundary=#{boundary}"
request['X-API-KEY']    = api_key
request.body             = body

response = http.request(request)
if response.code.to_i == 200
  File.binwrite('output.pdf', response.body)
  puts 'Document saved to output.pdf'
else
  warn "Error #{response.code}: #{response.body}"
end

Generate Document Asynchronously

POST /{base-path}/{id}/generate-document-async

Starts asynchronous document generation. Returns a job ID immediately. The generated document is delivered via the callback URL when complete.

Parameters

Name Type In Required Description
id integer (long) path Yes Template resource ID
X-API-KEY string header Yes API authentication key

Request Body

multipart/form-data:

Part Type Required Description
data file No Input data file
params JSON Yes AsyncGenerationParams object

AsyncGenerationParams schema (extends GenerationParams):

All fields from GenerationParams plus:

Field Type Required Description
callback object No Callback configuration for async notification
callback.callbackUrl string Yes (if callback set) URL to POST the result to
callback.queryParams object No Additional query parameters to include in the callback request
callback.headers object No Additional headers to include in the callback request

Example params JSON:

{
  "name": "report-2024.pdf",
  "outputFormat": "PDF",
  "outputMode": "RAW",
  "data": {"month": "January", "year": 2024},
  "callback": {
    "callbackUrl": "https://my-app.example.com/webhook/document-ready",
    "queryParams": {"jobRef": "JOB-001"},
    "headers": {"Authorization": "Bearer my-webhook-token"}
  }
}

Response

Status Description
202 Accepted Job accepted; returns job ID (long)
400 Bad Request Invalid parameters

Example response:

12345

Code Examples

package main

import (
    "bytes"
    "fmt"
    "io"
    "mime/multipart"
    "net/http"
    "strings"
)

func main() {
    apiKey     := "your-api-key"
    baseURL    := "https://your-comfly-instance.com"
    templateID := "42"

    params := `{
        "name": "report-2024.pdf",
        "outputFormat": "PDF",
        "outputMode": "RAW",
        "data": {"month": "January"},
        "callback": {
            "callbackUrl": "https://my-app.example.com/webhook/document-ready"
        }
    }`

    var buf bytes.Buffer
    w := multipart.NewWriter(&buf)
    pw, _ := w.CreateFormField("params")
    io.Copy(pw, strings.NewReader(params))
    w.Close()

    url := fmt.Sprintf("%s/api/templates/%s/generate-document-async", baseURL, templateID)
    req, _ := http.NewRequest("POST", url, &buf)
    req.Header.Set("Content-Type", w.FormDataContentType())
    req.Header.Set("X-API-KEY", apiKey)

    resp, err := http.DefaultClient.Do(req)
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()

    if resp.StatusCode == http.StatusAccepted {
        jobID, _ := io.ReadAll(resp.Body)
        fmt.Printf("Job accepted, ID: %s\n", string(jobID))
    } else {
        body, _ := io.ReadAll(resp.Body)
        fmt.Printf("Error %d: %s\n", resp.StatusCode, string(body))
    }
}
import java.net.URI;
import java.net.http.*;

public class GenerateDocumentAsync {
    public static void main(String[] args) throws Exception {
        String boundary = "----Boundary" + System.currentTimeMillis();
        String params = """
                {
                    "name": "report-2024.pdf",
                    "outputFormat": "PDF",
                    "outputMode": "RAW",
                    "data": {"month": "January"},
                    "callback": {
                        "callbackUrl": "https://my-app.example.com/webhook/ready"
                    }
                }
                """;
        byte[] bodyBytes = ("--" + boundary + "\r\n"
                + "Content-Disposition: form-data; name=\"params\"\r\n"
                + "Content-Type: application/json\r\n\r\n"
                + params + "\r\n--" + boundary + "--\r\n").getBytes();

        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(
                    "https://your-comfly-instance.com/api/templates/42/generate-document-async"))
                .header("Content-Type", "multipart/form-data; boundary=" + boundary)
                .header("X-API-KEY", "your-api-key")
                .POST(HttpRequest.BodyPublishers.ofByteArray(bodyBytes))
                .build();

        HttpResponse<String> response = client.send(request,
                HttpResponse.BodyHandlers.ofString());

        if (response.statusCode() == 202) {
            System.out.println("Job ID: " + response.body());
        } else {
            System.err.println("Error " + response.statusCode() + ": " + response.body());
        }
    }
}
import json
import requests

api_key     = "your-api-key"
template_id = 42

params = {
    "name": "report-2024.pdf",
    "outputFormat": "PDF",
    "outputMode": "RAW",
    "data": {"month": "January"},
    "callback": {
        "callbackUrl": "https://my-app.example.com/webhook/document-ready"
    }
}

response = requests.post(
    f"https://your-comfly-instance.com/api/templates/{template_id}/generate-document-async",
    files={"params": (None, json.dumps(params), "application/json")},
    headers={"X-API-KEY": api_key}
)

if response.status_code == 202:
    print(f"Job ID: {response.text}")
else:
    print(f"Error {response.status_code}: {response.text}")
<?php
$params = json_encode([
    'name'         => 'report-2024.pdf',
    'outputFormat' => 'PDF',
    'outputMode'   => 'RAW',
    'data'         => ['month' => 'January'],
    'callback'     => ['callbackUrl' => 'https://my-app.example.com/webhook/ready'],
]);

$boundary = '----Boundary' . uniqid();
$body  = "--{$boundary}\r\nContent-Disposition: form-data; name=\"params\"\r\n";
$body .= "Content-Type: application/json\r\n\r\n{$params}\r\n--{$boundary}--\r\n";

$ch = curl_init('https://your-comfly-instance.com/api/templates/42/generate-document-async');
curl_setopt_array($ch, [
    CURLOPT_POST           => true,
    CURLOPT_POSTFIELDS     => $body,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => [
        "Content-Type: multipart/form-data; boundary={$boundary}",
        'X-API-KEY: your-api-key',
    ],
]);
$response = curl_exec($ch);
$code     = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $code == 202 ? "Job ID: {$response}\n" : "Error {$code}: {$response}\n";
using System;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

class Program {
    static async Task Main() {
        var paramsObj = new {
            name = "report-2024.pdf", outputFormat = "PDF", outputMode = "RAW",
            data = new { month = "January" },
            callback = new { callbackUrl = "https://my-app.example.com/webhook/ready" }
        };

        using var client = new HttpClient();
        client.DefaultRequestHeaders.Add("X-API-KEY", "your-api-key");

        var multipart = new MultipartFormDataContent();
        multipart.Add(
            new StringContent(JsonSerializer.Serialize(paramsObj),
                Encoding.UTF8, "application/json"), "params");

        var response = await client.PostAsync(
            "https://your-comfly-instance.com/api/templates/42/generate-document-async",
            multipart);

        if (response.StatusCode == System.Net.HttpStatusCode.Accepted)
            Console.WriteLine("Job ID: " + await response.Content.ReadAsStringAsync());
        else
            Console.Error.WriteLine($"Error {(int)response.StatusCode}");
    }
}
require 'net/http'
require 'json'

params = JSON.generate(
  name: 'report-2024.pdf', outputFormat: 'PDF', outputMode: 'RAW',
  data: { month: 'January' },
  callback: { callbackUrl: 'https://my-app.example.com/webhook/ready' }
)

boundary = "----Boundary#{Time.now.to_i}"
body = "--#{boundary}\r\nContent-Disposition: form-data; name=\"params\"\r\n" \
       "Content-Type: application/json\r\n\r\n#{params}\r\n--#{boundary}--\r\n"

uri = URI('https://your-comfly-instance.com/api/templates/42/generate-document-async')
req = Net::HTTP::Post.new(uri)
req['Content-Type'] = "multipart/form-data; boundary=#{boundary}"
req['X-API-KEY']    = 'your-api-key'
req.body             = body

res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |h| h.request(req) }
res.code.to_i == 202 ? puts("Job ID: #{res.body}") : warn("Error #{res.code}: #{res.body}")

Deliver Document

POST /{base-path}/{id}/deliver-document

Generates a document and immediately delivers it to a configured output channel (file, printer, SMTP, etc.).

Parameters

Name Type In Required Description
id integer (long) path Yes Template resource ID
X-API-KEY string header Yes API authentication key

Request Body

multipart/form-data:

Part Type Required Description
data file No Input data file
params JSON Yes DeliveryParams object

DeliveryParams schema (extends DataParams):

Field Type Required Description
outputChannelType string (enum) Yes Target output channel. See OutputChannelType
data object No Key-value map of template variables
sampleUUID string (UUID) No UUID of sample data to use
resourceType string (enum) No Resource type hint

Response

Status Description
200 OK Document delivered successfully
400 Bad Request Delivery failed; returns error JSON

Error response (400):

{
  "status": 400,
  "message": "Output channel not configured"
}

Code Examples

package main

import (
    "bytes"
    "fmt"
    "io"
    "mime/multipart"
    "net/http"
    "strings"
)

func main() {
    apiKey     := "your-api-key"
    baseURL    := "https://your-comfly-instance.com"
    templateID := "42"

    params := `{
        "outputChannelType": "SMTP",
        "data": {"recipient": "john@example.com", "subject": "Your Invoice"}
    }`

    var buf bytes.Buffer
    w := multipart.NewWriter(&buf)
    pw, _ := w.CreateFormField("params")
    io.Copy(pw, strings.NewReader(params))
    w.Close()

    url := fmt.Sprintf("%s/api/templates/%s/deliver-document", baseURL, templateID)
    req, _ := http.NewRequest("POST", url, &buf)
    req.Header.Set("Content-Type", w.FormDataContentType())
    req.Header.Set("X-API-KEY", apiKey)

    resp, err := http.DefaultClient.Do(req)
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()

    if resp.StatusCode == http.StatusOK {
        fmt.Println("Document delivered")
    } else {
        body, _ := io.ReadAll(resp.Body)
        fmt.Printf("Error %d: %s\n", resp.StatusCode, string(body))
    }
}
import java.net.URI;
import java.net.http.*;

public class DeliverDocument {
    public static void main(String[] args) throws Exception {
        String boundary = "----Boundary" + System.currentTimeMillis();
        String params = "{\"outputChannelType\":\"SMTP\","
                + "\"data\":{\"recipient\":\"john@example.com\"}}";
        byte[] bodyBytes = ("--" + boundary + "\r\n"
                + "Content-Disposition: form-data; name=\"params\"\r\n"
                + "Content-Type: application/json\r\n\r\n"
                + params + "\r\n--" + boundary + "--\r\n").getBytes();

        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(
                    "https://your-comfly-instance.com/api/templates/42/deliver-document"))
                .header("Content-Type", "multipart/form-data; boundary=" + boundary)
                .header("X-API-KEY", "your-api-key")
                .POST(HttpRequest.BodyPublishers.ofByteArray(bodyBytes))
                .build();

        HttpResponse<String> response = client.send(request,
                HttpResponse.BodyHandlers.ofString());
        System.out.println(response.statusCode() == 200
            ? "Delivered" : "Error: " + response.body());
    }
}
import json
import requests

params = {
    "outputChannelType": "SMTP",
    "data": {"recipient": "john@example.com", "subject": "Your Invoice"}
}

response = requests.post(
    "https://your-comfly-instance.com/api/templates/42/deliver-document",
    files={"params": (None, json.dumps(params), "application/json")},
    headers={"X-API-KEY": "your-api-key"}
)
print("Delivered" if response.ok else f"Error {response.status_code}: {response.text}")
<?php
$params   = json_encode(['outputChannelType' => 'SMTP',
                         'data' => ['recipient' => 'john@example.com']]);
$boundary = '----Boundary' . uniqid();
$body     = "--{$boundary}\r\nContent-Disposition: form-data; name=\"params\"\r\n"
          . "Content-Type: application/json\r\n\r\n{$params}\r\n--{$boundary}--\r\n";

$ch = curl_init('https://your-comfly-instance.com/api/templates/42/deliver-document');
curl_setopt_array($ch, [
    CURLOPT_POST           => true,
    CURLOPT_POSTFIELDS     => $body,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => [
        "Content-Type: multipart/form-data; boundary={$boundary}",
        'X-API-KEY: your-api-key',
    ],
]);
$response = curl_exec($ch);
$code     = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $code === 200 ? "Delivered\n" : "Error {$code}: {$response}\n";
using System;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

class Program {
    static async Task Main() {
        var paramsObj = new {
            outputChannelType = "SMTP",
            data = new { recipient = "john@example.com" }
        };
        using var client = new HttpClient();
        client.DefaultRequestHeaders.Add("X-API-KEY", "your-api-key");

        var mp = new MultipartFormDataContent();
        mp.Add(new StringContent(JsonSerializer.Serialize(paramsObj),
            Encoding.UTF8, "application/json"), "params");

        var response = await client.PostAsync(
            "https://your-comfly-instance.com/api/templates/42/deliver-document", mp);
        Console.WriteLine(response.IsSuccessStatusCode
            ? "Delivered" : $"Error {(int)response.StatusCode}");
    }
}
require 'net/http'
require 'json'

params   = JSON.generate(outputChannelType: 'SMTP',
                          data: { recipient: 'john@example.com' })
boundary = "----Boundary#{Time.now.to_i}"
body     = "--#{boundary}\r\nContent-Disposition: form-data; name=\"params\"\r\n" \
           "Content-Type: application/json\r\n\r\n#{params}\r\n--#{boundary}--\r\n"

uri = URI('https://your-comfly-instance.com/api/templates/42/deliver-document')
req = Net::HTTP::Post.new(uri)
req['Content-Type'] = "multipart/form-data; boundary=#{boundary}"
req['X-API-KEY']    = 'your-api-key'
req.body             = body

res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |h| h.request(req) }
puts res.code.to_i == 200 ? 'Delivered' : "Error #{res.code}: #{res.body}"

Get PDF Preview

GET /{base-path}/{id}/preview/{dummyFileName}

Generates a PDF preview of the template. Optionally stores the first page as a thumbnail.

Note

This endpoint is considered legacy. Prefer POST /{id}/generate-document with outputFormat=PDF.

Parameters

Name Type In Required Description
id integer (long) path Yes Template resource ID
dummyFileName string path Yes Filename hint included in the Content-Disposition header
dataId integer (long) query No ID of sample data to use for preview
inputChannelConfigId integer (long) query No ID of input channel configuration to use
setThumbnail boolean query No If true, stores the first page as thumbnail on the resource
X-API-KEY string header Yes API authentication key

Response

Status Description
200 OK PDF bytes with Content-Type: application/pdf
204 No Content Template produced no output

Code Examples

package main

import (
    "fmt"
    "io"
    "net/http"
    "os"
)

func main() {
    req, _ := http.NewRequest("GET",
        "https://your-comfly-instance.com/api/templates/42/preview/preview.pdf?setThumbnail=false",
        nil)
    req.Header.Set("X-API-KEY", "your-api-key")

    resp, err := http.DefaultClient.Do(req)
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()

    if resp.StatusCode == http.StatusOK {
        f, _ := os.Create("preview.pdf")
        defer f.Close()
        io.Copy(f, resp.Body)
        fmt.Println("Preview saved")
    } else {
        fmt.Printf("Status: %d\n", resp.StatusCode)
    }
}
import java.net.URI;
import java.net.http.*;
import java.nio.file.*;

public class GetPreview {
    public static void main(String[] args) throws Exception {
        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(
                    "https://your-comfly-instance.com/api/templates/42/preview/preview.pdf"))
                .header("X-API-KEY", "your-api-key")
                .GET()
                .build();
        HttpResponse<byte[]> response = client.send(request,
                HttpResponse.BodyHandlers.ofByteArray());
        if (response.statusCode() == 200)
            Files.write(Path.of("preview.pdf"), response.body());
    }
}
import requests

response = requests.get(
    "https://your-comfly-instance.com/api/templates/42/preview/preview.pdf",
    headers={"X-API-KEY": "your-api-key"}
)
if response.status_code == 200:
    with open("preview.pdf", "wb") as f:
        f.write(response.content)
    print("Preview saved")
<?php
$ch = curl_init(
    'https://your-comfly-instance.com/api/templates/42/preview/preview.pdf');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['X-API-KEY: your-api-key'],
]);
$pdf = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($code === 200) file_put_contents('preview.pdf', $pdf);
using System.IO;
using System.Net.Http;

using var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-API-KEY", "your-api-key");
var bytes = await client.GetByteArrayAsync(
    "https://your-comfly-instance.com/api/templates/42/preview/preview.pdf");
await File.WriteAllBytesAsync("preview.pdf", bytes);
require 'net/http'

uri = URI('https://your-comfly-instance.com/api/templates/42/preview/preview.pdf')
req = Net::HTTP::Get.new(uri)
req['X-API-KEY'] = 'your-api-key'
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |h| h.request(req) }
File.binwrite('preview.pdf', res.body) if res.code.to_i == 200