Import Instant JSON API
Use the import Instant JSON API to apply Instant JSON data to a PDF. Instant JSON is Nutrient’s JSON format for representing PDF annotations, form field values, attachments, and related document records.
The /build endpoint handles Instant JSON import. Add the source PDF as a parts item, and add an applyInstantJson action that references the Instant JSON file.
For signup, pricing, and task-level examples, refer to the Instant JSON import API task page.
Import Instant JSON
The following example imports Instant JSON from annotations.json into document.pdf and writes the output to result.pdf:
curl -X POST https://api.nutrient.io/build \ -H "Authorization: Bearer your_api_key_here" \ -o result.pdf \ --fail \ -F document=@annotations.pdf \ -F annotations.json=@annotations.json \ -F instructions='{ "parts": [ { "file": "document" } ], "actions": [ { "type": "applyInstantJson", "file": "annotations.json" } ] }'curl -X POST https://api.nutrient.io/build ^ -H "Authorization: Bearer your_api_key_here" ^ -o result.pdf ^ --fail ^ -F document=@annotations.pdf ^ -F annotations.json=@annotations.json ^ -F instructions="{\"parts\": [{\"file\": \"document\"}], \"actions\": [{\"type\": \"applyInstantJson\", \"file\": \"annotations.json\"}]}"package com.example.pspdfkit;
import java.io.File;import java.io.IOException;import java.nio.file.FileSystems;import java.nio.file.Files;import java.nio.file.StandardCopyOption;
import org.json.JSONArray;import org.json.JSONObject;
import okhttp3.MediaType;import okhttp3.MultipartBody;import okhttp3.OkHttpClient;import okhttp3.Request;import okhttp3.RequestBody;import okhttp3.Response;
public final class PspdfkitApiExample { public static void main(final String[] args) throws IOException { final RequestBody body = new MultipartBody.Builder() .setType(MultipartBody.FORM) .addFormDataPart( "document", "annotations.pdf", RequestBody.create( MediaType.parse("application/pdf"), new File("annotations.pdf") ) ) .addFormDataPart( "annotations.json", "annotations.json", RequestBody.create( MediaType.parse("application/octet-stream"), new File("annotations.json") ) ) .addFormDataPart( "instructions", new JSONObject() .put("parts", new JSONArray() .put(new JSONObject() .put("file", "document") ) ) .put("actions", new JSONArray() .put(new JSONObject() .put("type", "applyInstantJson") .put("file", "annotations.json") ) ).toString() ) .build();
final Request request = new Request.Builder() .url("https://api.nutrient.io/build") .method("POST", body) .addHeader("Authorization", "Bearer your_api_key_here") .build();
final OkHttpClient client = new OkHttpClient() .newBuilder() .build();
final Response response = client.newCall(request).execute();
if (response.isSuccessful()) { Files.copy( response.body().byteStream(), FileSystems.getDefault().getPath("result.pdf"), StandardCopyOption.REPLACE_EXISTING ); } else { // Handle the error throw new IOException(response.body().string()); } }}using System;using System.IO;using System.Net;using RestSharp;
namespace PspdfkitApiDemo{ class Program { static void Main(string[] args) { var client = new RestClient("https://api.nutrient.io/build");
var request = new RestRequest(Method.POST) .AddHeader("Authorization", "Bearer your_api_key_here") .AddFile("document", "annotations.pdf") .AddFile("annotations.json", "annotations.json") .AddParameter("instructions", new JsonObject { ["parts"] = new JsonArray { new JsonObject { ["file"] = "document" } }, ["actions"] = new JsonArray { new JsonObject { ["type"] = "applyInstantJson", ["file"] = "annotations.json" } } }.ToString());
request.AdvancedResponseWriter = (responseStream, response) => { if (response.StatusCode == HttpStatusCode.OK) { using (responseStream) { using var outputFileWriter = File.OpenWrite("result.pdf"); responseStream.CopyTo(outputFileWriter); } } else { var responseStreamReader = new StreamReader(responseStream); Console.Write(responseStreamReader.ReadToEnd()); } };
client.Execute(request); } }}// This code requires Node.js. Do not run this code directly in a web browser.
const axios = require('axios')const FormData = require('form-data')const fs = require('fs')
const formData = new FormData()formData.append('instructions', JSON.stringify({ parts: [ { file: "document" } ], actions: [ { type: "applyInstantJson", file: "annotations.json" } ]}))formData.append('document', fs.createReadStream('annotations.pdf'))formData.append('annotations.json', fs.createReadStream('annotations.json'))
;(async () => { try { const response = await axios.post('https://api.nutrient.io/build', formData, { headers: formData.getHeaders({ 'Authorization': 'Bearer your_api_key_here' }), responseType: "stream" })
response.data.pipe(fs.createWriteStream("result.pdf")) } catch (e) { const errorString = await streamToString(e.response.data) console.log(errorString) }})()
function streamToString(stream) { const chunks = [] return new Promise((resolve, reject) => { stream.on("data", (chunk) => chunks.push(Buffer.from(chunk))) stream.on("error", (err) => reject(err)) stream.on("end", () => resolve(Buffer.concat(chunks).toString("utf8"))) })}import requestsimport json
response = requests.request( 'POST', 'https://api.nutrient.io/build', headers = { 'Authorization': 'Bearer your_api_key_here' }, files = { 'document': open('annotations.pdf', 'rb'), 'annotations.json': open('annotations.json', 'rb') }, data = { 'instructions': json.dumps({ 'parts': [ { 'file': 'document' } ], 'actions': [ { 'type': 'applyInstantJson', 'file': 'annotations.json' } ] }) }, stream = True)
if response.ok: with open('result.pdf', 'wb') as fd: for chunk in response.iter_content(chunk_size=8096): fd.write(chunk)else: print(response.text) exit()<?php
$FileHandle = fopen('result.pdf', 'w+');
$curl = curl_init();
curl_setopt_array($curl, array( CURLOPT_URL => 'https://api.nutrient.io/build', CURLOPT_CUSTOMREQUEST => 'POST', CURLOPT_RETURNTRANSFER => true, CURLOPT_ENCODING => '', CURLOPT_POSTFIELDS => array( 'instructions' => '{ "parts": [ { "file": "document" } ], "actions": [ { "type": "applyInstantJson", "file": "annotations.json" } ] }', 'document' => new CURLFILE('annotations.pdf'), 'annotations.json' => new CURLFILE('annotations.json') ), CURLOPT_HTTPHEADER => array( 'Authorization: Bearer your_api_key_here' ), CURLOPT_FILE => $FileHandle,));
$response = curl_exec($curl);
curl_close($curl);
fclose($FileHandle);POST https://api.nutrient.io/build HTTP/1.1Content-Type: multipart/form-data; boundary=--customboundaryAuthorization: Bearer your_api_key_here
--customboundaryContent-Disposition: form-data; name="instructions"Content-Type: application/json
{ "parts": [ { "file": "document" } ], "actions": [ { "type": "applyInstantJson", "file": "annotations.json" } ]}--customboundaryContent-Disposition: form-data; name="document"; filename="annotations.pdf"Content-Type: application/pdf
(document data)--customboundaryContent-Disposition: form-data; name="annotations.json"; filename="annotations.json"Content-Type: application/octet-stream
(annotations.json data)--customboundary--Import Instant JSON from URLs
For remotely hosted source files, send a JSON request and pass URLs for both the PDF and the Instant JSON file. Use this instructions object:
{ "parts": [ { "file": { "url": "https://example.com/document.pdf" } } ], "actions": [ { "type": "applyInstantJson", "file": { "url": "https://example.com/annotations.json" } } ]}Shell
Run this request to import Instant JSON from URLs:
curl -X POST https://api.nutrient.io/build \ -H "Authorization: Bearer $NUTRIENT_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "parts": [ { "file": { "url": "https://example.com/document.pdf" } } ], "actions": [ { "type": "applyInstantJson", "file": { "url": "https://example.com/annotations.json" } } ] }' \ -o result.pdfImport annotations
Instant JSON can contain annotations, such as highlights, notes, ink annotations, stamps, and image annotations.
The following example imports one note annotation:
{ "annotations": [ { "type": "pspdfkit/note", "v": 2, "id": "01J0EXAMPLEANNOTATIONID0001", "pageIndex": 0, "bbox": [100, 100, 32, 32], "contents": "Review this section", "createdAt": "2026-06-29T00:00:00Z", "updatedAt": "2026-06-29T00:00:00Z" } ], "format": "https://pspdfkit.com/instant-json/v1"}Use the exact annotation data exported from Nutrient SDKs or another system that produces compatible Instant JSON.
Fill form fields with Instant JSON
Instant JSON can also set PDF form field values. Add a formFieldValues array and reference form fields by their field names.
Use this Instant JSON structure to fill form fields:
{ "formFieldValues": [ { "name": "First Name", "type": "pspdfkit/form-field-value", "v": 1, "value": "John" }, { "name": "Last Name", "type": "pspdfkit/form-field-value", "v": 1, "value": "Appleseed" }, { "name": "Newsletter", "type": "pspdfkit/form-field-value", "v": 1, "value": "Choice1" } ], "format": "https://pspdfkit.com/instant-json/v1"}The field name must match the form field name in the PDF, not only the visible label next to the field. For form-specific examples, refer to the PDF form filling API guide.
Import image attachments
Some Instant JSON annotations reference attachments, such as image annotations or visual signature appearances. Include attachments in the attachments object, and reference them by ID from the annotation.
Use this Instant JSON structure to import an image attachment:
{ "annotations": [ { "type": "pspdfkit/image", "v": 2, "id": "01J0EXAMPLEIMAGEANNOTATION1", "pageIndex": 0, "bbox": [72, 700, 200, 48], "contentType": "image/png", "imageAttachmentId": "signature-image", "isSignature": true } ], "attachments": { "signature-image": { "binary": "<base64-encoded-png>", "contentType": "image/png" } }, "format": "https://pspdfkit.com/instant-json/v1"}A visual signature appearance imported this way differs from a cryptographic digital signature. To cryptographically sign a PDF, use the Processor API digital signature endpoint. For digital signing workflows, refer to the PDF digital signature API guide.
Import and flatten Instant JSON
If the imported annotations or form appearances should no longer be editable, add a flatten action after applyInstantJson. Actions run in the order specified in the actions array.
Use this instructions object to import and flatten Instant JSON:
{ "parts": [ { "file": "document" } ], "actions": [ { "type": "applyInstantJson", "file": "annotations.json" }, { "type": "flatten" } ]}Flattening turns annotations and form appearances into regular page content. Use it only when the output no longer needs editable annotations or form fields.
Import Instant JSON into selected pages
The applyInstantJson action applies to the assembled PDF in the request. If you first extract pages with parts[].pages, Nutrient DWS Processor API applies the Instant JSON to that extracted output.
Use this instructions object to import Instant JSON into selected pages:
{ "parts": [ { "file": "document", "pages": { "start": 0, "end": 2 } } ], "actions": [ { "type": "applyInstantJson", "file": "annotations.json" } ]}Make sure page indexes, bounding boxes, and form field names in the Instant JSON match the PDF that the action applies to.
Import Instant JSON into password-protected PDFs
If the source PDF is password-protected, include the password on the part. Use this instructions object:
{ "parts": [ { "file": "protected_document", "password": "document-password" } ], "actions": [ { "type": "applyInstantJson", "file": "annotations.json" } ]}Nutrient DWS Processor API uses the password only to open the source document for processing. To set a password on the output PDF, configure output.user_password, output.owner_password, and output.user_permissions.
Combine Instant JSON import with other actions
The /build endpoint can import Instant JSON and then apply additional actions. For example, you can import annotations, add a watermark, and then flatten the final output.
Use this instructions object to combine Instant JSON import with other actions:
{ "parts": [ { "file": "document" } ], "actions": [ { "type": "applyInstantJson", "file": "annotations.json" }, { "type": "watermark", "text": "REVIEWED", "width": "50%", "height": "20%", "opacity": 0.3, "rotation": 45 }, { "type": "flatten" } ]}For workflows that include cryptographic signing, import and optionally flatten Instant JSON before signing the final PDF.
Reference
An Instant JSON import request uses the Build API actions array with an applyInstantJson action:
type ApplyInstantJsonAction = { type: "applyInstantJson",
// Multipart field name, or a remote URL object pointing to an Instant JSON file. file: string | { url: string },};
type InstantJson = { annotations?: object[], formFieldValues?: object[], attachments?: Record<string, object>, format: "https://pspdfkit.com/instant-json/v1",};
type FilePart = { // Multipart field name, or a remote URL object. file: string | { url: string },
// Optional password for encrypted input PDFs. password?: string,
// Optional page range to use before Instant JSON import. pages?: { start?: number, end?: number, },};
type BuildInstructions = { parts: FilePart[], actions: ApplyInstantJsonAction[], output?: { type?: "pdf", },};Related API reference operations
- Refer to the build document endpoint API reference to import Instant JSON and combine import with flattening, watermarking, security, or other document actions.
Related guides
- Refer to the import XFDF annotations API guide.
- Refer to the PDF form filling API guide.
- Refer to the PDF flatten API guide.
- Refer to the PDF watermark API guide.
- Refer to the PDF digital signature API guide.
- Refer to the tools and APIs guide.