PDF Blocks
TarifsSupport
Commencer gratuitement
Ouvrir la page

Fusionner des documents PDF

Combinez plusieurs documents PDF en un seul, dans l’ordre où vous les envoyez.

Combinez plusieurs documents PDF en un seul. Les fichiers sont fusionnés exactement dans l’ordre où ils apparaissent dans la requête : vous contrôlez donc la séquence finale des pages. Envoyez autant de fichiers que nécessaire en un seul appel. L’API est stateless : votre document est traité dans la région et n’est jamais stocké.

Endpoint

POST
/v1/merge_documents

Disponible dans toutes les régions. Consultez Régions et résidence des données pour le routage et la résidence des données.

Région URL
Global https://api.pdfblocks.com/v1/merge_documents
États-Unis https://us.api.pdfblocks.com/v1/merge_documents
HIPAA États-Unis https://hipaa.api.pdfblocks.com/v1/merge_documents
Union européenne https://eu.api.pdfblocks.com/v1/merge_documents
Royaume-Uni https://uk.api.pdfblocks.com/v1/merge_documents
Canada https://ca.api.pdfblocks.com/v1/merge_documents
Australie https://au.api.pdfblocks.com/v1/merge_documents
Japon https://jp.api.pdfblocks.com/v1/merge_documents
Inde https://in.api.pdfblocks.com/v1/merge_documents
Brésil https://br.api.pdfblocks.com/v1/merge_documents

Authentification

Authentifiez chaque requête avec votre clé d’API secrète dans l’en-tête X-API-Key, via HTTPS. Créez et gérez vos clés depuis le dashboard. Consultez Authentification pour plus de détails.

Requête

L’endpoint accepte un corps de requête multipart/form-data.

filefile[]required

Les documents PDF d’entrée, envoyés sous forme de parties file répétées. Fournissez-en au moins une ; envoyez autant de fichiers que nécessaire en une seule requête. Les documents sont fusionnés exactement dans l’ordre où les parties apparaissent dans la requête. Consultez Travailler avec les fichiers pour savoir comment envoyer plusieurs parties file.

Exemples

Fusionnez trois PDF en un seul, dans l’ordre :

cURLbash
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
Pythonpython
# 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)
Node.jsjavascript
// 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()));
PHPphp
<?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());
}
Rubyruby
# 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?
Gogo
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)
}
C#csharp
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());

Réponse

En cas de succès, la réponse est 200 OK et le PDF fusionné constitue le corps :

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

La sortie est un seul PDF dont le nombre de pages est la somme de ceux des documents d’entrée ; ses pages sont disposées dans l’ordre de la requête. Écrivez le corps directement dans un fichier, comme le font les exemples ci-dessus ; rien n’est stocké de notre côté.

Erreurs

Les requêtes en échec renvoient un corps application/problem+json. L’erreur la plus fréquente sur cet endpoint est un 400, renvoyé lorsque l’une des parties file n’est pas un PDF lisible. L’objet errors nomme le champ :

{
  "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."]
  }
}

Une X-API-Key absente ou non valide renvoie un 401. Consultez Erreurs pour tous les codes de statut et la forme complète de la réponse.

Recettes

Variantes courantes. Dépliez-en une pour la voir dans tous les langages.

Placer une page de couverture devant un rapport
cURLbash
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
Pythonpython
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)
Node.jsjavascript
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()));
PHPphp
<?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());
}
Rubyruby
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?
Gogo
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)
}
C#csharp
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());

Actions associées