LabelOps CLI
The zplflow command-line tool lets you manage conversions, async jobs, pipelines, and your account directly from the terminal — no code required.
Availability: Pre-built binaries for Windows, Linux, and macOS on amd64 and arm64 architectures. Published as a single static binary with zero system dependencies.
Installation
Download Pre-built Binary
| Platform | Architecture | Binary |
|---|---|---|
| Linux | amd64 | zplflow_linux_amd64 |
| Linux | arm64 | zplflow_linux_arm64 |
| macOS | amd64 (Intel) | zplflow_darwin_amd64 |
| macOS | arm64 (Apple Silicon) | zplflow_darwin_arm64 |
| Windows | amd64 | zplflow_windows_amd64.exe |
| Windows | arm64 | zplflow_windows_arm64.exe |
Download the appropriate binary from GitHub Releases and place it in your PATH.
Linux / macOS Setup
# Download (replace {version}, {os}, {arch} with your values)
curl -L -o zplflow "https://github.com/zplflow/zplflow/releases/download/v{version}/zplflow_{os}_{arch}"
# Make executable and move to PATH
chmod +x zplflow
sudo mv zplflow /usr/local/bin/
# Verify
zplflow version
Windows Setup
# Download the .exe to a directory in your PATH, e.g. C:\Tools\
# Or install via winget (coming soon):
# Verify
zplflow.exe version
Build from Source
git clone https://github.com/zplflow/zplflow.git
cd zplflow
go build -o zplflow ./cmd/cli
The CLI compiles with CGO_ENABLED=0 — no external dependencies required.
Configuration
The CLI needs your API key to authenticate. Provide it via environment variable or flag:
Environment Variable (Recommended)
export LABELOPS_API_KEY="lb_live_YOUR_KEY"
This keeps the key out of your shell history.
Command-Line Flag
zplflow --api-key lb_live_YOUR_KEY account balance
Useful for one-off commands or scripting with a different key.
API URL
By default the CLI connects to https://api.zplflow. Override with LABELOPS_API_URL or --api-url:
export LABELOPS_API_URL="https://staging-api.zplflow"
Output Format
All commands support three output modes via --output:
| Value | Behavior |
|---|---|
text |
Human-readable key-value output (default) |
json |
Raw API response — ideal for piping to jq |
table |
Aligned columns for list endpoints |
Commands Reference
Contents: Account · Convert · Estimate · Jobs · Pipeline · Version · Shell Completion
Account
zplflow account balance
Get your tenant’s token balance and reservations.
zplflow account balance
Tenant: your-company
Balance: 10,000 tokens
Reserved: 3 tokens
# JSON for scripting
zplflow account balance --output json
{"tenant_id":"your-company","balance":10000,"reserved":3}
Estimate
zplflow estimate
Estimate the token cost of a conversion before running it. No payload analysis — purely parameter-based.
# PDF to ZPL estimate
zplflow estimate --operation pdf_to_zpl --dpi 203 --documents 10
# ZPL to PDF estimate
zplflow estimate --operation zpl_to_pdf --dpmm 8dpmm --documents 5
| Flag | Type | Description |
|---|---|---|
--operation |
string | Required. pdf_to_zpl, zpl_to_pdf, or pipeline_run |
--dpi |
int | DPI for pdf_to_zpl: 203 or 300 |
--max-kb |
int | Max KB for pdf_to_zpl |
--fit |
string | Fit mode: contain, cover, or stretch |
--dpmm |
string | Density for zpl_to_pdf: 8dpmm, 12dpmm, 24dpmm |
--documents |
int | Number of documents (default: 1) |
Convert
Synchronous conversions with inline payloads. No S3, no async — ideal for real-time label printing.
zplflow convert pdf-to-zpl
Convert a PDF file to ZPL text.
# From file, output to stdout
zplflow convert pdf-to-zpl --file shipping.pdf --dpi 203
# Save to file
zplflow convert pdf-to-zpl --file labels.pdf --dpi 300 --save output.zpl
# Read from stdin (pipe)
cat shipping.pdf | zplflow convert pdf-to-zpl --stdin > label.zpl
# With dimensions and fit
zplflow convert pdf-to-zpl --file large.pdf --dpi 203 --width 101.6 --height 152.4 --unit mm --fit contain
| Flag | Type | Default | Description |
|---|---|---|---|
--file |
string | — | Input PDF file path |
--stdin |
bool | false | Read PDF from stdin |
--save |
string | — | Save ZPL to file (default: stdout) |
--dpi |
int | 203 | 203 or 300 |
--max-kb |
int | — | Max output KB per page |
--width |
float | — | Label width |
--height |
float | — | Label height |
--unit |
string | mm | mm or in |
--fit |
string | contain | contain, cover, or stretch |
--allow-degrade |
bool | false | Allow quality degradation |
--compat-mode |
bool | false | Enable compatibility mode |
--idempotency-key |
string | auto | Override auto-generated key |
zplflow convert zpl-to-pdf
Convert a ZPL string to a PDF file.
# From file
zplflow convert zpl-to-pdf --file label.zpl --save output.pdf
# Read from stdin
echo "^XA^FO50,50^ADN,36,20^FDHello^FS^XZ" | zplflow convert zpl-to-pdf --stdin --save hello.pdf
# Custom density and dimensions
zplflow convert zpl-to-pdf --file label.zpl --save out.pdf --dpmm 12dpmm --width 101.6 --height 152.4
| Flag | Type | Default | Description |
|---|---|---|---|
--file |
string | — | Input ZPL file path |
--stdin |
bool | false | Read ZPL from stdin |
--save |
string | — | Required. Output PDF file path |
--dpmm |
string | 8dpmm | 8dpmm, 12dpmm, 24dpmm |
--width |
float | — | Label width |
--height |
float | — | Label height |
--unit |
string | mm | mm or in |
--index |
int | 0 | Label index within ZPL |
--idempotency-key |
string | auto | Override auto-generated key |
Note: PDF output is binary —
--saveis always required. The file path is never written to stdout.
Pipeline
zplflow pipeline apply <pipeline-id>
Apply a pre-defined pipeline transformation to ZPL documents.
# Single ZPL file
zplflow pipeline apply 550e8400-e29b-41d4-a716-446655440000 --zpl-file label.zpl
# Multiple documents via JSON file
zplflow pipeline apply 550e8400-... --json-file batch.json
# Save output to file
zplflow pipeline apply 550e8400-... --zpl-file label.zpl --save transformed.zpl
| Flag | Type | Description |
|---|---|---|
--zpl-file |
string | Single ZPL file to transform |
--json-file |
string | JSON file with array of {"zpl_base64":"..."} documents |
--save |
string | Save output to file (default: stdout) |
--idempotency-key |
string | Override auto-generated key |
The pipeline ID is the first positional argument. Find your pipelines in the Admin UI.
Jobs
Async job management for bulk conversions and large files. The CLI handles the full lifecycle: create → upload → start → poll → download.
zplflow job create
Create and automatically start an async job.
# PDF to ZPL async
zplflow job create --operation pdf_to_zpl --file labels.pdf --dpi 203
# ZPL to PDF async
zplflow job create --operation zpl_to_pdf --file label.zpl
# Pipeline run
zplflow job create --operation pipeline_run --file labels.zpl --pipeline-id 550e8400-...
Job ID: 770e8400-e29b-41d4-a716-446655440000
Status: queued
Tokens Reserved: 2
Monitor: zplflow job wait 770e8400-...
The create command uploads the input file via the presigned S3 URL and starts the job in a single step.
| Flag | Type | Description |
|---|---|---|
--operation |
string | Required. pdf_to_zpl, zpl_to_pdf, or pipeline_run |
--file |
string | Input file path |
--stdin |
bool | Read input from stdin |
--dpi |
int | DPI for pdf_to_zpl |
--max-kb |
int | Max KB for pdf_to_zpl |
--fit |
string | Fit mode: contain, cover, or stretch |
--dpmm |
string | Density for zpl_to_pdf |
--width |
float | Label width |
--height |
float | Label height |
--unit |
string | Unit: mm or in |
--pipeline-id |
string | Required for pipeline_run |
--allow-degrade |
bool | Allow quality degradation |
--compat-mode |
bool | Enable compatibility mode |
--idempotency-key |
string | Override auto-generated key |
zplflow job list
List all async jobs for your tenant.
# Last 10 jobs
zplflow job list
# Filter by status, with table output
zplflow job list --status succeeded --limit 20
# Paginated
zplflow job list --status failed --cursor next-cursor-token
JOB ID STATUS OPERATION
550e8400-e29b-41d4-a716-446655440000 succeeded pdf_to_zpl
660e8400-e29b-41d4-a716-446655440000 failed zpl_to_pdf
| Flag | Type | Default | Description |
|---|---|---|---|
--status |
string | — | Filter: created, queued, running, succeeded, failed, canceled |
--limit |
int | 10 | Max jobs to return |
--cursor |
string | — | Pagination cursor |
zplflow job get <job-id>
Get detailed status and results for a specific job.
zplflow job get 550e8400-e29b-41d4-a716-446655440000
Job ID: 550e8400-e29b-41d4-a716-446655440000
Operation: pdf_to_zpl
Status: succeeded
Tokens: 2 reserved / 2 committed
Results: 1 file(s)
[0] 12,451 bytes application/pdf
URL: https://s3.amazonaws.com/... (expires 2026-01-15T11:00:00Z)
Meta:
DPI: 203
Budget KB: 32
Degraded: false
Tile count: 1
zplflow job start <job-id>
Start a job that is in created state.
zplflow job start 550e8400-...
| Flag | Type | Description |
|---|---|---|
--idempotency-key |
string | Override auto-generated key |
zplflow job cancel <job-id>
Cancel a queued or running job. Reserved tokens are rolled back.
zplflow job cancel 550e8400-...
| Flag | Type | Description |
|---|---|---|
--idempotency-key |
string | Override auto-generated key |
zplflow job wait <job-id>
Poll a job until completion and automatically download the result. The recommended way to handle async jobs.
# Wait for result and save to file
zplflow job wait 550e8400-... --save result.pdf
# Custom timeout (default 5 minutes)
zplflow job wait 550e8400-... --save result.zpl --timeout 10m
# Without --save, prints text results to stdout (use for ZPL output)
zplflow job wait 550e8400-...
Waiting for job 550e8400-... [created] 1s
Waiting for job 550e8400-... [queued] 2s
Waiting for job 550e8400-... [running] 4s
Job succeeded! Saved 12,451 bytes to result.pdf
Polling uses exponential backoff starting at 1 second and capping at 8 seconds.
| Flag | Type | Default | Description |
|---|---|---|---|
--save |
string | — | File to save result to (required for binary output) |
--timeout |
duration | 5m | Max wait time (e.g. 30s, 5m, 1h) |
--interval |
duration | 1s | Initial poll interval |
Shell Completion
Generate tab-completion for your shell.
# Bash
zplflow completion bash > /etc/bash_completion.d/zplflow
# Zsh
zplflow completion zsh > "${fpath[1]}/_zplflow"
# Fish
zplflow completion fish > ~/.config/fish/completions/zplflow.fish
# PowerShell
zplflow completion powershell > zplflow.ps1
Version
zplflow version
zplflow version 1.2.3 (commit: abc1234, built: 2026-01-15T10:00:00Z)
go version go1.25.4 linux/amd64
# Short form — handy for scripting
zplflow version --short
1.2.3
Exit Codes
| Code | Meaning |
|---|---|
0 |
Success |
1 |
API error or invalid parameters |
2 |
Usage error (missing required flag) |
3 |
Authentication error (missing/invalid API key) |
4 |
Network or timeout error |
Use exit codes in scripts:
#!/bin/bash
if zplflow job wait "$JOB_ID" --save result.zpl --timeout 5m; then
echo "Done: $(wc -c < result.zpl) bytes"
else
code=$?
echo "Failed with exit code $code"
fi
Idempotency
All POST commands automatically generate a unique Idempotency-Key (UUID v4) per request. This prevents duplicate operations on network retries.
The generated key is printed to stderr:
Idempotency Key: a1b2c3d4-e5f6-7890-abcd-ef1234567890
To reuse a key for explicit retry control:
zplflow convert pdf-to-zpl --file labels.pdf --idempotency-key my-retry-001
Typical Workflows
Quick Sync Convert
export LABELOPS_API_KEY="lb_live_YOUR_KEY"
# PDF → ZPL (result to stdout)
zplflow convert pdf-to-zpl --file shipping.pdf --dpi 203 > label.zpl
# ZPL → PDF (result to file)
zplflow convert zpl-to-pdf --file label.zpl --save output.pdf
Async Batch Processing
# Step 1: Create and start job
JOB_ID=$(zplflow job create --operation pdf_to_zpl --file labels.pdf --dpi 203 --output json | jq -r '.job_id')
echo "Job: $JOB_ID"
# Step 2: Wait for completion
zplflow job wait "$JOB_ID" --save result.zpl
Pipeline in a CI/CD Pipeline
# Apply pipeline transformation
zplflow pipeline apply "$PIPELINE_ID" --zpl-file label.zpl --save transformed.zpl
# Then convert to PDF for preview
zplflow convert zpl-to-pdf --file transformed.zpl --save preview.pdf
Error Messages
The CLI translates API errors into human-readable messages:
| HTTP | Error Code | CLI Output |
|---|---|---|
| 401 | UNAUTHORIZED |
Invalid API key. Set LABELOPS_API_KEY env var or use --api-key flag. |
| 402 | INSUFFICIENT_TOKENS |
Not enough tokens — ... |
| 403 | FORBIDDEN |
Tenant suspended or access denied. |
| 409 | IDEMPOTENCY_CONFLICT |
Idempotency key conflict — different payload used with the same key. |
| 429 | RATE_LIMITED |
Rate limit exceeded. Try again in a few seconds. |
Security
- The API key is never logged or printed in output
- Use the environment variable (
LABELOPS_API_KEY) to avoid leaking keys in shell history - Presigned S3 URLs are never logged
- Payload content (PDF/ZPL) is never logged
- Gzip compression is transparent: the CLI sends
Accept-Encoding: gzipand compresses large request bodies automatically
Next Steps
- Authentication — Full auth reference
- Conversions — Sync API parameters and pricing
- Jobs API — Async workflow details
- Pipelines — ZPL transformation recipes
- Best Practices — Production integration guide