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

# Render ZPL labels to PDF or PNG with the HTTP API

> Send raw ZPL to the render endpoint and get back a vector PDF or PNG. Try it live in the playground with a ready-made example shipping label.

Caretly exposes a single HTTP endpoint at `https://caretly.dev/render`. Send your ZPL as the raw request body and the response is the rendered label.

## Get an API key

Every request needs an API key. Create one on the **API keys** page of the [console](https://caretly.dev/console). Start with a test key: it's free, and stamps **TEST** on every label. Then store the key in the `ZPL_API_KEY` environment variable:

```bash theme={null}
export ZPL_API_KEY="zpl_test_..."
```

See [Authentication](https://caretly.dev/docs/authentication.md) for live keys, billing and errors.

Click **Try it** to render the example shipping label directly from this page. Paste your key in the authorization field, and set `format` to `png` to preview the label inline.

## Example

```bash theme={null}
curl -X POST "https://caretly.dev/render?format=pdf" \
  -H "Authorization: Bearer $ZPL_API_KEY" \
  -H "Content-Type: text/plain" \
  --data-binary @label.zpl \
  -o label.pdf
```

> [!TIP]
>
> Use `--data-binary` instead of `-d` so curl keeps the newlines in your ZPL intact.

> [!NOTE]
>
> Just trying ZPL? The [playground](https://caretly.dev/playground) renders in your browser without a key. It's free, but stamps **PREVIEW** on every label and PDF.

> **[Authentication](https://caretly.dev/docs/authentication.md)**
>
> Live and test keys, billing per label, safe retries and error codes.

> **[Render many labels at once](https://caretly.dev/docs/multiple-labels.md)**
>
> Send several labels, `^PQ` copies or a batch of ZPL files in one request, optionally gzip-compressed.


## OpenAPI

````yaml openapi.json POST /render
openapi: 3.1.0
info:
  title: Caretly API
  version: 1.0.0
  description: Render ZPL labels to vector PDF or PNG.
servers:
  - url: https://caretly.dev
security: []
paths:
  /render:
    post:
      summary: Render ZPL labels
      description: >-
        Send ZPL and receive the rendered labels. The body is either raw ZPL, or
        `multipart/form-data` with one or more ZPL files. Every `^XA…^XZ`
        becomes a page, and `^PQ` adds copies. A PDF contains every page; a PNG
        is one page, chosen with `page`. Requires an API key. Live keys are
        billed per label; test keys are free and watermark every label with
        TEST.
      operationId: render
      parameters:
        - name: format
          in: query
          required: false
          description: >-
            The output format. `pdf` contains every page; `png` is the single
            page chosen with `page`.
          schema:
            type: string
            enum:
              - pdf
              - png
            default: pdf
        - name: page
          in: query
          required: false
          description: >-
            For `format=png`: the page to render, starting at 1. Pages are
            counted across all files of a multipart request. Out of range
            returns 400.
          schema:
            type: integer
            minimum: 1
            default: 1
        - name: dpmm
          in: query
          required: false
          description: >-
            Printer resolution in dots per millimetre: 6 (152 dpi), 8 (203 dpi),
            12 (300 dpi) or 24 (600 dpi).
          schema:
            type: integer
            enum:
              - 6
              - 8
              - 12
              - 24
            default: 8
        - name: timings
          in: query
          required: false
          description: >-
            Return server-side timings for each stage in a `Server-Timing`
            response header.
          schema:
            type: boolean
        - name: Content-Encoding
          in: header
          required: false
          description: >-
            Set when the request body is compressed. The 100 MiB limit applies
            to the decompressed body.
          schema:
            type: string
            enum:
              - gzip
              - deflate
        - name: Idempotency-Key
          in: header
          required: false
          description: >-
            Any string up to 255 characters, for example an order number. A
            retry with the same API key, `Idempotency-Key`, labels and query
            parameters is billed once; different labels or parameters are billed
            as a new request.
          schema:
            type: string
            maxLength: 255
      requestBody:
        required: true
        description: >-
          Raw ZPL, or several ZPL files as multipart form data. At most 100 MiB
          after decompression.
        content:
          text/plain:
            schema:
              type: string
              description: Raw ZPL. May contain several labels (`^XA…^XZ`).
            example: |
              ^XA
              ^PW800
              ^LL1000

              ^FX --- Outer border ---
              ^FO10,10^GB780,980,4^FS

              ^FX --- Header ---
              ^FO10,10^GB780,80,4^FS
              ^FO30,30^A0N,50,50^FDLABEL SYNTAX^FS
              ^FO600,35^A0N,30,30^FDPRIORITY^FS

              ^FX --- Addresses ---
              ^FO10,90^GB780,160,4^FS
              ^FO30,110^A0N,25,25^FDSENDER: Warehouse 42&43^FS
              ^FO30,140^A0N,25,25^FD123 Industrial AS, Sector 10^FS
              ^FO30,180^A0N,30,30^FDSHIP TO:^FS
              ^FO180,180^A0N,35,35^FDALBINS - CORP HQ^FS
              ^FO180,215^A0N,30,30^FD500 BUSINESS AVE, SUITE 100^FS

              ^FX --- Barcode ---
              ^FO10,250^GB780,200,4^FS
              ^FO100,280^BY4,2,120^BCN,120,Y,N,N^FD123456789012^FS

              ^FX --- QR code ---
              ^FO10,450^GB780,300,4^FS
              ^FO280,480^BQN,2,4^FDQA,https://labelsyntax.com/^FS
              ^FO250,710^A0N,25,25^FDSCAN FOR DETAILS^FS

              ^FX --- Footer ---
              ^FO30,770^A0N,30,30^FDREF: PO-998877^FS
              ^FO30,820^A0N,30,30^FDWEIGHT: 12.5 LBS^FS
              ^FO30,870^A0N,30,30^FDDIMENSIONS: 10x10x10^FS
              ^FO500,870^A0N,20,20^FDGenerated by AS^FS
              ^XZ
          multipart/form-data:
            schema:
              type: object
              properties:
                file:
                  type: array
                  items:
                    type: string
                    format: binary
                  description: >-
                    One or more ZPL files. Every part with a filename, or named
                    `file`, `files` or `zpl`, is a file. Each file is rendered
                    with a fresh printer state, and pages follow upload order.
              required:
                - file
      responses:
        '200':
          description: The rendered labels.
          headers:
            X-Page-Count:
              description: Total number of pages.
              schema:
                type: integer
            X-File-Page-Counts:
              description: >-
                Multipart requests only: pages per file, in upload order, for
                example `2, 1`.
              schema:
                type: string
            Server-Timing:
              description: >-
                With `timings`: duration of each stage in milliseconds (read,
                queue, parse, state, render, encode, total).
              schema:
                type: string
            X-Labels-Billed:
              description: >-
                Labels billed for this request: every page, including `^PQ`
                copies, for a live key; 1 for a PNG; 0 for a test key.
              schema:
                type: integer
            RateLimit-Limit:
              description: >-
                The burst size of your API key's rate limit: how many requests
                it can make at once.
              schema:
                type: integer
            RateLimit-Remaining:
              description: >-
                Requests your API key can still make at once before it is rate
                limited.
              schema:
                type: integer
          content:
            application/pdf:
              schema:
                type: string
                format: binary
            image/png:
              schema:
                type: string
                format: binary
        '400':
          description: >-
            Invalid parameters, a `page` out of range, a multipart request
            without ZPL files, or a corrupt compressed body.
          content:
            text/plain:
              schema:
                type: string
        '401':
          description: >-
            The API key is missing, not valid, expired or revoked. Create or
            renew a key in the console.
          headers:
            WWW-Authenticate:
              description: Always `Bearer realm="zpl"`.
              schema:
                type: string
          content:
            text/plain:
              schema:
                type: string
              example: >-
                An API key is required. Create one at
                https://caretly.dev/console/keys and send it as `Authorization:
                Bearer <key>`.
        '402':
          description: >-
            Billing for the account is not active, so live keys are paused. Test
            keys keep working.
          content:
            text/plain:
              schema:
                type: string
              example: >-
                Billing for this account is not active, so live keys are paused.
                Update it at https://caretly.dev/console/billing; test keys keep
                working.
        '413':
          description: The body is larger than 100 MiB after decompression.
          content:
            text/plain:
              schema:
                type: string
        '415':
          description: >-
            Unsupported `Content-Encoding`. The `Accept-Encoding` response
            header lists the supported ones.
          content:
            text/plain:
              schema:
                type: string
        '429':
          description: >-
            Too many requests for this API key. The rate limit is generous
            (about 50 requests per second with bursts of 200) and stops runaway
            loops. Wait the number of seconds in `Retry-After` and retry. See
            [Rate limits](/authentication#rate-limits).
          headers:
            Retry-After:
              description: Seconds to wait before retrying, rounded up.
              schema:
                type: integer
            RateLimit-Limit:
              description: >-
                The burst size of your API key's rate limit: how many requests
                it can make at once.
              schema:
                type: integer
            RateLimit-Remaining:
              description: >-
                Requests your API key can still make at once before it is rate
                limited.
              schema:
                type: integer
          content:
            text/plain:
              schema:
                type: string
              example: >-
                Too many requests for this API key: the limit is 50 per second,
                with bursts of 200. Retry after 1 s.
      security:
        - bearerAuth: []
        - apiKeyHeader: []
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: >-
        An API key from the [console](https://caretly.dev/console/keys), sent as
        `Authorization: Bearer <key>`. Live keys start with `zpl_live_`, test
        keys with `zpl_test_`.
    apiKeyHeader:
      type: apiKey
      in: header
      name: X-API-Key
      description: >-
        The same API key, sent as `X-API-Key: <key>` instead of the
        `Authorization` header.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.