The API that creates your PDFs
Your program describes the document it wants in JSON, posts it in one call, and the finished PDF comes back in the answer.
Summary
Think of ordering a cake. You write down what you want on it, hand that description over the counter, and the cake comes back over the same counter a moment later. Nothing else happens, and you never see the kitchen.
The description here is a piece of text your program writes. It says what goes on the page: this sentence in this place, this table under it, this logo in the corner, this QR code at the foot. Anything the page needs and the text cannot hold — a photograph, a letterhead template — travels along beside it.
The description is written in a form every machine agrees on, called JSON. It is ordinary text, made of names and values, and it reads the same whatever your program itself is written in.
What comes back is the finished document, ready to send to a customer or to a printing works. It comes back in the answer to the call itself, straight away.
The answer is the document. Not a link to fetch it later, not a ticket number to ask about again: the bytes of the finished PDF come back in the answer to that one call.
Nothing is installed to call this address: your program already knows how to send something across the network, and that is the whole of what is being asked of it.
There are twenty-four things you may put on a page: paragraphs, tables, photographs, pages taken from another document, the five kinds of barcode and square code, plain shapes, the fields of a form to fill in, and clickable links. Each of them has a page of its own here, with the shortest example that draws it.
Beside them, sixty keys settle the document around what is drawn: the list of what goes on the pages, and beside it the size of the sheet, the fonts, what the file says about itself, the way a reader finds their way through it, the colours, and how it all comes out. Each of those has a page of its own as well, so this section is eighty-four pages: one for each thing you may put on a page, and one for each key.
Two pieces, and why there are two
The server creates no PDF file itself. It reads the description, checks it, and then calls the library one instruction at a time: set this paragraph, start this table, place this picture here. The library is what writes the file.
They are two because they do two different jobs. The library knows how to draw and knows nothing of the network. The server knows the network — who is calling, how large a request may be, how many pages an account is allowed — and knows nothing of drawing.
The library works with fonts already loaded and ready to draw with, while a description arriving over the network carries only its name. Turning that name into a font the library can use is exactly the server's job, and it is done before the first letter lands on a page.
This is why the library can be bought and used on its own, called straight from a program written in Rust or in Python, with no server and no description travelling anywhere. And it is why a document comes out the same either way, page for page: the same library writes it.
Creating a PDF keeps a processor busy from beginning to end, so each request is handled by a process that has nothing else to do, and the server goes on answering everybody else meanwhile.
The round trip, drawn
- Your own program runs on your own machines
- on the way there: the document described as text, and the files it names on the way back: the finished PDF, and how many pages it has
- The server on the address you call
- on the way there: one call per thing to draw: a paragraph, a table, an image on the way back: the pages, created
- The library inside the server
What was noticed while the PDF was created
Beside the finished document, the answer says what was noticed while the PDF was created. It is a remark, not a refusal: the pages are the pages you asked for, and a remark leaves them exactly as they are.
The answer always says how many remarks there were, and a nought is an answer of its own: nothing was noticed while the PDF was created.
Two things are remarked on today. The first is something your description sent along that no page ever used — a font, a photograph, a colour, a layer. It travelled and it went into the file, so the file is heavier than the pages needed it to be.
The second is a font that carries a licence note from whoever drew it, saying how it may be passed on. The document is written with that font inside it, and the remark repeats what the licence note says, so that you can compare it with the licence you bought that font under. That licence is yours and stays with you: it is the one thing the file cannot carry.
Ten remarks at most come back in the answer, while the count says how many there really were. There is no way to fetch the rest: the server writes every one of them down in its own log.
Technically
One POST /render of multipart/form-data: the document described as JSON in the json_data part, the files it names in the parts beside it, and either 200 application/pdf back or a numbered refusal in plain text.
The transport
One endpoint, one method: a POST with a multipart/form-data body. The part named json_data holds the whole description as JSON. Every other part is a file the description addresses by that part's name — a PDF used as a template or imported page by page, an image, an ICC profile, an XMP packet, the XML of an invoice. There is no upload step and no asset identifier to keep: a part lasts only for the call that carried it.
Authentication is an API key carried in the Authorization header and checked by this site, which resolves it to a client name and forwards that name in a header of its own. A success answers 200 with application/pdf and the count of pages. A refusal answers a status code, one sentence of plain text, and x-hqf-refusal: one word from a closed list naming the kind of refusal, which is what a program reads. There is no envelope to unwrap and no job to poll.
The service we run adds one refusal of its own, which a server of your own never gives: when a month's documents are all used up, it answers 429, with Retry-After carrying the date the month turns. A server of your own counts no month.
| The call that creates a document, on a server of your own | POST /render |
|---|---|
| The service we run, which takes a call of its own | POST https://hqf-pdf.com/api/v1/render |
| The call that says the service is up | GET /health |
| The shape the body is sent in | multipart/form-data |
| The part carrying the description | json_data |
| Every other part | a file the description addresses by name |
| How the API key travels | Authorization: Bearer <key> |
| What this site forwards to the server | x-hqf-client: <name> |
| What a success carries | 200 application/pdf |
| How many pages the finished document has | x-hqf-pages |
| How many things were noticed while the PDF was created | x-hqf-warnings |
| One remark, repeated once per remark carried | x-hqf-warning |
| How many findings separate the document from the standards asked for | x-hqf-findings |
| One finding, repeated once per finding carried | x-hqf-finding |
| What an error carries | text/plain |
| The word a refusal names its sort by | x-hqf-refusal |
| The version of the service that answered | x-hqf-version |
The call the service we run takes, and every answer it gives
The body, part by part
The body is a form in several parts, and each part has a name.
json_datacarries the description of the document, the sixty keys of it. It is the one part whose name is fixed.- Every other part is a file the request draws on, under the name the description calls it by: a PDF laid under the pages, named by
templates, a picture named by animageitem, an ICC profile named byoutput_intentor by aniccspace, the XML named byinvoice, a metadata packet named by an image. What a part is follows from the JSON that names it, never from the part itself. - The body is kept in memory whole, and its size is capped at 536 870 912 bytes — 512 MiB — short of a setting on the server saying otherwise.
- The service we run caps the body of a call of its own at 536 870 912 bytes, or 512 MiB, and answers 413 naming
body_too_largepast that. The two ceilings are two settings of their own, so a server you run can be set lower or higher than the one above.
The header this site sets
The server authenticates nobody: this site takes the call, checks the API key and names the client it belongs to, in the x-hqf-client header. The server reads that name and creates the PDF under what the account carries: its fonts, its ceiling of pages, its entitlements. A request naming a client the server does not know, or naming none, is rendered under the default settings. The header is worth trusting because nothing but this site can set it: the server listens on the loopback and nothing outside this machine reaches it, and this site writes the header afresh on every request it forwards.
What a success hands back
- The status code
200, and the bytes of the PDF as the body. Content-Type: application/pdf.x-hqf-pages, how many pages the finished document has.x-hqf-warnings, how many things the engine remarked on while writing the document, and onex-hqf-warningper remark carried.x-hqf-findings, how many findings stand between the finished document and the standardscheckasked it to be measured against, and onex-hqf-findingper finding carried. Both stand on an answer that carries a document, whether or not a standard was asked for.- A server of your own repeats the header once per value. The service we run sends the name once with its values separated by commas; the rule for splitting them is on that service's page.
What a render remarks on
A remark is something the engine noticed while writing a document it went on to write: the bytes handed back are the bytes a render with nothing to remark on would have handed back, and the status code stays 200. x-hqf-warnings carries how many there were and stands on every rendered answer, 0 included; an answer carrying no such header comes from a server older than the header itself.
x-hqf-warning is then repeated once per remark carried, in the order the engine made them. Ten of them at most, running to a thousand bytes together, whichever of the two is reached first. The remark that runs past the bytes left is cut short and ends on %E2%80%A6, an ellipsis, and the remarks after it stand in the server's log alone — which keeps every one of them in full, at INFO, under the name of the client the render was for. The count states the whole number either way, so a customer reading x-hqf-warnings: 50 beside ten headers knows exactly where they stand.
Those two figures are what keeps the answer deliverable. A front server caps how large the headers of a response may be, and a document declaring fifty resources it never draws would produce fifty headers: the whole answer would be turned away before reaching the customer, and a document written without fault would arrive as a failure of the service.
- A resource the request declared and no page drew with — a font, an image, a drawing, a colour space, a graphics state, a gradient, a pattern or a layer. It is written into the file and put at every page's disposal, and no content stream names it. The remark reads
the image Im2 is never drawn with. - A font embedded against what its own
fsTypeflag permits: a flag forbidding embedding, one asking to go in whole where the glyphs drawn went in, or one allowing only the pictures the font carries where outlines went in. The remark names the font as the font names itself and the name the request selects it by —the font Foo (F1) must not be embedded without the owner's permission. Whether the embedding is lawful turns on the licence the font was bought under, which is yours to read. - Every value is percent-encoded and decodes the way a URL decodes: every byte outside printable ASCII stands as
%XXand the percent sign itself as%25, soCaféarrives asCaf%C3%A9. A header carries ASCII alone, while a resource is named by whoever wrote the request and a font names itself in its own licence — so a remark holds whatever those two hold. A remark cut short is cut between two characters, so what arrives decodes, and what it decodes to is text.
The version that answered, and the health probe
GET /health answers a 200 and a small JSON object: version, the number of the build that answered, licensed, whether a licence covers the day, and faces, how many fonts the general library carries. That is what a supervisor or a load balancer reads to know the service is answering, and what a deployment reads to know that the build it installed is the one now answering.
The same number stands on every answer the service sends, in the x-hqf-version header: on a created document, on a refusal and on the probe alike. A customer writes it into their own log beside the call they made, so a document that came back wrong is tied to the build that created it; and after a deployment it is read to tell an instance that was replaced from one left behind. An answer carrying no such header comes from a build older than the header itself. The number is the service's own: the engine carries one of its own, on the page of the library, and this site carries a third, at the foot of every page.
The model
A request has one top level: a list of items, and beside it the resources those items name. Fonts, colour spaces, gradients, graphics states, layers and drawings are each declared once under a name, and an item refers to that name. A resource is found by its name, wherever it is declared, and everything that counts is written — a name an item calls for and no declaration carries is refused, with the name in the message.
Pages are created by what is drawn on them, not declared up front. An item states which pages it lands on; the default, an empty array, is every page, which is how a footer or a watermark is written once. A table that overflows its box carries on into the next box and creates the pages it needs, and the items keyed to every page follow it there.
Geometry is in typographic points with the origin at the bottom left, as the format itself has it. Any coordinate may be a quoted arithmetic expression over the page dimensions and the current page number, so a right margin is "{page_width} - 56" rather than a number your program had to work out. An item may name itself and another may hang off its edge, which is what keeps a layout right when the height of a block is only known after it is set.
What a request carries beside what it creates
The same request states the document's metadata, the archival standard it claims, the output intent its colours are read against, the compression of its streams, the outline and the named destinations, the article threads, the page labels, the reading preferences reading software honours, and the invoice XML a Factur-X document carries. One call produces a finished, standards-claiming file: there is no second pass and no post-processing tool.
The answers, and what they say
Validation is total and happens before anything is drawn: the server refuses a request rather than producing a document that quietly lost something. A refusal is one sentence naming the key or the name at fault, so it is worth logging verbatim.
Beside it stands x-hqf-refusal, one word from a closed list: client_name, call_number, form, body_too_large, description, drawing, too_many_pages, needs_a_licence, server. It is what a program branches on, the sentence being written for a person. A word not on this list comes from a server newer than this page.
Unknown keys are ignored almost everywhere, which makes a request written for a later version safe to send at an earlier one. The one exception is the object form of pages, the rule built from every, from, to and but: there a key the rule does not have is refused by name, since a rule stating nothing covers the whole document and a misspelt key would silently do the same. A key written twice in the same object is refused by name. Combinations that would contradict each other — a matrix together with a rotation, a link with both a short target and a full action, a table cell holding two things — are refused by name as well.
A page the document does not have is refused wherever a key names one — a bookmark, a named destination, the patch of an article thread — and the message names that page in the numbering the request used: ask for page nine of a five-page document and the message says page nine.
This site waits 30 seconds for the document and no longer. Past that the call comes back under the status 503 and one sentence saying the service did not answer. How long a document of your own takes is published nowhere: measure it on your own pages, on the machine that will run them.
200 |
The PDF is the body. Beside it stand the count of pages and what was noticed while the PDF was created: a count, and one header per remark carried. |
|---|---|
400 |
The request must be corrected and sent again; the body is one sentence of plain text. Known cases: the JSON will not read; the `json_data` part is absent; a font named is nowhere declared; a coordinate will not parse; a link or a bookmark leads to a page the document has not, named in the numbering the request itself uses; a standard declared and a setting that standard puts aside contradict each other; a compression level falls outside 1 to 9; a template supplied is not a PDF that reads. |
402 |
The request asks for something only a licence key covers, under `x-hqf-refusal: needs_a_licence`. The sentence names what was asked for and says a licence key carries it. Every case: text set in a font with no outline to draw the glyphs from — the fourteen standard fonts, a font whose glyphs are drawings, a type 1 program; a page imported from another document showing more than ten thousand words of its own; an imported page whose words cannot be counted at all; a claim of accessibility, or of archiving at the level that rests on saying what the marks on a page stand for; a destination leading to an element of the structure tree. The last three come of a free copy tracing every glyph as a shape: the document has no structure tree for any of them to rest on. |
413 |
The body of the request runs past the size the server accepts, or the document runs past the ceiling of pages of the server or of the account. The sentence names the size or the ceiling. |
500 |
Writing the PDF or the font store did not come off. That is on the service's side rather than in the request. |
Request schema
Every key a request carries, with its type, whether it is required and what it falls back to when it is left out. Every figure was read off the sources of the server and holds for the version in production.
The smallest request that creates a PDF
One declared font, one item, one line of text. Save it, post it, and a one-page PDF comes back.
{
"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
}
]
}
The same call, written three times
None of the three is a library to install: the server answers over the network, so any language able to post a form calls it. Here are three — a shell, Python and JavaScript.
Copy whichever of these matches your stack. Each posts the description and one file it draws on, and writes the answer straight to disk.
What the Rust library and the Python library create
From a shell
One part carries the description, one part per file it draws on. The name of a part is the name the description calls that file by.
# The service we run takes a call of its own:
# POST https://hqf-pdf.com/api/v1/render described on
# https://hqf-pdf.com/en/api/pdf-api-endpoint/
curl -X POST https://your-server/render \
-H "Authorization: Bearer $HQF_PDF_KEY" \
-F "json_data=@invoice.json;type=application/json" \
-F "letterhead.pdf=@letterhead.pdf" \
-o invoice.pdf
From Python
The API key comes from the environment, and the answer is the PDF itself, so write the body straight to a file. The count of pages stands on every answer that carries a document.
import json
import os
import pathlib
import requests
KEY = os.environ["HQF_PDF_KEY"]
LETTERHEAD = pathlib.Path("letterhead.pdf")
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,
}
],
}
# The service we run takes a call of its own: POST https://hqf-pdf.com/api/v1/render
# described on https://hqf-pdf.com/en/api/pdf-api-endpoint/
answer = requests.post(
"https://your-server/render",
headers={"Authorization": f"Bearer {KEY}"},
files={
"json_data": ("request.json", json.dumps(description), "application/json"),
"letterhead.pdf": ("letterhead.pdf", LETTERHEAD.read_bytes()),
},
timeout=120,
)
answer.raise_for_status()
pathlib.Path("invoice.pdf").write_bytes(answer.content)
print(answer.headers["x-hqf-pages"], "pages")
From JavaScript
A form body and the standard fetch, run by Node. The API key comes from the environment and the template from a file beside the program, and a refusal arrives as a sentence of plain text.
import { readFile, writeFile } from "node:fs/promises";
const key = process.env.HQF_PDF_KEY;
const letterhead = new Blob([await readFile("letterhead.pdf")]);
const 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,
},
],
};
const body = new FormData();
const asJson = JSON.stringify(description);
body.append("json_data", new Blob([asJson], { type: "application/json" }));
body.append("letterhead.pdf", letterhead, "letterhead.pdf");
// The service we run takes a call of its own:
// POST https://hqf-pdf.com/api/v1/render
// described on https://hqf-pdf.com/en/api/pdf-api-endpoint/
const answer = await fetch("https://your-server/render", {
method: "POST",
headers: { Authorization: `Bearer ${key}` },
body,
});
if (!answer.ok) {
throw new Error(await answer.text());
}
await writeFile("invoice.pdf", new Uint8Array(await answer.arrayBuffer()));
The keys of a request
Sixty keys stand at the top level of a request, and one of them is required. Every other key defaults to the value in the column beside it, so a request states what it needs and nothing else. Each key leads to its own page.
| JSON key | Type | Default | What it is for |
|---|---|---|---|
items
|
array | required | Everything drawn on the pages, in the order it is drawn. This is the one key a request cannot leave out. |
page
|
object |
595.276 × 841.89
|
The sheet every page is cut to, in points, unless a page names its own. |
page_sizes
|
array |
[]
|
A sheet of its own for one numbered page. |
page_boxes
|
array |
[]
|
The crop, bleed, trim and art boxes of one page, which is what a printing works reads before anything else. |
page_turns
|
array |
[]
|
Which way up a page is presented to whoever opens the file. |
page_tab_orders
|
array |
[]
|
The order the keyboard walks the fields of one page. |
page_shows
|
array |
[]
|
How one page arrives, and how long it stands, when reading software shows the document full screen. |
supplied_pdfs
|
object |
—
|
How the PDFs supplied alongside the request are read: how far one of their streams is allowed to unpack. |
structure
|
object |
—
|
What the document says it is made of, in reading order, so a program reads it as a person would rather than as the ink went down. |
accessible
|
string |
—
|
The accessibility standard the document claims, checked against what it actually carries. |
simple_fonts
|
array |
[]
|
A font reached by one-byte codes fitted to a stated text: a lighter page, and word spacing that has a code to reach. |
attachments
|
array |
[]
|
The attachments the document carries beside its pages. |
collection
|
object |
—
|
How reading software lays the attachments out as a portfolio: the columns, the order the rows stand in, and the file opened first. |
page_files
|
array |
[]
|
Which of the attachments one page claims as its own. |
page_metadata
|
array |
[]
|
The identity card one page carries, beside the document's own. |
tilings
|
array |
[]
|
A cell repeated to fill a shape: hatching, a weave, a background. |
fonts
|
array |
[]
|
Fonts carried in the request as base64, each under a name the items call for, with the characters they keep and what they draw for one they have no glyph for. |
type1_fonts
|
array |
[]
|
Type 1 fonts, carried the same way. |
standard_fonts
|
array |
[]
|
One of the fourteen fonts all reading software already carries, under a name of your choosing. |
font_variants
|
array |
[]
|
A declared font with ligatures, small capitals, oldstyle figures or kerning switched on. |
type3_fonts
|
array |
[]
|
A font whose glyphs are drawings rather than outlines. |
font_chains
|
array |
[]
|
Two or more fonts tried in order, so a glyph the first lacks is taken from the next. |
templates
|
object |
—
|
The supplied PDFs laid under the first page, under the middle pages and under the last. |
renumber
|
array |
[]
|
Where page numbering restarts, in which style, behind which prefix. |
bookmarks
|
array |
[]
|
The outline reading software opens beside the page, nested as deep as you like. |
destinations
|
array |
[]
|
Named places in the document a link or an action may aim at. |
articles
|
array |
[]
|
Reading threads that carry a reader from one column to the next. |
document_parts
|
object |
—
|
The tree of parts a PDF 2.0 document declares, each claiming a range of pages and carrying named values. |
private_data
|
object |
—
|
What a program leaves in the document for itself, filed under its own name. No reading software shows it. |
page_private_data
|
array |
[]
|
The same, left on one numbered page rather than on the document. |
metadata
|
object |
—
|
Title, author, subject, keywords, the program it was written in, producer, creation and modification dates, trapping state, and schemas of your own. |
information_dictionary
|
object |
—
|
Whether the file keeps its table of entries beside its metadata packet, or says what it is in the packet alone. |
archive
|
string |
—
|
The archival standard the file claims: `pdfa3b` or `pdfa4`. |
protection
|
object |
—
|
The passwords the document is locked under, and what reading software is asked to allow once it is open. |
invoice
|
object |
—
|
The invoice XML carried inside the document, with its profile, its version, its relationship and its date. |
reading
|
object |
—
|
How reading software is asked to open the file: which panel, which layout, which page, which zoom, and what to send a printer. |
base_uri
|
string |
—
|
The address a relative link is resolved against. |
version
|
string |
the engine's own
|
The PDF version the file declares: `1.4` through `1.7`, or `2.0`. |
compression
|
object |
—
|
Whether streams are deflated, at which level, and whether small objects travel packed together. |
first_page_first
|
object |
—
|
Whether the file is written first page first, so reading software shows page one while the rest is still arriving. |
output_intent
|
object |
sRGB
|
The colour profile the file's colours are to be read against. |
images
|
array |
[]
|
What one supplied picture says about itself, and how it is read: its masks, its see-through samples, its orientation and its profile. |
color_spaces
|
array |
[]
|
Separations, indexed palettes, Lab, calibrated grey and RGB, and profile-based spaces, each under a name a colour may call for. |
shadings
|
array |
[]
|
Axial and radial gradients, each under a name a fill may call for. |
graphics_states
|
array |
[]
|
Named states carrying the opacities, the blend mode, a mask, and what a press asks for: the overprinting, the intent, the transfer curve and the halftone screen. |
layers
|
array |
[]
|
Named layers reading software can switch on and off, and which say whether they print. |
drawings
|
array |
[]
|
Named vector drawings, which is what a push button shows as its icon. |
transparency
|
object |
—
|
The blending space the page group works in, and whether it is isolated or knocked out. |
page_units
|
array |
—
|
How many points one unit of a page is, for a sheet larger than the 14 400 points a PDF measures in. |
page_review_marks
|
array |
—
|
The shapes a page lays over what it draws: a note, a stamp, a shape drawn by hand. |
page_triggers
|
array |
—
|
What a page sets off when reading software arrives at it, and when it leaves it. |
print
|
string |
—
|
The print standard the document claims, and is refused for breaking. |
check
|
array |
—
|
The standards the finished document is measured against, the answer coming back beside the file. |
page_spaces
|
array |
—
|
What a page's bare numbers mean, colour space by colour space, and how its marks are composited. |
page_separations
|
array |
—
|
Which plate of a separated sheet a page is, and the ink it is printed in. |
page_output_intents
|
array |
—
|
The device one page's colours are stated for, where the cover and the inside are not printed on the same paper. |
layer_rules
|
array |
—
|
A name items are drawn on that stands for several layers at once, and the rule reading software applies to decide whether to show them. |
layer_configurations
|
array |
—
|
The named sets of layer states reading software offers beside the one the document opens under. |
layer_families
|
array |
—
|
Layers reading software shows one of at a time, so showing one of them turns the others off. |
carried_facts
|
array |
[]
|
Named lists of data of your own, each hung on a run of ink by the item that names it. No reading software shows them. |
The eighty-four pages of this section
One page per item and per key a request can carry, filed under the question it answers. Each says what the thing is, what it does technically, the schema of the request it takes, and shows a whole request using it.
What a request creates
Twenty-four things go on a page, and each has a page of its own here: what it is, what it does technically, the schema of the request it takes, and a whole request showing it.
Text
-
A block of text placed on the page
textSet text inside a chosen rectangle, with its font, size and colour, and give one word in the middle of a sentence a style of its own. -
Text in paragraphs, with indents and tab stops
flowLay several paragraphs in a frame, with a first-line indent, space between them, bulleted lists and neat columns of figures. -
A stamp laid across the page
stampLay one word across an area, at the size that fills the box: draft, paid, copy, cancelled, on the diagonal or flat. -
A line of words set along a path
text_pathRun one line of text round a seal, over an arch or along the edge of a map: every letter stands on the curve and leans the way it leans. -
Blocks laid one under the other, page after page
stackPile paragraphs, tables, pictures and rules in reading order and let them find their own pages: what does not fit carries on in the box of the next one.
Tables
-
A table that carries on from page to page
tableRows and columns flowing over as many pages as needed, with a repeated header, rules, coloured backgrounds and merged cells.
Pictures and imported pages
-
A picture placed in a rectangle
imagePlace a photo or a logo supplied with the request in a chosen frame, stretched to the edges or kept at its own proportions. -
A page of a supplied PDF, placed on the page
pdf_pageTake one page of a PDF sent with the request and place it in a frame, at its own proportions, among the other items.
Barcodes and square codes
-
A barcode of vertical bars
barcodeDraw a barcode a scanner reads: Code 128, Code 39, Code 93, ITF-14, Codabar, EAN-13, UPC-A, EAN-8, UPC-E, GS1 DataBar and the two add-ons. -
A square QR code, read with a phone
qrDraw a QR code carrying a web address or a piece of text, read by any phone, with its white margin all around. -
An Aztec code, with no white margin around it
aztecDraw an Aztec code, the one on train tickets: square, needing no margin, with the share of safety you choose. -
A Data Matrix code, very small and very sturdy
data_matrixDraw a Data Matrix code, the one on parcels and small parts: as much content as a QR code in far less room. -
A PDF417 code, carrying a whole form
pdf417Draw a PDF417 code of stacked bars, the one on boarding passes: it carries a whole form, not merely a number.
Shapes
-
A free path: lines, curves and filled shapes
pathDraw a shape point by point, with straight segments and curves, filled with a colour or a gradient, and outlined with a stroke. -
A rectangle, filled or outlined
rectPlace a rectangle: a coloured band behind a heading, a frame around an area, or both, with the stroke you choose. -
A straight line between two points
linePull a line from one point to another, at the thickness, colour and dash you want: a divider, an underline, a ruled row. -
A drawing declared once and placed as often as wanted
drawingPut a drawing the request declared on the page, where you want it and at the size you want, without the file carrying the same ink twice.
Form fields
-
A field the reader types into
text_fieldAdd a field to fill in: a name, an address, a comment over several lines, a hidden password, or a number one square per digit. -
A box the reader ticks
check_boxAdd a tick box: accepting terms, choosing an option, with the mark you pick and the value the form reports. -
A list the reader picks from
choice_fieldOffer a list of answers: an open list, a drop-down menu, or a menu the reader may also type an answer into. -
Several buttons, one answer
radio_groupPlace buttons of which only one stays chosen at a time, each in its own spot, all belonging to the same question. -
The place kept for a signature
signature_fieldKeep a spot on the page where an electronic signature will settle, with its name and its frame. -
A button the reader presses
push_buttonPlace a button that acts instead of answering: open an address, go to a page, send the form or reset it.
Navigation
-
A patch of page a reader clicks
linkMake a patch of page clickable: it opens a web address, or takes the reader to another page of the same document.
What a request settles
Sixty keys stand at the top level of a request and settle the document around what is drawn: the sheet, the fonts, the identity of the file, the way a reader moves through it, the colour, and the rendering itself.
The sheet, and what is laid under it
-
The size of the pages
pageGive the document's pages a width and a height. Say nothing and the sheet is an A4 of 595.276 by 841.89 points. -
A size of its own for certain pages
page_sizesGive one named page a width and a height of its own, leaving every other page of the document as it is. -
The unit a page is measured in
page_unitsState how many points one unit of a page is, for a sheet larger than the 14 400 points a PDF measures in. -
The areas a page states
page_boxesState what reading software shows of a page and what a printing works does with it: the cut, the ink overrun, the useful area. -
The shapes a page lays over what it draws
page_review_marksLay squares, circles, lines and outlines over a page, each with its own colour, border and note. -
Which way up a page is shown
page_turnsTurn a page a quarter turn before reading software shows it, without moving anything drawn on the sheet. -
How a page arrives, and how long it stands
page_showsTurn the document into a slideshow: each page arrives with an effect of its own and stands for the time you give it before the next one comes. -
How far a supplied PDF is allowed to unpack
supplied_pdfsSet the ceiling one stream of a PDF you send may unpack to, so that a file built to swallow the machine is refused before it takes the room. -
The template under the pages
templatesLay the document's pages over a PDF already made: a letterhead, a contract background, a signature sheet.
The fonts
-
Carrying a font inside the document
fontsSend a font file along with the request so the document reads everywhere with exactly the same fonts. -
The older Type 1 font programs
type1_fontsCarry a Type 1 font into the document, the format of the older typesetting studios, under a name of your choosing. -
The fourteen fonts all reading software owns
standard_fontsSet text in one of the fourteen fonts reading software already owns, carrying nothing at all inside the file. -
The typographic niceties of a font
font_variantsTurn on ligatures, small capitals, oldstyle figures or kerning for a font, under a new name of its own. -
A font whose letters you draw yourself
type3_fontsDescribe your own letters with lines and shapes, then set text in them like any other font. -
A backup font for the rarer signs
font_chainsChain several fonts together: each character is drawn by the first one in the list that has a shape for it. -
Fonts whose letters cost one byte
simple_fontsMake a font reached by one-byte codes fitted to the text you will actually draw: a lighter page, and a word space that has a code of its own.
The document as a whole
-
The numbers reading software shows
renumberRestart the numbering somewhere in the document, in roman numerals, in letters, or behind a prefix. -
A hundred letters in a single file
document_partsSay, inside the file itself, where one recipient ends and the next begins, with what the finishing needs. -
What the document says about itself
metadataGive the file its title, its author, its subject, its date, and if needed entries from a vocabulary of your own. -
What the document says about itself, said once
information_dictionaryWrite what the file says about itself in its metadata packet alone, with no table of entries beside it. -
The notes a program leaves in the file for itself
private_dataLeave data in the document for the program that wrote it, filed under that program's name and dated. No reading software shows it. -
The notes a program leaves on one page
page_private_dataLeave the same private data on one numbered page rather than on the document as a whole. -
The data a program hangs on a run of ink
carried_factsHang a list of your own data on a run of ink of the page, under a name you choose. Nothing of it is drawn, and no reading software shows it. -
A file still readable decades from now
archiveState that the document follows an archiving standard: all it takes to read it again is written inside, for good. -
The print standard the document claims
printClaim PDF/X-4, and have the document refused rather than written when it breaks the standard. -
The password that opens it, and what may be done with it
protectionLock the document under a password, and name what reading software is asked to allow: printing, copying, filling in a form. -
An invoice a person and a machine both read
invoiceProduce an invoice a person reads, carrying inside the same file the data accounting reads on its own. -
The address relative links are read against
base_uriSay where the document was published, so its short links keep leading to the right place after it moves. -
The PDF version the file declares
versionChoose the version the document announces, from 1.4 to 2.0, by what it carries and by the age of the software reading it. -
What a picture says about itself, and how it is read
imagesAttach to a supplied picture its author and its rights, and say which of its pixels show, how opaque they are and which way up it is drawn. -
The attachments the document carries beside its pages
attachmentsCarry whole files inside the PDF — the data an invoice was made from, the same statement in another form — each named, described and dated. -
The attachments shown as a portfolio
collectionSay how reading software lays the attachments out: the columns, what each file puts in them, the order, and which file opens first. -
Which attachments a page claims
page_filesSay, page by page, which of the attachments belong to that page, so a hundred statements in one PDF each keep their own data file. -
The identity card a single page carries
page_metadataGive one page its own title, author, subject and dates, so a document cut back into pieces keeps each piece's identity. -
The accessibility standard the document claims
accessibleDeclare the document built to be read aloud and described, and have that claim checked against what it actually carries. -
The standards the finished document is measured against
checkAsk for the finished document to be measured against a standard, and get what stands in its way back beside the file.
Finding one's way through it
-
The order one field leads to the next
page_tab_ordersSay the order the tab key walks a page's links and fields in: row by row, or column by column. -
What a page sets off as reading software comes and goes
page_triggersSet off an action when reading software arrives at a page, and another when it leaves it. -
What the document says it is made of
structureGive the document a reading order and a shape — headings, paragraphs, figures — so a program can read it aloud in the order a person would. -
The clickable contents down the side
bookmarksGive the document a folding contents list beside the pages, each line leading straight to a page. -
Landing places that have a name
destinationsRegister a place in the document under a name, so a link leads there without ever quoting a page number. -
Following an article column by column
articlesSay the order the pieces of one article are read in, when it runs across several columns and several pages. -
How the document opens and prints
readingAsk the reading software what to show on opening, how to lay the pages out, and what to offer when printing.
Colour and how it is shown
-
The device the colours are stated for
output_intentName the press or the screen the document's colours were chosen for, so they come out as intended. -
Which plate of a separated sheet a page is
page_separationsSay that a page is one plate of a sheet, and name the ink it is printed in. -
The device one page's colours are stated for
page_output_intentsName a press for one page alone, where the cover and the inside are not printed on the same paper. -
Declaring colour beyond red, green and blue
color_spacesName a separate ink, a measured colour or a profile, so the document speaks of it in more than three numbers. -
What a page's bare numbers mean
page_spacesSay which declared colour space a page's one, three and four-number colours are read through, and how its marks are composited. -
A colour sliding into another
shadingsDeclare a gradient, along a line or between circles, then fill a shape with it by naming it. -
Opacity, mixing, and what a press asks for
graphics_statesDeclare a painting setting — opacity, blend mode, overprinting, halftone screen — then apply it to shapes by its name. -
A cell repeated to fill a shape
tilingsDraw one small cell and have it laid down over and over to fill a shape: hatching, a weave, a background of dots. -
The space a page mixes its colours in
transparencySay which colour space a page's marks mix in with each other, for the same result everywhere.
What is drawn, and how it comes out
-
Everything that can be drawn on a page
itemsThe one required key: the list of what gets drawn, in drawing order. Twenty-four kinds in all. -
The file's weight and the time it takes
compressionSet how hard the document compresses: the fastest, the smallest, or a file readable in a plain text editor. -
The first page, shown while the rest arrives
first_page_firstAsk for the file to be written first page first, so somebody opening it from a link sees page one almost at once. -
Layers reading software shows or hides
layersSort what is drawn into named layers, shown or hidden in one click, and which reading software shows by the magnification or by the language. -
A name that stands for several layers at once
layer_rulesDraw items on a name that follows several layers, and say what reading software must find true of them before it shows what the name covers. -
A drawing made once, shown by a button
drawingsDescribe a drawing under a name, with lines and shapes, so a form button carries it as its icon. -
The sets of layers reading software offers
layer_configurationsOffer named sets of layer states beside the one the document opens under, so reading software can switch between them. -
Layers reading software shows one of at a time
layer_familiesTie layers together so that showing one of them turns the others off, the way a set of radio buttons works.
The shapes every key is built from
A handful of objects recur throughout the format. They are written once here, and every page that uses one names it by these words.
rect |
Four coordinates — `llx`, `lly`, `urx`, `ury`. The origin sits at the bottom left of the sheet and the vertical axis goes up, which is the convention of the format itself. |
|---|---|
coordinate |
A number, or a quoted expression over `+ - * / ( )` and the variables `{page_width}`, `{page_height}`, `{current_page}`, `{total_pages}`, `{llx}`, `{lly}`, `{urx}`, `{ury}`. An expression nests up to a hundred deep, which is how an item sits against the page width without the customer computing anything. |
color |
One number for grey, three for red, green and blue, four for the four printing inks, all from 0 to 1. Also `{"gray": n}`, and `{"space": "name", "components": …}` for a space the request declared. |
stroke |
A `width`, and optionally a `color`, a `dash` pattern with its phase, a `cap` and a `join`. |
pages |
The one-based pages an item is drawn on. The default, an empty array, draws it on every page, which is how a footer is written once. |
layer |
The declared layer an item belongs to, which is what reading software switches on and off. |
id / relative_to |
An item names itself with `id`; another places itself against that item's `top` or `bottom` edge with an `offset`, so a paragraph follows a table whose height nobody knew in advance. |
transform / rotate |
Six numbers for a matrix, or a number of degrees counter-clockwise about the centre of the rectangle. An item states one or the other. |
How a request is read
- A key the server does not know is ignored, so a request written for a later version renders at an earlier one.
- A key written twice in the same object is refused, and the message names the key.
- A choice that has no value of its own is written as a bare string —
"center","pdfa4". A choice that has one is a single-key object naming the variant —{"points": 12},{"page": 3}. - An absent optional key and an explicit
nullare read the same way, which is what lets a serialiser emit either. - The same description, posted twice, yields the same bytes twice, outside the two places where the schema says otherwise: a run asking for the moment of rendering reads the clock as the page is written, and a
protectionblock stating nokeyof its own is locked under thirty-two bytes read off the machine. Everywhere else the file identifier is a digest of what was written, so two renders can be compared as files.
The figures the service holds itself to
| The body of a request, on a server of your own | 536 870 912 (512 MiB) |
|---|---|
| The body of a request to the service we run | 536 870 912 (512 MiB) |
| How long the service we run waits for a document | 30 seconds |
| How deep an expression nests | 100 |
| Entries in an indexed palette | 256 |
| Compression level | 1 – 9 |
| Error correction of an Aztec code | 0 – 90 % |
| Columns of a PDF417 code | 1 – 30 |
| Error correction level of a PDF417 code | 0 – 8 |
| Fonts in a chain | 2 or more |
| Remarks an answer carries | 10 |
| Bytes those remarks run to together | 1 000 |
| Pages of the middle template | 1 |
| How far one stream of a supplied PDF unpacks | 1 073 741 824 |
| Characters in the name of a stored font | 64 |
| Pages in one document | what your plan includes |
The questions people ask first
Is anything of my document kept?
The pages are not. The finished PDF goes back in the answer to your call, and it is never written to a disk along the way.
The description you sent, and any file you sent with it, are kept only for as long as the render takes, and only in the machine's own memory. Neither of them is written to a disk, and both are gone the moment the pages leave.
Two things are written down, and only two. The first is fonts. If your account is allowed to send fonts of its own, then a font the render really used is kept in a folder belonging to that account, so that you never have to send it a second time — from then on your description simply names it. A font that was sent but drawn with nowhere is not kept, and a render that failed keeps nothing at all. An account that draws with the fonts already on the server keeps nothing either.
The second is a line raised when the server breaks on its own side, so that somebody here is woken. It names the sort of failure, the account, the number your answer quoted and the moment, and nothing your description chose. It waits in a small file until this site has taken it, and leaves it as soon as it has.
Nothing about the bill travels from the server. This site counts the render off the answer handed back to it and writes one line of its own: the name of the account, one identifier standing for that single render, the moment it happened, and how many pages came out. Nothing of what is written on those pages goes with it.
The server keeps a log, as any program on a machine does. It writes a line for every document that comes out, holding the name of the account, how many pages came out and how long it took. It writes another when a render mentions something it then never used — a font, a picture, a colour nothing selected — carrying the name of the account and the remark. The pages come back either way: it is a remark, not a refusal.
If you run the server on your own machines, none of this reaches us at all. The reporting is switched on by naming an address to send it to, and a server that has not been given one sends nothing anywhere.
How is the server called, and in what form?
One address takes the work, and the request is posted to it as a form. One part of that form carries the description of the document, written as ordinary text. Every other part is a file the document draws on. What comes back is the PDF itself.
Anything able to send a form across the network can call it, whatever it is written in. The table above names the address, the shape and the answer exactly, and the short example below is a whole working request.
What does this bring over a free PDF library?
A great many documents are written every day with free PDF libraries, and several of them are very good at what they set out to do. What is sold here is a different thing: one piece that already covers the whole of the ground, and somebody who answers for it.
The ground is wide. Text that flows, tables that carry on over as many pages as they need, pictures, printing colours, barcodes, forms to fill in, files made to still open decades from now, files made to be read aloud to somebody who cannot see the page, and the room left for a seal. One thing to learn, one thing to keep up to date, and one place to write to when a page does not come out as you expected.
It is checked from outside. There is a free checker called veraPDF whose whole job is to open a file and say whether it follows the published rules, and every archival document shown on this site goes through it. We own no part of it, and it knows nothing about who wrote the file in front of it.
The same document is written three ways — a Rust program, a Python program, and a request to the server — and the three are re-run and compared. Where they come out the same to the byte, it is written down beside them; where they come out the same to the eye but not to the byte, that is written down too.
And there is a contract, a company, and a person to write to. Putting several free pieces together is a fine way to work, and it is also work that somebody has to do and go on doing: when two of them disagree, finding out why is yours. Here it is ours.
The library bought outright stays yours: paid once, installed as often as you like, and it does not stop working the day anything runs out.
Do I have to install anything?
On a subscription, no. You call an address across the network and the pages come back. Nothing goes on your machines and nothing has to be kept up to date.
If you buy the server, it is one program to start on your own machines, with a handful of settings: where its fonts live, where its licence key lives, and how many pages one document may run to. It listens on the machine itself and sits behind whatever front server you already run.
If you buy the library on its own, it goes inside your program like any other part of it, from Rust or from Python. No server, no network, nothing running beside it.
How am I billed?
By the document. Each render is reported once, with the number of pages it created, and a month of them is added up into one bill. A document counts as one, however many pages come out of it: the page count is written down beside the render and never charged for.
A report that could not be sent straight away is not lost: it waits and goes later. And a report that arrives twice is counted once, because each render carries an identifier of its own.
Which programming languages can call it?
All of them. The request is ordinary text sent across the network, so anything able to do that can ask for a document — which is every language in everyday use.
The library underneath is written in Rust and is called from Python just as readily, which is what a team buying the library on its own works with.
What does the free version do?
It creates documents, and it signs its work. Every page it produces comes out with a watermark, and every letter on those pages is traced as a shape instead of being written as text, so the pages look right and nothing can be lifted out of them.
A few things need a licence key. A free copy asked for one of them refuses, says so plainly, and names the licence key that covers it: setting text in one of the fourteen fonts all reading software already carries or in either of the two older kinds of font, and taking a page from another document that holds more than ten thousand words of its own. A free copy sets text only in a font that gives a glyph to trace: one your request carries with it, or one the service already holds.
Which rules are really checked, and by whom?
Files made to stay readable for years, and files made to be read aloud to somebody who cannot see the page, are put through veraPDF, the free checker named above, and it accepts them. It is run by the Open Preservation Foundation and the PDF Association, and we own no part of either.
Files meant for a printing press are held to four requirements before a single byte is written, and a file short of one of them is refused rather than written. The page on printing standards names the four.
How do I know the service is answering?
There is a second address whose only job is to say so. It creates nothing, costs nothing to ask, and answers for as long as the service is up.
Counting your documents never delays a render. The pages come back first, and the count goes on its own afterwards.
Where to go next
Everything the library puts on a page Everything the service keeps, in full What is held about you, and for how long Files made to still open decades from now Files a printing works runs without asking