PPDF123
How-to2026-09-289 menit baca

SDK TypeScript untuk API PDF: lima menit sampai panggilan pertama, dan apa yang diserahkan kepada Anda

Pakai @pdf123/sdk dari TypeScript untuk menggabungkan berkas, menambah tanda air, membaca info berkas, dan merangkai beberapa alat dalam satu permintaan. SDK menangkap nama alat atau parameter yang salah eja sebelum apa pun diunggah; penolakan dari server membawa alasan dan petunjuk, sedangkan percobaan ulang, pembatalan, dan kegagalan sebagian dalam batch menjadi urusan Anda.

PDF123 Β· Updated 2026-09-28

Saat Anda memanggil API PDF dari Node, kit pengembangan perangkat lunak (SDK) @pdf123/sdk menangkap nama alat atau parameter yang salah eja sebelum berkas apa pun diunggah. SDK ini tidak mencoba ulang, tidak membatalkan untuk Anda, dan tidak men-stream hasil. new Pdf123Client() secara bawaan mengarah secara anonim ke https://pdf123.xyz; berkas Anda diunggah dan diproses di sana, karena tidak ada mesin lokal.

Diagram: satu panggilan melewati tiga gerbang berurutan, pemeriksaan tsc saat kompilasi, validasi runtime sebelum permintaan dikirim, dan 400 yang dikembalikan server setelah unggah; percobaan ulang dan pembatalan diserahkan kepada pemanggil, dan input yang totalnya lebih dari 95 MiB diunggah secara otomatis dalam potongan

Dua PDF di satu folder cukup untuk menggabungkan

Anda memerlukan Node 20.3 atau lebih baru, atau Bun. Paketnya adalah modul ES: taruh kode di berkas .mjs, atau jalankan npm pkg set type=module lebih dulu. Letakkan a.pdf dan b.pdf di direktori saat ini.

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" }));

Setelah node merge.mjs, terminal mencetak jalur keluaran yang Anda berikan, merged.pdf, dan berkasnya ada di direktori saat ini. readFileInput dan saveResult berada di @pdf123/sdk/node. Entri akar hanya bergantung pada fetch dan menerima input sebagai { name, data } biasa, sehingga lingkungan tanpa sistem berkas dapat memakai klien yang sama. Hasilnya berbentuk { data, contentType, filename, json }; data adalah Uint8Array utuh, dan Buffer.from(result.data) memberi Anda Buffer.

Gabungkan PDF hanyalah salah satu alat.

Berkas kembali lewat data, laporan lewat json

Setiap alat dipanggil dengan client.run(toolName, { input, params }). Kode di bawah melanjutkan merge.mjs dari bagian sebelumnya, dengan client dan saveResult sudah tersedia. Dari mana hasil dibaca bergantung pada bidang returns dari getTool, yang bernilai "file" atau "json": pakai data untuk yang pertama, json untuk yang kedua.

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

// client berasal dari merge.mjs di bagian sebelumnya
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"

Blok pertama menulis berkas bertanda air ke marked.pdf; pada blok kedua, info.json adalah laporannya. Anda tidak perlu menghafal nama bidang, nilai bawaan, atau nilai yang diizinkan: getTool("watermark")?.fields adalah katalognya, dan pdfx describe watermark di baris perintah membaca katalog yang sama. TOOLS memuat ke-95 alat. Referensi lengkapnya ada di panduan SDK di halaman pengembang.

Untuk menggabungkan, lalu memberi tanda air, lalu mengompres, Anda bisa memakai pipeline atau tiga panggilan run berturut-turut; pilihannya bergantung pada apakah Anda menginginkan berkas antara. Lagi-lagi ini melanjutkan client di atas. pipeline melipat ketiga langkah menjadi satu permintaan, hasil antara tetap di server, dan pemanggil hanya menerima langkah terakhir, yang ditulis kode di bawah ke out.pdf. Jika Anda ingin berkas dari setiap langkah, panggil satu per satu.

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" }));

Satu pipeline memiliki paling banyak 8 langkah. Langkah ke-9 mendapat HTTP 400: at most 8 pipeline steps allowed.

Anonim, dengan kunci, atau diarahkan ke server Anda sendiri

Jika Anda sudah mengatur PDFX_API_BASE tetapi panggilan tetap menuju https://pdf123.xyz, itu karena new Pdf123Client() tidak membaca variabel lingkungan; ia hanya melihat opsi konstruktornya.

Untuk panggilan anonim, pakai konstruktor itu apa adanya. Dengan kunci, tulis new Pdf123Client({ apiKey: process.env.PDFX_API_KEY }); header permintaannya adalah X-API-KEY.

Untuk mengarah ke server Anda sendiri, pakai clientFromEnv() dari @pdf123/sdk/node. Fungsi ini membaca PDFX_API_BASE dan PDFX_API_KEY. Anda juga bisa menulis langsung new Pdf123Client({ baseUrl: "http://localhost:8080" }). Jika alamatnya tidak terjangkau, panggilan gagal; tidak ada mode luring. Apa yang Anda dapat dan berapa biayanya ketika berkas tetap berada di jaringan Anda sendiri dibahas di Apa yang benar-benar Anda dapatkan dari self-hosting (dan biayanya).

Parameter yang salah ditangkap sebelum unggah

Tanpa ini, berkas akan diunggah lebih dulu dan nama bidang yang salah eja baru muncul sebagai 400 dari server. Tipe parameter untuk tiap alat dibangkitkan dari katalog, sehingga tiga kesalahan umum gagal pada tahap tsc:

Yang Anda tulis Galat kompiler (kutipan)
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, diakhiri Did you mean to write 'watermarkText'?
params: { angle: 45 } (rotate hanya menerima 90, 180, 270) Type '45' is not assignable to type …, diikuti nilai yang diizinkan

Panggilan yang benar seperti { angle: 90 } atau { watermarkText: "DRAFT", fontSize: 30 } dapat dikompilasi. Bidang numerik menerima angka maupun string, jadi fontSize: 30 dan fontSize: "30" setara. Proyek yang tidak memakai TypeScript mendapat galat yang sama saat runtime, dan permintaan tidak pernah dikirim: kasus ketiga menghasilkan Field "angle" of "rotate" must be one of: 90, 180, 270, dan nama alat yang salah eja menghasilkan unknown_tool, dengan nama-nama yang mirip tercantum dalam pesan.

Saat server menolak, bercabanglah berdasarkan reason

Saat server menolak permintaan, SDK melempar Pdf123Error dengan status, code, reason, dan problem.hint. Satu code bisa memiliki beberapa nilai reason, jadi periksa reason lebih dulu dan kembali ke code bila perlu. Tiga kegagalan umum, dijalankan secara lokal dengan input yang sama, tampak seperti ini:

Input status code reason hint (aslinya dalam bahasa Inggris)
PDF terenkripsi, tanpa kata sandi 400 bad_request password_required Berikan kata sandi dokumen, atau buka kunci PDF terlebih dahulu
Kata sandi salah 400 bad_request wrong_password Periksa kata sandi lalu coba lagi
Bukan PDF, atau berkas rusak 400 invalid_document invalid_pdf Unggah PDF yang valid dan utuh; Anda bisa mencoba memperbaikinya lebih dulu
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" });
  }
}

Bila Anda tahu kata sandinya, berikan password untuk satu berkas; pembukaan kunci dan alat tujuan berlangsung dalam permintaan yang sama. Untuk berkas rusak, coba Perbaiki PDF lebih dulu.

Kasus "tanpa hasil" perlu dibedakan. Ketika PDF ke CSV tidak menemukan tabel di PDF, server mengembalikan 204 dan SDK melempar code: "no_content"; alasannya ada di Ekspor tabel kosong (204): PDF Anda kemungkinan tanpa kolom. Alat filter bersyarat memperlakukan syarat yang salah sebagai hasil biasa: mereka tidak melempar galat, dan mengembalikan matched: false dengan data kosong.

Percobaan ulang, memori, dan pembatalan adalah tugas pemanggil

Galat jaringan dan respons 5xx dilempar apa adanya; SDK tidak pernah mencoba ulang sendiri. Untuk permintaan yang mengubah status, berikan idempotencyKey Anda sendiri: mengirim ulang dengan kunci yang sama mengembalikan hasil pertama, bukan memproses lagi, dan mekanisme serta batasnya ada di Idempotency-Key: percobaan ulang yang aman untuk pekerjaan PDF. Hasil dibaca ke memori secara utuh, tanpa streaming. Bila input dan output sama-sama besar, hitung memori yang mereka tempati pada saat yang bersamaan.

Pembatalan dan batas waktu adalah dua nilai code yang berbeda, dan satu panggilan hanya melaporkan salah satu yang terjadi lebih dulu. Contoh di bawah menguji keduanya dalam dua panggilan terpisah, agar kedua cabang benar-benar bisa berjalan:

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") { /* Anda membatalkannya */ }
}

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

Begitu sinyal pembatalan (AbortSignal) aktif, permintaan ditolak dengan code: "cancelled"; melewati batas waktu menghasilkan code: "timeout". Setiap permintaan memiliki batas waktu bawaan 5 menit, yang dapat Anda ubah saat membuat klien atau timpa per panggilan dengan timeoutMs. Pada unggahan berpotongan, setiap permintaan membawa batas waktu itu sendiri-sendiri. Membatalkan hanya menutup koneksi ini; tidak ada jaminan server berhenti memproses.

Satu berkas gagal, sisanya lanjut, dan callback datang menurut urutan selesai

Untuk batch input pada alat berkas tunggal, pakai runBatch. Jika satu berkas gagal, yang lain tetap berjalan. onResult dipanggil begitu tiap berkas selesai, sehingga berjalan menurut urutan selesai, dan index adalah posisi berkas dalam array input; array yang dikembalikan selalu menurut urutan input. Tulis byte ke disk di dalam callback ini: retainData: false mengosongkan data begitu callback kembali, jadi hasil yang tidak Anda saveResult di sini akan hilang. Jika proses terhenti di tengah jalan, berkas yang sudah ditulis tetap ada.

Anggap folder berisi tiga PDF yang baik, a.pdf, b.pdf, dan locked.pdf yang terenkripsi (kata sandi secret), ditambah berkas rusak broken.pdf yang hanya berisi beberapa karakter ketikan:

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,
});

Secara bawaan dua berkas diproses sekaligus; ubah dengan concurrency. fileSource(path) membaca berkas dari disk hanya ketika gilirannya tiba, sehingga batch besar berisi berkas besar tidak pernah seluruhnya berada di memori sekaligus. passwordFor memungkinkan batch yang mencampur berkas terkunci dan tidak terkunci berjalan sekali jalan. Saat keempat berkas di atas dijalankan secara lokal, callback menerima:

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

Urutan selesai bisa berbeda di setiap proses; ini hanya apa yang terjadi pada satu kali jalan. retainData: false membuat data pada array yang dikembalikan kosong; berkas yang berhasil sudah ditulis ke out/ oleh saveResult di atas. Bila Anda memberikan idempotencyKey ke runBatch, kunci yang benar-benar dikirim untuk tiap berkas adalah <key>:<index>.

Unggah berpotongan baru dimulai di atas total 95 MiB

Body permintaan langsung dibatasi 100 MiB, dan yang lebih besar ditolak; lihat Saat unggahan PDF besar ditolak: batas 100 MiB pada body permintaan dan galat yang menuntun ke arah salah untuk rinciannya. Ketika seluruh berkas dalam satu permintaan berjumlah lebih dari 95 MiB, SDK beralih ke unggah berpotongan, dan panggilan client.run Anda tidak berubah. Batas maksimum bawaan server untuk satu unggahan adalah 500 MiB; bila Anda self-host, atur dengan PDFX_UPLOAD_MAX_BYTES.

Untuk operasi yang sama yang ditulis dengan curl, MCP, dan baris perintah, lihat Operasi yang sama, empat klien: browser, curl, MCP, pdfx: tulisan itu menaruh keempat panggilan berdampingan, sedangkan tulisan ini hanya merinci SDK. Halaman paket di npm adalah @pdf123/sdk.

Open tool
Process in the browser β€” no watermark, files removed after the job.
Open tool