# PDF-Dokumente zusammenführen

Kombinieren Sie mehrere PDF-Dokumente zu einem einzigen, in der Reihenfolge, in der Sie sie angeben.

Kombinieren Sie mehrere PDF-Dokumente zu einem einzigen. Die Dateien werden
genau in der Reihenfolge zusammengeführt, in der sie in der Anfrage erscheinen,
sodass Sie die endgültige Seitenreihenfolge bestimmen. Senden Sie in einem
einzigen Aufruf so viele Dateien, wie Sie benötigen. Die API ist *stateless*:
Ihr Dokument wird in der Region verarbeitet und niemals gespeichert.

## Endpoint

<Endpoint method="POST" path="/v1/merge_documents" />

In allen Regionen verfügbar. Hinweise zu Routing und Datenresidenz finden Sie
unter [Regionen und Datenresidenz](/docs/api/regions-and-data-residency).

| Region                 | URL                                                 |
| ---------------------- | --------------------------------------------------- |
| Global                 | `https://api.pdfblocks.com/v1/merge_documents`      |
| USA                    | `https://us.api.pdfblocks.com/v1/merge_documents`   |
| HIPAA USA              | `https://hipaa.api.pdfblocks.com/v1/merge_documents` |
| Europäische Union      | `https://eu.api.pdfblocks.com/v1/merge_documents`   |
| Vereinigtes Königreich | `https://uk.api.pdfblocks.com/v1/merge_documents`   |
| Kanada                 | `https://ca.api.pdfblocks.com/v1/merge_documents`   |
| Australien             | `https://au.api.pdfblocks.com/v1/merge_documents`   |
| Japan                  | `https://jp.api.pdfblocks.com/v1/merge_documents`   |
| Indien                 | `https://in.api.pdfblocks.com/v1/merge_documents`   |
| Brasilien              | `https://br.api.pdfblocks.com/v1/merge_documents`   |

## Authentifizierung

Authentifizieren Sie jede Anfrage mit Ihrem geheimen API-Schlüssel im Header
`X-API-Key`, über HTTPS. Schlüssel erstellen und verwalten Sie im
[Dashboard](https://dashboard.pdfblocks.com). Einzelheiten finden Sie unter
[Authentifizierung](/docs/api/authentication).

## Anfrage

Der Endpoint nimmt einen Anfragetext vom Typ `multipart/form-data` entgegen.

<ParamField name="file" type="file[]" required>
  Die PDF-Eingabedokumente, gesendet als wiederholte `file`-Teile. Geben Sie
  mindestens einen an; senden Sie in einer einzigen Anfrage so viele Dateien,
  wie Sie benötigen. Die Dokumente werden genau in der Reihenfolge
  zusammengeführt, in der die Teile in der Anfrage erscheinen. Siehe [Mit
  Dateien arbeiten](/docs/api/working-with-files) dazu, wie mehrere
  `file`-Teile gesendet werden.
</ParamField>

## Beispiele

Führen Sie drei PDFs in der angegebenen Reihenfolge zu einem einzigen zusammen:

<CodeGroup>

```bash title="cURL"
curl https://api.pdfblocks.com/v1/merge_documents \
  -H 'X-API-Key: your_api_key' \
  -F file=@chapter-1.pdf \
  -F file=@chapter-2.pdf \
  -F file=@chapter-3.pdf \
  -o merged.pdf
```

```python title="Python"
# pip install requests
import requests

files = [
    ('file', open('chapter-1.pdf', 'rb')),
    ('file', open('chapter-2.pdf', 'rb')),
    ('file', open('chapter-3.pdf', 'rb')),
]

response = requests.post(
    'https://api.pdfblocks.com/v1/merge_documents',
    headers={'X-API-Key': 'your_api_key'},
    files=files,
)

response.raise_for_status()
with open('merged.pdf', 'wb') as output:
    output.write(response.content)
```

```javascript title="Node.js"
// Node.js 18+
import { readFile, writeFile } from 'node:fs/promises';

const body = new FormData();
body.append('file', new Blob([await readFile('chapter-1.pdf')]), 'chapter-1.pdf');
body.append('file', new Blob([await readFile('chapter-2.pdf')]), 'chapter-2.pdf');
body.append('file', new Blob([await readFile('chapter-3.pdf')]), 'chapter-3.pdf');

const response = await fetch('https://api.pdfblocks.com/v1/merge_documents', {
  method: 'POST',
  headers: { 'X-API-Key': 'your_api_key' },
  body,
});

if (!response.ok) throw new Error(`Request failed: ${response.status}`);
await writeFile('merged.pdf', Buffer.from(await response.arrayBuffer()));
```

```php title="PHP"
<?php
// composer require guzzlehttp/guzzle
require 'vendor/autoload.php';

use GuzzleHttp\Client;

// Repeat the `file` part once per document: they merge in the order sent.
$response = (new Client())->post('https://api.pdfblocks.com/v1/merge_documents', [
    'headers' => ['X-API-Key' => 'your_api_key'],
    'multipart' => [
        ['name' => 'file', 'contents' => fopen('chapter-1.pdf', 'r'), 'filename' => 'chapter-1.pdf'],
        ['name' => 'file', 'contents' => fopen('chapter-2.pdf', 'r'), 'filename' => 'chapter-2.pdf'],
        ['name' => 'file', 'contents' => fopen('chapter-3.pdf', 'r'), 'filename' => 'chapter-3.pdf'],
    ],
]);

if ($response->getStatusCode() === 200) {
    file_put_contents('merged.pdf', $response->getBody());
}
```

```ruby title="Ruby"
# gem install http
require 'http'

response = HTTP
  .headers('X-API-Key' => 'your_api_key')
  .post('https://api.pdfblocks.com/v1/merge_documents', form: {
    file: [
      HTTP::FormData::File.new('chapter-1.pdf'),
      HTTP::FormData::File.new('chapter-2.pdf'),
      HTTP::FormData::File.new('chapter-3.pdf'),
    ],
  })

File.write('merged.pdf', response.body) if response.status.success?
```

```go title="Go"
package main

import (
	"bytes"
	"io"
	"mime/multipart"
	"net/http"
	"os"
)

func main() {
	var buf bytes.Buffer
	form := multipart.NewWriter(&buf)

	for _, name := range []string{"chapter-1.pdf", "chapter-2.pdf", "chapter-3.pdf"} {
		file, _ := os.Open(name)
		part, _ := form.CreateFormFile("file", name)
		io.Copy(part, file)
		file.Close()
	}
	form.Close()

	req, _ := http.NewRequest("POST", "https://api.pdfblocks.com/v1/merge_documents", &buf)
	req.Header.Set("Content-Type", form.FormDataContentType())
	req.Header.Set("X-API-Key", "your_api_key")

	res, _ := http.DefaultClient.Do(req)
	defer res.Body.Close()

	out, _ := os.Create("merged.pdf")
	defer out.Close()
	io.Copy(out, res.Body)
}
```

```csharp title="C#"
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-API-Key", "your_api_key");

using var form = new MultipartFormDataContent
{
    { new ByteArrayContent(File.ReadAllBytes("chapter-1.pdf")), "file", "chapter-1.pdf" },
    { new ByteArrayContent(File.ReadAllBytes("chapter-2.pdf")), "file", "chapter-2.pdf" },
    { new ByteArrayContent(File.ReadAllBytes("chapter-3.pdf")), "file", "chapter-3.pdf" },
};

var response = await client.PostAsync(
    "https://api.pdfblocks.com/v1/merge_documents", form);
response.EnsureSuccessStatusCode();
await File.WriteAllBytesAsync(
    "merged.pdf", await response.Content.ReadAsByteArrayAsync());
```

</CodeGroup>

## Antwort

Bei Erfolg lautet die Antwort `200 OK` mit dem zusammengeführten PDF als
Antworttext:

```http
HTTP/1.1 200 OK
Content-Type: application/pdf
Content-Length: 96124
```

Die Ausgabe ist ein einzelnes PDF, dessen Seitenzahl der Summe der Seitenzahlen
der Eingabedokumente entspricht, angeordnet in der Reihenfolge der Anfrage.
Schreiben Sie den Antworttext direkt in eine Datei, wie es die Beispiele oben
tun; auf unserer Seite wird nichts gespeichert.

## Fehler

Fehlgeschlagene Anfragen liefern einen Antworttext vom Typ
`application/problem+json`. Am häufigsten ist bei diesem Endpoint der Status
`400`, der zurückgegeben wird, wenn einer der `file`-Teile kein lesbares PDF
ist. Das Objekt `errors` nennt das betroffene Feld:

```json
{
  "type": "https://www.pdfblocks.com/docs/api/v1/error/400",
  "title": "One or more validation errors occurred.",
  "status": 400,
  "errors": {
    "file": ["Could not parse the PDF document. The file may be invalid or corrupt."]
  }
}
```

Ein fehlender oder ungültiger `X-API-Key` gibt einen `401` zurück. Alle
Statuscodes und die vollständige Form der Antwort finden Sie unter
[Fehler](/docs/api/errors).

## Rezepte

Häufige Varianten. Klappen Sie eine auf, um sie in jeder Sprache zu sehen.

<AccordionGroup>

<Accordion title="Ein Deckblatt vor einen Bericht setzen">

<CodeGroup>

```bash title="cURL"
curl https://api.pdfblocks.com/v1/merge_documents \
  -H 'X-API-Key: your_api_key' \
  -F file=@cover.pdf \
  -F file=@report.pdf \
  -o report-with-cover.pdf
```

```python title="Python"
import requests

files = [
    ('file', open('cover.pdf', 'rb')),
    ('file', open('report.pdf', 'rb')),
]

response = requests.post(
    'https://api.pdfblocks.com/v1/merge_documents',
    headers={'X-API-Key': 'your_api_key'},
    files=files,
)

response.raise_for_status()
with open('report-with-cover.pdf', 'wb') as output:
    output.write(response.content)
```

```javascript title="Node.js"
import { readFile, writeFile } from 'node:fs/promises';

const body = new FormData();
body.append('file', new Blob([await readFile('cover.pdf')]), 'cover.pdf');
body.append('file', new Blob([await readFile('report.pdf')]), 'report.pdf');

const response = await fetch('https://api.pdfblocks.com/v1/merge_documents', {
  method: 'POST',
  headers: { 'X-API-Key': 'your_api_key' },
  body,
});

if (!response.ok) throw new Error(`Request failed: ${response.status}`);
await writeFile('report-with-cover.pdf', Buffer.from(await response.arrayBuffer()));
```

```php title="PHP"
<?php
// composer require guzzlehttp/guzzle
require 'vendor/autoload.php';

use GuzzleHttp\Client;

$response = (new Client())->post('https://api.pdfblocks.com/v1/merge_documents', [
    'headers' => ['X-API-Key' => 'your_api_key'],
    'multipart' => [
        ['name' => 'file', 'contents' => fopen('cover.pdf', 'r'), 'filename' => 'cover.pdf'],
        ['name' => 'file', 'contents' => fopen('report.pdf', 'r'), 'filename' => 'report.pdf'],
    ],
]);

if ($response->getStatusCode() === 200) {
    file_put_contents('report-with-cover.pdf', $response->getBody());
}
```

```ruby title="Ruby"
require 'http'

response = HTTP
  .headers('X-API-Key' => 'your_api_key')
  .post('https://api.pdfblocks.com/v1/merge_documents', form: {
    file: [
      HTTP::FormData::File.new('cover.pdf'),
      HTTP::FormData::File.new('report.pdf'),
    ],
  })

File.write('report-with-cover.pdf', response.body) if response.status.success?
```

```go title="Go"
package main

import (
	"bytes"
	"io"
	"mime/multipart"
	"net/http"
	"os"
)

func main() {
	var buf bytes.Buffer
	form := multipart.NewWriter(&buf)

	for _, name := range []string{"cover.pdf", "report.pdf"} {
		file, _ := os.Open(name)
		part, _ := form.CreateFormFile("file", name)
		io.Copy(part, file)
		file.Close()
	}
	form.Close()

	req, _ := http.NewRequest("POST", "https://api.pdfblocks.com/v1/merge_documents", &buf)
	req.Header.Set("Content-Type", form.FormDataContentType())
	req.Header.Set("X-API-Key", "your_api_key")

	res, _ := http.DefaultClient.Do(req)
	defer res.Body.Close()

	out, _ := os.Create("report-with-cover.pdf")
	defer out.Close()
	io.Copy(out, res.Body)
}
```

```csharp title="C#"
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-API-Key", "your_api_key");

using var form = new MultipartFormDataContent
{
    { new ByteArrayContent(File.ReadAllBytes("cover.pdf")), "file", "cover.pdf" },
    { new ByteArrayContent(File.ReadAllBytes("report.pdf")), "file", "report.pdf" },
};

var response = await client.PostAsync(
    "https://api.pdfblocks.com/v1/merge_documents", form);
response.EnsureSuccessStatusCode();
await File.WriteAllBytesAsync(
    "report-with-cover.pdf", await response.Content.ReadAsByteArrayAsync());
```

</CodeGroup>

</Accordion>

</AccordionGroup>

## Verwandte Aktionen

<CardGroup cols={2}>

<Card title="Seiten extrahieren" href="/docs/api/extract-pages-from-pdf">
  Holen Sie eine Teilmenge von Seiten aus der zusammengeführten Datei heraus.
</Card>

<Card title="Seiten neu anordnen" href="/docs/api/reorder-pages-of-pdf">
  Ordnen Sie die Seiten nach dem Zusammenführen neu an.
</Card>

<Card title="An einer Seite aufteilen" href="/docs/api/split-pdf-at-page">
  Nehmen Sie das kombinierte Dokument wieder auseinander.
</Card>

<Card title="Textwasserzeichen hinzufügen" href="/docs/api/add-text-watermark-to-pdf">
  Bringen Sie ein Wasserzeichen auf das zusammengeführte Dokument auf.
</Card>

</CardGroup>
