How-to2026-09-2810 min. lezen

TypeScript-SDK voor de PDF-API: vijf minuten tot de eerste aanroep, en wat u zelf moet regelen

Gebruik @pdf123/sdk vanuit TypeScript om bestanden samen te voegen, watermerken toe te voegen, bestandsinfo uit te lezen en meerdere tools in één verzoek te koppelen. De SDK vangt een verkeerd gespelde toolnaam of parameter af voordat er iets is geüpload; weigeringen van de server bevatten een reden en een hint, terwijl nieuwe pogingen, annuleren en gedeeltelijke mislukkingen in een batch aan u zijn.

PDF123 · Updated 2026-09-28

Als u de PDF-API vanuit Node aanroept, vangt de software development kit (SDK) @pdf123/sdk een verkeerd gespelde toolnaam of parameter af voordat er een bestand wordt geüpload. De SDK probeert niet opnieuw, annuleert niet voor u en streamt geen resultaten. new Pdf123Client() wijst standaard anoniem naar https://pdf123.xyz; uw bestanden worden daar geüpload en daar verwerkt, want er is geen lokale engine.

Diagram: één aanroep passeert achtereenvolgens drie poorten, de tsc-controle bij het compileren, validatie tijdens de uitvoering voordat het verzoek wordt verstuurd, en de 400 die de server na de upload teruggeeft; nieuwe pogingen en annuleren laat de SDK aan de aanroeper, en invoer van samen meer dan 95 MiB wordt automatisch in delen geüpload

Twee PDF's in een map zijn genoeg om samen te voegen

U hebt Node 20.3 of nieuwer nodig, of Bun. Het pakket is een ES-module: zet de code in een .mjs-bestand, of voer eerst npm pkg set type=module uit. Zet a.pdf en b.pdf in de huidige map.

npm install @pdf123/sdk
// merge.mjs
import { Pdf123Client } from "@pdf123/sdk";
import { readFileInput, saveResult } from "@pdf123/sdk/node";

const client = new Pdf123Client();
const merged = await client.run("merge", {
  input: [await readFileInput("a.pdf"), await readFileInput("b.pdf")],
});
console.log(await saveResult(merged, { output: "merged.pdf" }));

Na node merge.mjs toont de terminal het uitvoerpad dat u hebt opgegeven, merged.pdf, en staat het bestand in de huidige map. readFileInput en saveResult zitten in @pdf123/sdk/node. Het hoofdingangspunt hangt alleen af van fetch en neemt invoer aan als gewone { name, data }, dus een omgeving zonder bestandssysteem kan dezelfde client gebruiken. Een resultaat is { data, contentType, filename, json }; data is een volledige Uint8Array, en Buffer.from(result.data) geeft u een Buffer.

PDF's samenvoegen is slechts één van de tools.

Bestanden komen terug in data, rapporten in json

Elke tool wordt aangeroepen als client.run(toolName, { input, params }). De code hieronder gaat verder op merge.mjs uit de vorige sectie, met client en saveResult al binnen bereik. Waar u het resultaat leest, hangt af van het veld returns uit getTool, dat "file" of "json" is: gebruik data voor het eerste en json voor het tweede.

import { getTool } from "@pdf123/sdk";
import { readFileInput, saveResult } from "@pdf123/sdk/node";

// client komt uit merge.mjs in de vorige sectie
const marked = await client.run("watermark", {
  input: await readFileInput("a.pdf"),
  params: { watermarkText: "DRAFT", fontSize: 40 },
});
console.log(await saveResult(marked, { output: "marked.pdf" }));

const info = await client.run("get-info", { input: await readFileInput("a.pdf") });
console.log(info.json.FileSize, info.json.Encrypted);
console.log(getTool("get-info")?.returns); // "json"

Het eerste blok schrijft het bestand met watermerk naar marked.pdf; in het tweede is info.json het rapport. U hoeft veldnamen, standaardwaarden of toegestane waarden niet te onthouden: getTool("watermark")?.fields is die catalogus, en pdfx describe watermark op de opdrachtregel leest dezelfde. TOOLS bevat alle 95 tools. De volledige referentie staat in de SDK-gids op de ontwikkelaarspagina.

Om samen te voegen, dan een watermerk toe te voegen en dan te comprimeren, kunt u pipeline gebruiken of drie run-aanroepen achter elkaar; wat het wordt hangt ervan af of u de tussenbestanden wilt hebben. Ook dit gaat verder op de client hierboven. pipeline vouwt de drie stappen samen tot één verzoek, de tussenresultaten blijven op de server, en de aanroeper krijgt alleen de laatste stap, die de code hieronder naar out.pdf schrijft. Wilt u het bestand van elke stap, roep de tools dan afzonderlijk aan.

const result = await client.pipeline(
  [{ tool: "merge" }, { tool: "watermark", params: { watermarkText: "DRAFT" } }, { tool: "compress" }],
  [await readFileInput("a.pdf"), await readFileInput("b.pdf")],
);
console.log(await saveResult(result, { output: "out.pdf" }));

Een pipeline heeft maximaal 8 stappen. Een 9e stap levert HTTP 400: at most 8 pipeline steps allowed op.

Anoniem, met een sleutel, of gericht op uw eigen server

Als u PDFX_API_BASE instelt en toch bij https://pdf123.xyz uitkomt, komt dat doordat new Pdf123Client() geen omgevingsvariabelen leest; het kijkt alleen naar de opties van de constructor.

Voor anonieme aanroepen gebruikt u die constructor zoals hij is. Met een sleutel schrijft u new Pdf123Client({ apiKey: process.env.PDFX_API_KEY }); de verzoekheader is X-API-KEY.

Om naar uw eigen server te wijzen gebruikt u clientFromEnv() uit @pdf123/sdk/node. Die leest PDFX_API_BASE en PDFX_API_KEY. U kunt ook direct new Pdf123Client({ baseUrl: "http://localhost:8080" }) schrijven. Is het adres onbereikbaar, dan mislukt de aanroep; een offlinemodus bestaat niet. Wat het oplevert en wat het kost als bestanden binnen uw eigen netwerk blijven, staat in Wat self-hosting u echt oplevert (en wat het kost).

Een verkeerde parameter wordt vóór de upload afgevangen

Zonder dit zou het bestand eerst worden geüpload en zou een verkeerd gespelde veldnaam pas als 400 van de server opduiken. De parametertypen van elke tool worden uit de catalogus gegenereerd, dus drie veelvoorkomende misstappen mislukken al in de tsc-fase:

Wat u schrijft Compilerfout (fragment)
client.run("rotat", { input }) Argument of type '"rotat"' is not assignable to parameter of type 'ToolId'
params: { watermarkTxt: "DRAFT" } Object literal may only specify known properties, but 'watermarkTxt' does not exist, ending with Did you mean to write 'watermarkText'?
params: { angle: 45 } (rotate accepteert alleen 90, 180, 270) Type '45' is not assignable to type …, followed by the allowed values

Juiste aanroepen zoals { angle: 90 } of { watermarkText: "DRAFT", fontSize: 30 } compileren. Numerieke velden accepteren zowel getallen als strings, dus fontSize: 30 en fontSize: "30" zijn gelijkwaardig. Een project dat geen TypeScript gebruikt, krijgt dezelfde fouten tijdens de uitvoering, en het verzoek wordt nooit verstuurd: het derde geval geeft Field "angle" of "rotate" must be one of: 90, 180, 270, en een verkeerd gespelde toolnaam geeft unknown_tool, met gelijkende namen in het bericht.

Als de server weigert, vertakt u op reason

Weigert de server een verzoek, dan gooit de SDK een Pdf123Error met status, code, reason en problem.hint. Eén code kan meerdere reason-waarden hebben, dus controleer eerst reason en val terug op code. Drie veelvoorkomende fouten, lokaal uitgevoerd met dezelfde invoer, zien er zo uit:

Invoer status code reason hint (het origineel is in het Engels)
Versleutelde PDF, geen wachtwoord opgegeven 400 bad_request password_required Provide the document password, or unlock the PDF first
Verkeerd wachtwoord 400 bad_request wrong_password Check the password and try again
Geen PDF, of een beschadigd bestand 400 invalid_document invalid_pdf Upload a valid, undamaged PDF; you can try repairing it first
import { Pdf123Client, Pdf123Error } from "@pdf123/sdk";
import { readFileInput } from "@pdf123/sdk/node";

const client = new Pdf123Client();
const input = await readFileInput("locked.pdf");
try {
  await client.run("compress", { input });
} catch (error) {
  if (!(error instanceof Pdf123Error)) throw error;
  console.error(error.status, error.code, error.reason, error.problem?.hint);
  if (error.reason === "password_required") {
    await client.run("compress", { input, password: "secret" });
  }
}

Kent u het wachtwoord, geef dan voor één bestand password mee; ontgrendelen en de doeltool gebeuren in hetzelfde verzoek. Probeer bij een beschadigd bestand eerst PDF repareren.

"Geen resultaat" moet u uit elkaar houden. Vindt PDF naar CSV geen tabel in de PDF, dan geeft de server 204 terug en gooit de SDK code: "no_content"; de reden staat in Lege tabelexport (204): uw PDF heeft waarschijnlijk geen kolommen. Voorwaardelijke filtertools behandelen een onwaar geworden voorwaarde als een normale uitkomst: ze gooien niets en geven matched: false terug met een lege data.

Nieuwe pogingen, geheugen en annuleren zijn het werk van de aanroeper

Netwerkfouten en 5xx-antwoorden worden ongewijzigd gegooid; de SDK probeert nooit uit zichzelf opnieuw. Geef bij een verzoek dat iets wijzigt uw eigen idempotencyKey mee: opnieuw versturen met dezelfde sleutel geeft het eerste resultaat terug in plaats van opnieuw te verwerken, en het mechanisme en de limieten staan in Idempotency-Key: veilige nieuwe pogingen voor PDF-taken. Resultaten worden in hun geheel in het geheugen gelezen, zonder streaming. Zijn invoer en uitvoer allebei groot, tel dan het geheugen mee dat ze tegelijk innemen.

Annuleren en een time-out zijn twee verschillende code-waarden, en één aanroep meldt er maar één: die welke als eerste optreedt. Het voorbeeld hieronder test ze in twee afzonderlijke aanroepen, zodat beide takken echt kunnen draaien:

import { Pdf123Client, Pdf123Error } from "@pdf123/sdk";
import { readFileInput } from "@pdf123/sdk/node";

const client = new Pdf123Client();
const input = await readFileInput("a.pdf");

const controller = new AbortController();
setTimeout(() => controller.abort(), 10_000);
try {
  await client.run("compress", { input, signal: controller.signal });
} catch (error) {
  if (error instanceof Pdf123Error && error.code === "cancelled") { /* u hebt het zelf geannuleerd */ }
}

try {
  await client.run("compress", { input, timeoutMs: 60_000 });
} catch (error) {
  if (error instanceof Pdf123Error && error.code === "timeout") { /* timeoutMs overschreden; nu zonder signal */ }
}

Zodra het afbreeksignaal (AbortSignal) afgaat, wordt het verzoek afgewezen met code: "cancelled"; overschrijding van de time-out geeft code: "timeout". Elk verzoek heeft een standaardtime-out van 5 minuten, die u kunt wijzigen bij het aanmaken van de client of per aanroep kunt overschrijven met timeoutMs. Bij een upload in delen krijgt elk verzoek die time-out afzonderlijk. Annuleren sluit alleen deze verbinding; er is geen garantie dat de server stopt met verwerken.

Eén bestand mislukt, de rest gaat door, en callbacks komen in volgorde van voltooiing

Voor een batch met invoer voor een tool voor één bestand gebruikt u runBatch. Mislukt één bestand, dan gaan de andere door. onResult wordt aangeroepen op het moment dat elk bestand klaar is, dus in volgorde van voltooiing, en index is de positie van het bestand in de invoerarray; de teruggegeven array staat altijd in invoervolgorde. Schrijf de bytes binnen deze callback naar schijf: retainData: false leegt data zodra de callback terugkeert, dus een resultaat dat u hier niet met saveResult bewaart, is weg. Wordt de run onderbroken, dan blijven de al geschreven bestanden staan.

Neem aan dat de map drie goede PDF's bevat, a.pdf, b.pdf en een versleutelde locked.pdf (wachtwoord secret), plus een kapot bestand broken.pdf met slechts een paar ingetypte tekens:

import { Pdf123Client } from "@pdf123/sdk";
import { fileSource, saveResult } from "@pdf123/sdk/node";

const client = new Pdf123Client();
const results = await client.runBatch("compress", [
  fileSource("a.pdf"), fileSource("broken.pdf"), fileSource("b.pdf"), fileSource("locked.pdf"),
], {
  concurrency: 2,
  passwordFor: (file) => (file.name === "locked.pdf" ? "secret" : undefined),
  onResult: async (entry, index) => {
    console.log(index, entry.input.name, entry.ok ? "ok" : entry.error.reason);
    if (entry.ok) await saveResult(entry.result, { output: "out/" });
  },
  retainData: false,
});

Standaard worden twee bestanden tegelijk verwerkt; wijzig dat met concurrency. fileSource(path) leest een bestand pas van schijf wanneer het aan de beurt is, dus een grote batch grote bestanden zit nooit helemaal tegelijk in het geheugen. Met passwordFor kan een batch met vergrendelde en niet-vergrendelde bestanden in één keer draaien. Toen de vier bestanden hierboven lokaal werden uitgevoerd, kreeg de callback:

1 broken.pdf invalid_pdf
0 a.pdf ok
2 b.pdf ok
3 locked.pdf ok

De volgorde van voltooiing kan bij elke run verschillen; dit is gewoon hoe één run eruitzag. retainData: false maakt data in de teruggegeven array leeg; de geslaagde bestanden zijn al door de saveResult hierboven naar out/ geschreven. Geeft u idempotencyKey mee aan runBatch, dan is de sleutel die voor elk bestand daadwerkelijk wordt verstuurd <key>:<index>.

Upload in delen begint pas boven 95 MiB in totaal

De body van een direct verzoek is beperkt tot 100 MiB, en alles wat groter is wordt geweigerd; zie Wanneer een grote PDF-upload wordt geweigerd: de limiet van 100 MiB op de body van een verzoek en de fout die u de verkeerde kant op stuurt voor de details. Tellen alle bestanden in één verzoek op tot meer dan 95 MiB, dan schakelt de SDK over op upload in delen, en uw client.run-aanroep verandert niet. Het standaardmaximum van de server voor één upload is 500 MiB; als u zelf host, past u dat aan met PDFX_UPLOAD_MAX_BYTES.

Voor dezelfde bewerking in curl, MCP en de opdrachtregel, zie Zelfde operatie, vier clients: browser, curl, MCP, pdfx: dat artikel zet de vier aanroepen naast elkaar, en dit artikel werkt alleen de SDK uit. De pagina van het pakket op npm is @pdf123/sdk.

Open tool
Process in the browser — no watermark, files removed after the job.
Open tool