Developer Reference

API Reference

Generate production-ready PDF417 barcodes via a single POST endpoint. Parse a US or Canadian driver's-license PDF417 into clean JSON with one call, including privacy-safe age and expiry checks when `redactPII` is enabled.

API is live at POST /api/generate

Quickstart

No API key required for development. Send a JSON POST to /api/generate with a payload field:

curl -sS -X POST http://127.0.0.1:5055/api/generate \
  -H "Content-Type: application/json" \
  -d '{"payload": "HELLO PDF417"}' \
  | python3 -m json.tool

Decode the base64 PNG and save to disk:

curl -sS -X POST http://127.0.0.1:5055/api/generate \
  -H "Content-Type: application/json" \
  -d '{"payload": "HELLO PDF417"}' \
  | python3 -c "
import sys, json, base64
data = json.load(sys.stdin)
open('barcode.png', 'wb').write(base64.b64decode(data['pngBase64']))
print('Saved barcode.png')
"

Endpoint

POST /api/generate

Accepts Content-Type: application/json. Returns application/json. Maximum request body: 512 KB.

Request schema

All fields except payload are optional and fall back to the listed defaults.

Field Type Default Range Description
payload required string 1–20,000 chars The text or data string to encode into the barcode symbol.
columns integer 6 1–30 Number of data columns. More columns = wider barcode and fewer rows.
errorCorrection integer 2 0–8 PDF417 error correction level. Higher values add redundancy and increase symbol size. Level 2 is suitable for most print use cases.
moduleWidth integer 3 1–50 Width of the narrowest bar or space in pixels. Increase for larger print dimensions.
rowHeight integer 9 1–200 Height of each row in pixels. ISO/IEC 15438 recommends a minimum row height of 3× module width for reliable scanning.
padding integer 20 0–500 Quiet zone padding in pixels applied uniformly to all four sides.
foreground string #000000 CSS hex Bar color as a CSS hex string. Must provide sufficient contrast with the background for reliable scanning.
background string #FFFFFF CSS hex or transparent Space color as a CSS hex string. Use transparent for a transparent PNG with RGBA channel output.
standard string pdf417 pdf417 Barcode standard. Only pdf417 (ISO/IEC 15438) is currently supported.

Full request example

{
  "payload": "SHIPMENT-001\nDEST: WAREHOUSE-B\nSKU: 4921-AX",
  "columns": 6,
  "errorCorrection": 2,
  "moduleWidth": 3,
  "rowHeight": 9,
  "padding": 20,
  "foreground": "#000000",
  "background": "transparent"
}

Response schema

Successful responses return HTTP 200 with the following JSON body:

{
  "pngBase64": "iVBORw0KGgoAAAANSUhEUg...",
  "info": {
    "standard": "PDF417 (ISO/IEC 15438)",
    "columns": 6,
    "rows": 3,
    "moduleWidth": 3,
    "rowHeight": 9,
    "errorCorrectionLevel": 2,
    "errorCorrectionCodewords": 8,
    "padding": 20,
    "moduleSize": { "width": 171, "height": 3 },
    "imageSize": { "width": 553, "height": 67 },
    "bytes": 618,
    "mode": "RGBA"
  }
}
Field Type Description
pngBase64 string Base64-encoded PNG image bytes. Decode with base64.b64decode() or equivalent.
info.rows integer Number of rows in the generated symbol.
info.columns integer Number of data columns used.
info.errorCorrectionLevel integer Error correction level applied (0–8).
info.errorCorrectionCodewords integer Number of error-correction codewords implied by the selected level.
info.moduleSize object Barcode symbol size before pixel scaling and padding.
info.imageSize object Output PNG dimensions as width and height.
info.bytes integer PNG file size in bytes.
info.mode string RGBA when background is transparent; RGB otherwise.

Response headers

Header Description
X-RateLimit-Limit Maximum requests allowed per window.
X-RateLimit-Remaining Requests remaining in the current window.
Retry-After Seconds to wait before retrying. Present only on 429 responses.

Error codes

HTTP status Error Cause
400 Payload is required. The payload field was missing or empty.
400 Payload must be 20000 characters or less. Payload exceeds the 20,000-character limit.
400 <field> must be an integer. A numeric parameter was supplied as a non-integer.
400 <field> must be at least <n>. A parameter was below the allowed minimum.
400 <field> must be at most <n>. A parameter exceeded the allowed maximum.
413 Request body too large The request body exceeded 512 KB.
429 Rate limit exceeded. Too many requests from this IP in the current window. Check Retry-After.

Error response body

// HTTP 400
{ "error": "Payload is required." }

// HTTP 429
{
  "error": "Rate limit exceeded.",
  "limit": 60,
  "windowSeconds": 60,
  "retryAfterSeconds": 14
}

Rate limits

The API applies a sliding-window rate limit keyed by client IP address. When the limit is exceeded the server responds with HTTP 429 and a Retry-After header.

Setting Default Override via
Max requests per window 60 PDF417_RATE_LIMIT_MAX_REQUESTS
Window duration 60 seconds PDF417_RATE_LIMIT_WINDOW_SECONDS

API plan customers will have higher limits enforced via API key in a future release.

Code examples

cURL

# Basic generation — save PNG to disk
curl -sS -X POST http://127.0.0.1:5055/api/generate \
  -H "Content-Type: application/json" \
  -d '{
    "payload": "ORDER-9821\nSKU: XR-440\nQTY: 12",
    "columns": 6,
    "errorCorrection": 2,
    "moduleWidth": 3,
    "rowHeight": 9,
    "padding": 20
  }' | python3 -c "
import sys, json, base64
d = json.load(sys.stdin)
open('barcode.png','wb').write(base64.b64decode(d['pngBase64']))
print('rows:', d['info']['rows'], '| size:', d['info']['imageSize']['width'], 'x', d['info']['imageSize']['height'])
"

# Transparent background (RGBA PNG)
curl -sS -X POST http://127.0.0.1:5055/api/generate \
  -H "Content-Type: application/json" \
  -d '{"payload": "TICKET-EVENT-2026", "background": "transparent"}' \
  | python3 -c "
import sys, json, base64
open('ticket.png','wb').write(base64.b64decode(json.load(sys.stdin)['pngBase64']))
print('Saved ticket.png')
"

Python

import requests, base64
from pathlib import Path

API_URL = "http://127.0.0.1:5055/api/generate"

def generate_barcode(payload, *, output="barcode.png", **kwargs):
    """Generate a PDF417 barcode PNG and save it to disk."""
    resp = requests.post(
        API_URL,
        json={"payload": payload, **kwargs},
        timeout=15,
    )
    resp.raise_for_status()
    data = resp.json()
    Path(output).write_bytes(base64.b64decode(data["pngBase64"]))
    return data["info"]

# Basic
info = generate_barcode("SHIPMENT-001\nDEST: WAREHOUSE-B", output="shipment.png")
print(f"Generated: {info['imageSize']['width']}x{info['imageSize']['height']}px, {info['rows']} rows")

# Transparent PNG
info = generate_barcode("TICKET-EVENT-2026", background="transparent", output="ticket.png")
print(f"Mode: {info['mode']}")  # RGBA

# Batch from list
for i, item in enumerate(["ORDER-001", "ORDER-002", "ORDER-003"]):
    generate_barcode(item, output=f"barcode_{i:04d}.png")
    print(f"Saved barcode_{i:04d}.png")

JavaScript (fetch)

const API_URL = 'http://127.0.0.1:5055/api/generate';

async function generateBarcode({ payload, columns = 6, errorCorrection = 2,
  moduleWidth = 3, rowHeight = 9, padding = 20, background = '#FFFFFF' }) {
  const resp = await fetch(API_URL, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ payload, columns, errorCorrection,
      moduleWidth, rowHeight, padding, background }),
  });
  if (!resp.ok) {
    const err = await resp.json().catch(() => ({}));
    throw new Error(err.error ?? `HTTP ${resp.status}`);
  }
  return resp.json();
}

// Display in an <img> element
generateBarcode({ payload: 'HELLO PDF417', background: 'transparent' })
  .then(({ pngBase64, info }) => {
    const img = document.getElementById('barcode-preview');
    img.src = `data:image/png;base64,${pngBase64}`;
    console.log(`Generated: ${info.imageSize.width}x${info.imageSize.height}`);
  })
  .catch(console.error);

// Node.js — save to disk
import { writeFileSync } from 'node:fs';
const { pngBase64 } = await generateBarcode({ payload: 'NODE-BATCH-001' });
writeFileSync('barcode.png', Buffer.from(pngBase64, 'base64'));
console.log('Saved barcode.png');

Authentication

The current public API does not require authentication. API key-based auth will be introduced with the paid API plan. When active, pass your key in the Authorization header:

Authorization: Bearer pdf417_live_xxxxxxxxxxxxxxxxxxxx

Development and free-tier usage continues without a key, subject to IP-based rate limits.

AAMVA parser

Parse a US or Canadian driver's-license PDF417 into clean JSON with one call. Header, subfiles, date formats, and validation are handled for you. Use redactPII to age-gate without touching personal data.

Most ID-scanning flows only need the answer to a narrow question: is this person of age, and is the license still valid? The paid AAMVA parser is positioned to return is21Plus, isExpired, and ageYears while masking personal fields.

See AAMVA API pricing →