# Requests and responses
Every request is multipart/form-data with the PDF in a file field, and single-output responses are application/pdf. The uniform, stateless contract behind every action.
Every action in the API shares one contract. You send a `multipart/form-data`
request with your PDF in a `file` field, and you get the processed document back
as the response body. There is no job to poll, no upload step, and no resource to
clean up afterward — one request in, one document out. Learn this shape once and
every action page reads the same way.
## Every request looks the same
Each action is a single `POST` to `/v1/<action>` with a `multipart/form-data`
body. Three things are always present:
- The `X-API-Key` header carrying your secret key, over HTTPS.
- A `file` part containing the input PDF.
- Zero or more string parts for the action's options (for example `line_1` or
`pages`), named exactly as the action reference lists them.
Here is a complete request that stamps a watermark, shown as raw HTTP:
```http
POST /v1/add_text_watermark HTTP/1.1
Host: api.pdfblocks.com
X-API-Key: your_api_key
Content-Type: multipart/form-data; boundary=----PdfBlocksBoundary
------PdfBlocksBoundary
Content-Disposition: form-data; name="file"; filename="input.pdf"
Content-Type: application/pdf
%PDF-1.7
<binary PDF bytes>
------PdfBlocksBoundary
Content-Disposition: form-data; name="line_1"
CONFIDENTIAL
------PdfBlocksBoundary--
```
Reading it part by part:
- **Request line** — `POST /v1/add_text_watermark`. The action name is the path;
the method is always `POST`.
- **`X-API-Key`** — your key authenticates the request. See
[Authentication](/docs/api/authentication).
- **`Content-Type`** — `multipart/form-data` with a boundary string. Any HTTP
client's multipart helper sets this header and the boundary for you; you rarely
write it by hand.
- **The `file` part** — the input PDF, sent as binary.
- **Option parts** — one part per option, here `line_1`. Each is a plain string
value.
You never assemble that body yourself. Every language's HTTP client builds it
from a file handle and a few fields. The same request in cURL:
```bash title="cURL"
curl https://api.pdfblocks.com/v1/add_text_watermark \
-H 'X-API-Key: your_api_key' \
-F file=@input.pdf \
-F line_1='CONFIDENTIAL' \
-o watermarked.pdf
```
<Info>
The default base URL is `https://api.pdfblocks.com`. To keep processing in a
specific jurisdiction, swap the host for a regional one — see
[Regions and data residency](/docs/api/regions-and-data-residency). Only the
host changes; the path, headers, and body are identical everywhere.
</Info>
## Every response is the document
A single-output action responds with `200 OK` and the processed PDF as the raw
body:
```http
HTTP/1.1 200 OK
Content-Type: application/pdf
Content-Length: 48213
%PDF-1.7
<binary PDF bytes>
```
The body is the finished document — not JSON wrapping a URL, and not a base64
string. Stream it straight to a file or pass it to the next step in your
pipeline. In cURL that is the `-o watermarked.pdf` above; in code it is writing
`response` bytes to disk, exactly as the examples on each action page do.
## Stateless by design
The API stores nothing. Your document is processed in memory, in the region you
address, and discarded as soon as the response is written. There is no document
ID to reference later and no server-side copy to delete. Because nothing
persists between calls, each request must carry its own input `file` — including
when you chain actions, where you feed one call's output straight into the next
(see [Chaining actions](/docs/api/chaining-actions)).
## Where the contract varies
Three things sit on top of this baseline, each documented on its own page:
- **More than one input.** [Merge documents](/docs/api/merge-pdf-documents) takes
an ordered array of `file` parts, and
[Add an image watermark](/docs/api/add-image-watermark-to-pdf) takes a second
binary `image` part. Both are covered in
[Working with files](/docs/api/working-with-files).
- **More than one output.** The split family returns several documents, and you
choose the packaging — ZIP, JSON, or multipart — with the `Accept` header. See
[Response formats](/docs/api/response-formats).
- **Failures.** Any error returns an `application/problem+json` body following
RFC 7807, never a partial PDF. See [Errors](/docs/api/errors).
Every request is multipart/form-data with the PDF in a file field, and single-output responses are application/pdf. The uniform, stateless contract behind every action.
Every action in the API shares one contract. You send a multipart/form-data
request with your PDF in a file field, and you get the processed document back
as the response body. There is no job to poll, no upload step, and no resource to
clean up afterward — one request in, one document out. Learn this shape once and
every action page reads the same way.
Each action is a single POST to /v1/<action> with a multipart/form-data
body. Three things are always present:
The X-API-Key header carrying your secret key, over HTTPS.
A file part containing the input PDF.
Zero or more string parts for the action’s options (for example line_1 or
pages), named exactly as the action reference lists them.
Here is a complete request that stamps a watermark, shown as raw HTTP:
POST /v1/add_text_watermark HTTP/1.1Host: api.pdfblocks.comX-API-Key: your_api_keyContent-Type: multipart/form-data; boundary=----PdfBlocksBoundary------PdfBlocksBoundaryContent-Disposition: form-data; name="file"; filename="input.pdf"Content-Type: application/pdf%PDF-1.7<binary PDF bytes>------PdfBlocksBoundaryContent-Disposition: form-data; name="line_1"CONFIDENTIAL------PdfBlocksBoundary--
Reading it part by part:
Request line — POST /v1/add_text_watermark. The action name is the path;
the method is always POST.
X-API-Key — your key authenticates the request. See
Authentication.
Content-Type — multipart/form-data with a boundary string. Any HTTP
client’s multipart helper sets this header and the boundary for you; you rarely
write it by hand.
The file part — the input PDF, sent as binary.
Option parts — one part per option, here line_1. Each is a plain string
value.
You never assemble that body yourself. Every language’s HTTP client builds it
from a file handle and a few fields. The same request in cURL:
The default base URL is https://api.pdfblocks.com. To keep processing in a
specific jurisdiction, swap the host for a regional one — see
Regions and data residency. Only the
host changes; the path, headers, and body are identical everywhere.
A single-output action responds with 200 OK and the processed PDF as the raw
body:
HTTP/1.1 200 OKContent-Type: application/pdfContent-Length: 48213%PDF-1.7<binary PDF bytes>
The body is the finished document — not JSON wrapping a URL, and not a base64
string. Stream it straight to a file or pass it to the next step in your
pipeline. In cURL that is the -o watermarked.pdf above; in code it is writing
response bytes to disk, exactly as the examples on each action page do.
The API stores nothing. Your document is processed in memory, in the region you
address, and discarded as soon as the response is written. There is no document
ID to reference later and no server-side copy to delete. Because nothing
persists between calls, each request must carry its own input file — including
when you chain actions, where you feed one call’s output straight into the next
(see Chaining actions).
More than one output. The split family returns several documents, and you
choose the packaging — ZIP, JSON, or multipart — with the Accept header. See
Response formats.
Failures. Any error returns an application/problem+json body following
RFC 7807, never a partial PDF. See Errors.