The address your program posts to

Your program posts the description of one document to one address, under the key of its account, and the finished PDF comes back in the answer.

The call

One address answers, it answers to a POST, and the body is the description of the document you want. The key of your account travels in the usual header.

What may be in a description — the page, the items drawn on it, the fonts, the standard it is written to — is the whole of the API section, and none of it is repeated here.

What a call and its answer are made of
The call that draws a document POST https://hqf-pdf.com/api/v1/render
The shape the body is sent in application/json
What the body holds the description of one document, and nothing else
How the key travels Authorization: Bearer <key>
What a success carries 200 application/pdf
The name the file is offered under Content-Disposition: attachment; filename="document.pdf"
What a refusal carries application/json {"error": "…"}

Every key a description may carry

What travels, and what does not

This address carries the description alone. No file travels beside it: a document drawn here draws on the fonts the service holds, and on nothing sent with the call.

A PDF server running on a machine of your own takes files beside the description, each as a named part of the body. That is a different call, written on the head page of the section.

The same call, twice over

From a shell

The body is the description itself. The answer is the PDF, so write it straight to a file.

curl -X POST https://hqf-pdf.com/api/v1/render \
  -H "Authorization: Bearer $HQF_PDF_KEY" \
  -H "Content-Type: application/json" \
  --data-binary @invoice.json \
  -o invoice.pdf

From Python

A refusal arrives as JSON carrying one sentence, and the status says whether the request is worth sending again.

import json
import pathlib
import requests

description = {
    "standard_fonts": [{"name": "sans", "face": "helvetica"}],
    "items": [
        {
            "type": "text",
            "rect": {"llx": 56, "lly": 700, "urx": "{page_width} - 56", "ury": 780},
            "content": ["Invoice 2026-014"],
            "font": "sans",
            "font_size": 24,
        }
    ],
}

answer = requests.post(
    "https://hqf-pdf.com/api/v1/render",
    headers={"Authorization": f"Bearer {KEY}"},
    json=description,
    timeout=120,
)
if answer.status_code != 200:
    raise SystemExit(answer.json()["error"])
pathlib.Path("invoice.pdf").write_bytes(answer.content)

Every answer, and what to do about it

A refusal is JSON carrying one sentence. The status is what tells a program whether the request is worth sending again: one alone is, and it is the one that says the render server was never reached.

Every answer this address gives, by its number
Answer What it means What to do
200 The PDF is the body, handed over as it is drawn, under the file name the header above names. Nothing to do.
400 Either what was posted is not JSON at all, or the render server read the description and refused it. The sentence says which, and what it found. Correct the description. The same one posted twice gives the same answer.
401 The call carried no key, or a key nobody holds any more. Present a live key of the account.
402 Either the documents of the month are all used, or the drawing asked for something a licence key covers and the account has none. The sentence says which. Wait for the month to turn, or move up an offer.
405 The address was asked for any way but a POST. Post the description. The same address opened in a browser shows a page.
413 The body of the request, or the document it asks for, runs past a ceiling. The sentence names the size or the ceiling. Ask for less in one call.
500 Writing the PDF did not come off, on the render server's side. Worth one more call. Tell us if it keeps happening.
503 The render server could not be reached at all, or this site does not know where it is. Nothing was read of the description. The one answer worth sending the same request again for.

What a call costs

  • One document is taken off the month before the description is forwarded.
  • A render that never arrives gives its document back: a call answered 503 costs nothing.
  • A call refused before anything is forwarded — no key, a body that is not JSON, a month with nothing left — costs nothing either.
  • The pages written down are the ones the render server states, and nothing here opens the document to count them a second time.

Trying it by hand

The same address opened in a browser shows a box: paste a description into it and the document comes back on the spot. It draws for whoever is signed in, off the session rather than off a key, and it counts nothing.

It is the same address, the same description and the same render server, so what you try by hand is what your program will send.

Where to go next

The format of a description Your keys and what is left of your month What becomes of a document you send

See the prices See the examples