1. Templates
  2. Generate PDF

Templates

Generate PDF

POST
`/v1/templates/pdf/generate`

Generate custom PDFs with text, barcodes (Code128), QR codes, DataMatrix codes, and lines using explicit x,y positioning. This endpoint is useful for creating shipping labels, asset tags, inventory bin labels, and other custom documents.

Authentication

This endpoint requires authentication with an API key that has the templates:write scope.

Header Value
PX-API-KEY Your API key with templates:write scope
Content-Type application/json

Performance

PDF generation runs in a dedicated worker thread, ensuring non-blocking operation even for complex documents with many elements. The generated PDF is uploaded to cloud storage and a public URL is returned.

Request Body

size string
Page size. Options: A4, letter, 4x6, a6, custom. Default: A4
orientation string
Page orientation. Options: portrait, landscape. Default: portrait
width number
Custom width in points (required if size is custom). Minimum: 72
height number
Custom height in points (required if size is custom). Minimum: 72
filename string
Optional custom filename (without .pdf extension)
raw array (required)
Array of elements to render (1-500 elements)

Page Sizes

Size Dimensions (points) Use Case
A4 595 x 842 Standard documents
letter 612 x 792 US Letter documents
4x6 288 x 432 Shipping labels
a6 298 x 420 Small labels
custom User-defined Custom dimensions required

Note: 72 points = 1 inch. Coordinates use top-left origin with Y increasing downward.

Element Types

Text Element

type string (required)
Set to "text"
x number (required)
X coordinate in points from left edge
y number (required)
Y coordinate in points from top edge
value string
Text content to display
height number
Font size in points. Default: 12
width number
Maximum text width (for clipping). Default: page width
font_family string
Font family: inter (sans-serif, default) or mono (Fira Mono, monospace)
font_weight string
Font weight: light, regular (default), bold, black
align string
Text alignment: left (default), center, right. For center/right, x is the alignment anchor point
color string
Hex color code (e.g., #FF0000). Default: #000000
angle number
Rotation angle in degrees. Default: 0

Code128 Barcode

type string (required)
Set to "code128"
x number (required)
X coordinate in points
y number (required)
Y coordinate in points
value string (required)
Barcode value to encode
height number
Barcode height in points. Default: 40
width number
Barcode width in points
angle number
Rotation angle in degrees. Default: 0

QR Code

type string (required)
Set to "qr"
x number (required)
X coordinate in points
y number (required)
Y coordinate in points
value string (required)
Data to encode (URL, text, etc.)
height number
QR code size in points. Default: 50
width number
QR code width (if different from height)
angle number
Rotation angle in degrees. Default: 0

DataMatrix Code

type string (required)
Set to "matrix"
x number (required)
X coordinate in points
y number (required)
Y coordinate in points
value string (required)
Data to encode
height number
DataMatrix size in points. Default: 50
width number
DataMatrix width (if different from height)
angle number
Rotation angle in degrees. Default: 0

Line

type string (required)
Set to "line"
x number (required)
Starting X coordinate in points
y number (required)
Starting Y coordinate in points
height number
Line thickness in points. Default: 1
width number
Line length in points. Default: 100
color string
Hex color code. Default: #000000
angle number
Line angle in degrees (0 = horizontal). Default: 0

Font Families

Family Description Weights Available
inter Inter (Sans-serif) - Default light, regular, bold, black
mono Fira Mono (Monospace) regular (all weights map to regular)

Use mono for tracking numbers, SKUs, and other codes where character alignment matters.

Text Alignment

Align Description
left Text starts at x position (default behavior)
center Text is centered at x position - useful for centering on page (x = page_width/2)
right Text ends at x position - useful for right-aligned columns

Note: When using center or right alignment, the x coordinate becomes the anchor point for alignment rather than the text starting position.

Example Request - Shipping Label

        const data = {
  size: "4x6",
  orientation: "portrait",
  raw: [
    {
      type: "text",
      x: 20,
      y: 20,
      value: "SHIP TO:",
      height: 10,
      font_family: "inter",
      font_weight: "bold"
    },
    {
      type: "text",
      x: 20,
      y: 35,
      value: "John Smith",
      height: 14,
      font_family: "inter",
      font_weight: "black"
    },
    {
      type: "text",
      x: 20,
      y: 52,
      value: "123 Main Street",
      height: 12,
      font_family: "inter"
    },
    {
      type: "text",
      x: 20,
      y: 67,
      value: "New York, NY 10001",
      height: 12,
      font_family: "inter"
    },
    {
      type: "line",
      x: 20,
      y: 90,
      height: 1,
      width: 248
    },
    {
      type: "text",
      x: 20,
      y: 110,
      value: "1Z999AA10123456784",
      height: 10,
      font_family: "mono"
    },
    {
      type: "code128",
      x: 20,
      y: 125,
      value: "1Z999AA10123456784",
      height: 50,
      width: 248
    },
    {
      type: "qr",
      x: 188,
      y: 200,
      value: "https://track.example.com/1Z999AA10123456784",
      height: 80
    }
  ]
};

const res = await fetch("https://api.packagex.io/v1/templates/pdf/generate", {
  method: "POST",
  headers: {
    "PX-API-KEY": process.env.PX_API_KEY,
    "Content-Type": "application/json",
  },
  body: JSON.stringify(data),
}).then((res) => res.json());

const pdfUrl = res.data.url; // URL to the generated PDF
const filename = res.data.filename; // e.g., "pdf_abc123.pdf"

      

Example Request - Asset Tag with Font Families

        const data = {
  size: "custom",
  width: 144,
  height: 72,
  orientation: "portrait",
  raw: [
    {
      type: "text",
      x: 5,
      y: 8,
      value: "ASSET TAG",
      height: 6,
      font_family: "inter",
      font_weight: "bold"
    },
    {
      type: "text",
      x: 5,
      y: 50,
      value: "AST-001234",
      height: 8,
      font_family: "mono"
    },
    {
      type: "code128",
      x: 5,
      y: 18,
      value: "AST-001234",
      height: 25,
      width: 100
    },
    {
      type: "matrix",
      x: 110,
      y: 18,
      value: "AST-001234",
      height: 30,
      width: 30
    }
  ]
};

const res = await fetch("https://api.packagex.io/v1/templates/pdf/generate", {
  method: "POST",
  headers: {
    "PX-API-KEY": process.env.PX_API_KEY,
    "Content-Type": "application/json",
  },
  body: JSON.stringify(data),
}).then((res) => res.json());

      

Response

        {
  "data": {
    "url": "https://storage.googleapis.com/bucket/org_123/pdf/pdf_abc123.pdf",
    "filename": "pdf_abc123.pdf"
  },
  "message": "PDF generated successfully"
}

      

Partial Success Response

If some elements fail to render but the PDF is still generated:

        {
  "data": {
    "url": "https://storage.googleapis.com/bucket/org_123/pdf/pdf_abc123.pdf",
    "filename": "pdf_abc123.pdf",
    "errors": [
      {
        "index": 2,
        "type": "code128",
        "error": "Invalid barcode value"
      }
    ]
  },
  "message": "PDF generated with 4/5 elements rendered successfully"
}

      

Error Responses

Empty Raw Array (400)

        {
  "errors": [
    {
      "message": "Array must contain at least 1 element(s)",
      "path": ["body", "raw"]
    }
  ]
}

      

Custom Size Missing Dimensions (400)

        {
  "errors": [
    {
      "message": "width and height are required when size is 'custom'"
    }
  ]
}

      

Invalid Color Format (400)

        {
  "errors": [
    {
      "message": "Invalid color format. Use hex code like #FF0000",
      "path": ["body", "raw", 0, "color"]
    }
  ]
}

      

Invalid Font Family (400)

        {
  "errors": [
    {
      "message": "Invalid enum value. Expected 'inter' | 'mono'",
      "path": ["body", "raw", 0, "font_family"]
    }
  ]
}

      

Too Many Elements (400)

        {
  "errors": [
    {
      "message": "Array must contain at most 500 element(s)",
      "path": ["body", "raw"]
    }
  ]
}

      

Example Request - Inventory Bin Label

        const data = {
  size: "custom",
  width: 216,  // 3 inches
  height: 72,  // 1 inch
  orientation: "portrait",
  raw: [
    {
      type: "text",
      x: 10,
      y: 15,
      value: "BIN A-01-03",
      height: 14,
      font_family: "inter",
      font_weight: "black"
    },
    {
      type: "code128",
      x: 10,
      y: 35,
      value: "A-01-03",
      height: 25,
      width: 120
    },
    {
      type: "text",
      x: 140,
      y: 42,
      value: "A-01-03",
      height: 12,
      font_family: "mono"
    }
  ]
};

const res = await fetch("https://api.packagex.io/v1/templates/pdf/generate", {
  method: "POST",
  headers: {
    "PX-API-KEY": process.env.PX_API_KEY,
    "Content-Type": "application/json",
  },
  body: JSON.stringify(data),
}).then((res) => res.json());

      

Example Request - Text Alignment

        const data = {
  size: "A4",
  orientation: "portrait",
  raw: [
    // Left aligned (default) - text starts at x
    {
      type: "text",
      x: 50,
      y: 50,
      value: "Left Aligned",
      height: 18,
      font_family: "inter",
      align: "left"
    },
    // Center aligned - text centered at x (page center = 297.5)
    {
      type: "text",
      x: 297,
      y: 80,
      value: "Center Aligned",
      height: 18,
      font_family: "inter",
      font_weight: "bold",
      align: "center"
    },
    // Right aligned - text ends at x (right margin = 545)
    {
      type: "text",
      x: 545,
      y: 110,
      value: "Right Aligned",
      height: 18,
      font_family: "inter",
      align: "right"
    },
    // Horizontal line to show alignment
    {
      type: "line",
      x: 50,
      y: 130,
      height: 1,
      width: 495
    }
  ]
};

const res = await fetch("https://api.packagex.io/v1/templates/pdf/generate", {
  method: "POST",
  headers: {
    "PX-API-KEY": process.env.PX_API_KEY,
    "Content-Type": "application/json",
  },
  body: JSON.stringify(data),
}).then((res) => res.json());

      

Example Request - Rotated Label Elements

        const data = {
  size: "4x6",
  orientation: "landscape",
  raw: [
    {
      type: "text",
      x: 50,
      y: 100,
      value: "FRAGILE",
      height: 24,
      font_family: "inter",
      font_weight: "black",
      color: "#FF0000",
      angle: -15
    },
    {
      type: "line",
      x: 20,
      y: 150,
      height: 2,
      width: 200,
      color: "#FF0000"
    },
    {
      type: "text",
      x: 50,
      y: 180,
      value: "HANDLE WITH CARE",
      height: 16,
      font_family: "inter",
      font_weight: "bold"
    }
  ]
};

const res = await fetch("https://api.packagex.io/v1/templates/pdf/generate", {
  method: "POST",
  headers: {
    "PX-API-KEY": process.env.PX_API_KEY,
    "Content-Type": "application/json",
  },
  body: JSON.stringify(data),
}).then((res) => res.json());

      

Best Practices

Coordinate System

  • All coordinates are in points (72 points = 1 inch)
  • The origin (0, 0) is at the top-left corner
  • X increases to the right, Y increases downward
  • Elements are positioned by their top-left corner

Element Ordering

Elements are rendered in the order they appear in the raw array. Later elements will appear on top of earlier ones if they overlap.

Font Selection

  • Use inter (default) for general text - it has excellent readability at all sizes
  • Use mono (Fira Mono) for tracking numbers, SKUs, and codes where character alignment is important

Barcode Best Practices

  • Ensure barcode values contain only valid characters for the barcode type
  • Code128 supports alphanumeric characters
  • QR codes can encode URLs, text, or binary data
  • DataMatrix codes are ideal for small spaces with high data density

Performance Tips

  • Keep the number of elements under 100 for optimal performance
  • Use the smallest appropriate page size for your use case
  • Pre-validate barcode values before sending to avoid partial success responses