# SimplePDF for Developers

> PDF workflows for humans, apps, and AI agents. Your UI. Your workflow. Your storage. Embed and control PDFs in React or JavaScript, prefill forms from your systems, and extend the same workflow to AI agents. People review, correct, sign, and submit.

Markdown representation of [https://simplepdf.com/developers](https://simplepdf.com/developers). Machine-readable contracts: [editor](https://simplepdf.com/embed/json), [REST OpenAPI](https://simplepdf.com/api/json), [site map for models](https://simplepdf.com/llms.txt).

- [Live demo](https://copilot.simplepdf.com)
- [View on GitHub](https://github.com/SimplePDF/simplepdf-embed)
- [API reference](https://simplepdf.com/api)

[Embed PDFs](https://github.com/SimplePDF/simplepdf-embed/tree/main) - [Control programmatically](https://github.com/SimplePDF/simplepdf-embed/blob/main/react/README.md#programmatic-control) - [Prefill forms](https://simplepdf.com/api/#tag/prefill) - [Add an AI agent](https://simplepdf.com/developers#operators)

## Quick start

### React

```tsx
import { EmbedPDF } from '@simplepdf/react-embed-pdf';

export function Document() {
  return (
    <EmbedPDF
      mode="inline"
      style={{ width: 900, height: 800 }}
      companyIdentifier="yourcompany"
      document={{ url: 'https://cdn.simplepdf.com/simple-pdf/assets/forms/fw9.pdf' }}
    />
  );
}
```

`@simplepdf/react-embed-pdf` - [React docs](https://github.com/SimplePDF/simplepdf-embed/blob/main/react/README.md)

### Iframe / JavaScript

```js
// <div id="editor" style="height: 100vh"></div>
import { createEmbed } from '@simplepdf/embed';

const embed = createEmbed({
  // a CSS selector, or the HTMLElement itself
  target: '#editor',
  companyIdentifier: 'yourcompany',
  document: { url: 'https://cdn.simplepdf.com/simple-pdf/assets/forms/fw9.pdf' },
});
```

`@simplepdf/embed` - [JavaScript docs](https://github.com/SimplePDF/simplepdf-embed/blob/main/embed/README.md)

### AI agents

```tsx
// expose the live editor as client-side tools
import { useEmbedTools } from '@simplepdf/react-embed-pdf/ai-sdk';

const tools = useEmbedTools(embedRef);
// the model's tool calls execute against the open document
```

`@simplepdf/react-embed-pdf/ai-sdk` - [Agent docs](https://github.com/SimplePDF/simplepdf-embed/blob/main/react/README.md#agentic-useembedtools-vercel-ai-sdk) - Vercel AI SDK - TanStack AI

## The PDF stack you don't have to build

Rendering is the easy part. Production PDF workflows also need field normalization, editing, signing, programmatic control, storage, submissions, and workflow events.

- viewer + editor: Renders, zooms, fills, annotates, signs. Runs in an iframe in your app.
- field detection: AcroForm fields read out with stable IDs. Comb fields, checkboxes, signatures.
- content extraction: Parse document content as structured Markdown in the browser for search, extraction, automation, or AI workflows.
- white label: Your logo, your loading screen, no "Powered by SimplePDF". Keep the built-in editor UI or reduce it and drive the document from your own application controls.
- programmatic control: Every editor operation is callable from your code through the typed SDK. The same operations can also be exposed as client-side tools for supported AI SDKs.
- POST /documents/{document_id}/prefills: Stage known field values from your backend, workflow, or agent, then hand the person a link to a prefilled draft.
- webhooks: submission.created with short-lived URLs for the completed PDF and structured field data, keyed by stable field ID.
- your storage: S3, Azure Blob Storage or SharePoint. Bytes go browser to bucket over signed URLs.
- portal + audit: Shareable links, submission dashboard, members and roles, audit log.

## You build your product. We make the PDFs work.

25,000+ PDFs processed by SimplePDF every day. Malformed forms, weird rendering: at our volume we hit every edge case first and our tooling fixes it once, for everyone. A broken PDF never becomes your on-call problem. Focus on your product: we'll handle the PDFs.

## Keep your PDF data in your infrastructure

PDF editing happens in the browser. With BYOS, document and submission data moves directly between the browser and storage you control, without passing through SimplePDF application servers. The one opt-in exception, off by default: a designated submission-name field, stored on SimplePDF to label the submission in the dashboard.

Your AI provider is separate too: SimplePDF parses the PDF outside the LLM, and your application decides what extracted context gets sent to the model.

In the browser: your UI (Your components, your routes, your auth.) -> `@simplepdf/embed + @simplepdf/react-embed-pdf` (Typed actions, events, tool registry. Zero runtime dependencies at the root.) -> the editor iframe (The PDF is rendered, filled and edited here. With bring your own storage, saved bytes go directly to storage you control.)

What leaves the browser, and where it goes:

- Your storage: S3, Azure Blob Storage or SharePoint. Browser to bucket, no proxy.
- Your backend: Webhook with metadata, your correlation context, and short-lived URLs for the completed PDF and the answers as JSON.
- Your AI provider: Optional. Provider-agnostic: the model your AI stack supports. Tool calls come back and execute in the browser.

| Data | Where it goes |
| --- | --- |
| PDF bytes while editing | The browser. With bring your own storage, saved bytes go browser to bucket over signed URLs. |
| Prefill field values | Your storage: Prefill requires a readable bring-your-own-storage configuration, so the browser can retrieve the staged values. |
| Submitted field values | Your storage when you bring your own; SimplePDF-managed storage otherwise. The webhook carries a short-lived field_data_url, not the values themselves. |
| AI context, when used | SimplePDF parses fields and content in the browser. Your application chooses which extracted context to send to its configured AI provider. The PDF itself never goes to the model. |
| Workflow metadata and submission context | SimplePDF, then your backend via webhook. |
| API key | Your server only. It never ships to the browser. |

Principles:

- Bring your own AI: If you add an AI workflow, your app chooses the provider, route, key, and policy. SimplePDF doesn't require proxying prompts through its infrastructure.
- Bring your own storage: S3, Azure Blob Storage or SharePoint over short-lived signed URLs.
- Edits stay in the browser: Operations run against the live document, not an uploaded copy.

Bring your own storage:

- [S3-compatible](https://simplepdf.com/help/how-to/use-your-own-s3-bucket-storage-for-pdf-form-submissions): Any bucket that speaks the S3 API, in your own account and region.
- [Azure Blob Storage](https://simplepdf.com/help/how-to/bring-your-own-azure-blob-storage-for-pdf-storage): Container-scoped SAS, no standing credentials in the browser.
- [SharePoint](https://simplepdf.com/help/how-to/connect-sharepoint-as-your-own-storage-for-pdf-submissions): For Microsoft-centric organisations already storing records there.

[Storage setup](https://simplepdf.com/help/how-to/use-your-own-s3-bucket-storage-for-pdf-form-submissions) - [Privacy policy](https://simplepdf.com/privacy-policy)

## Is SimplePDF the right tool?

SimplePDF fits when your product needs a live PDF surface that people or application code can read, fill, edit, sign, or submit. The same interaction layer can also be exposed to AI agents. If not, one of these may fit better.

| What you are building | Use |
| --- | --- |
| Render a public PDF on a page, nothing else | [pdf.js](https://mozilla.github.io/pdf.js/), when you want to own the interaction layer yourself |
| View documents inside a workflow: faxes, scans, records pulled from storage | **SimplePDF**: Viewer mode, the same embed, read-only. Display your faxes straight in your app when they come from [SRFax](https://www.srfax.com), [Documo](https://www.documo.com), [eFax](https://www.efax.com) or [Phaxio](https://www.phaxio.com). |
| Build your own PDF editor from primitives: custom rendering, annotation engine, offline processing | [Apryse (PDFTron)](https://apryse.com), [Nutrient (PSPDFKit)](https://www.nutrient.io), [EmbedPDF](https://www.embedpdf.com), engine-level control; you build and maintain the workflow layer |
| Load a form, fill it, submit it, with a person accountable for the answers | **SimplePDF**: [Intake](https://simplepdf.com/use-cases/healthcare), onboarding, [claims](https://simplepdf.com/use-cases/insurance), immigration, [tax](https://simplepdf.com/use-cases/government), [HR](https://simplepdf.com/use-cases/hr-onboarding), anything signed. |
| Generate documents from data, no human involved | [DocSpring](https://docspring.com), [Anvil](https://www.useanvil.com) |

## One PDF. Three operators.

A person, your application, or an AI agent can drive the same live PDF. AI is optional: the human and application SDKs use the same underlying interaction layer.

In agent-assisted workflows, review, signing, and submission stay with the person.

- A person: Embed the editor. Fill, sign, submit.
- Your app: Your UI, driving the live document through the SDK.
- An AI agent: Editor operations as client tools the model can call.

embed.tsx:

```tsx
import { EmbedPDF } from '@simplepdf/react-embed-pdf';

<EmbedPDF
  mode="inline"
  style={{ width: 900, height: 800 }}
  companyIdentifier="yourcompany"
  document={{ url: 'https://cdn.simplepdf.com/simple-pdf/assets/forms/fw9.pdf' }}
/>
```

control.tsx:

```tsx
// React: typed actions on the live editor
const { embedRef, actions } = useEmbed();
await actions.goTo({ page: 2 });
await actions.selectTool({ tool: 'SIGNATURE' });
await actions.setFieldValue({ fieldId: 'f_last_name', value: 'Doe' });
const fieldsResult = await actions.getFields(); // BridgeResult: { success, data | error }

<EmbedPDF ref={embedRef} onEmbedEvent={(event) => { ... }} /> // e.g. SUBMISSION_SENT

// framework-free: createEmbed({ target, companyIdentifier, document })
// grouped handle: embed.actions / embed.events / embed.lifecycle
// 15 actions, closed error codes: /embed/json
```

ai-tools.tsx:

```tsx
// server: the model learns the tools (execute-less definitions)
import { simplePDFToolDefinitions } from '@simplepdf/embed/ai-sdk';
streamText({ model, tools: simplePDFToolDefinitions() });

// browser, Vercel AI SDK: dispatch tool calls against the live editor
import { useEmbedTools } from '@simplepdf/react-embed-pdf/ai-sdk';
const tools = useEmbedTools(embedRef);
const { addToolOutput } = useChat({
  onToolCall: async ({ toolCall }) => {
    const output = await tools[toolCall.toolName]?.execute(toolCall.input);
    addToolOutput({ tool: toolCall.toolName, toolCallId: toolCall.toolCallId, output });
  },
});

// TanStack AI: the same tools, passed straight to useChat
import { useEmbedTools } from '@simplepdf/react-embed-pdf/tanstack-ai';
useChat({ connection, tools: useEmbedTools(embedRef) });
```

Every operation, with request/response schemas and error codes: [https://simplepdf.com/embed/json](https://simplepdf.com/embed/json)

Live demo with Copilot: Copilot is the open reference implementation for agentic HITL form filling, built on [TanStack Start](https://tanstack.com/start) and the [Vercel AI SDK](https://ai-sdk.dev). [Try Copilot](https://copilot.simplepdf.com) - [Fork the source](https://github.com/SimplePDF/simplepdf-embed/tree/main/copilot)

## The agent prepares. The person approves.

Known answers come out of your systems. An agent stages them with the Prefill API or works the live document through tools, and the person reviews, corrects, signs and submits. Your backend receives submission metadata plus short-lived URLs for the completed PDF and structured field data.

From your systems to your backend: The agent does the data entry. Review, signature and submission stay with the person.

```
CRM / EHR / conversation / database
                 |
                 v
         backend or agent
          /             \
         v               v
   Prefill API       live tools
   (stage known      (the model drives
    values first)     the open editor)
          \             /
           v           v
      the PDF, live in the browser
                 |
                 v
    the person reviews and corrects
                 |
                 v
          signs and submits
                 |
                 v
        webhook -> your backend:
   completed PDF URL + field_data_url
```

## Start with a prefilled form

When the answers already exist in a CRM, an EHR like Epic or any FHIR-based system, a prior submission, a database, or a conversation, stage them before the person opens the PDF. They review, correct, sign, and submit.

Prefill -> Review -> Submit

```
GET  /documents/{document_id}/fields
POST /documents/{document_id}/prefills

# PUT -> your storage
{ "fields": [
  { "id": "f_first_name", "value": "Jane" }
] }
```

- [Prefill guide](https://simplepdf.com/help/how-to/prefill-pdf-forms-with-ai-agents)
- [OpenAPI](https://simplepdf.com/api/json)

## Submissions your backend can act on

When the person submits, a `submission.created` webhook carries your correlation context, a short-lived URL for the completed PDF, and a short-lived URL for the answers as JSON keyed by field ID.

Your backend never parses a PDF to find out what someone entered.

Submission context: Attach non-sensitive correlation metadata: a case ID, a tenant, an environment. It comes back with the webhook, so no lookup call. Keep PII, PHI, secrets and form answers out of it.

```json
"context": { "case": "I-130", "tenant": "acme-eu" }
```

POST your-app.com/webhooks/simplepdf:

```json
{
  "type": "submission.created",
  "data": {
    "document": { "id": "47d8c475...", "name": "intake.pdf" },
    "submission": {
      "id": "a91f20c3...",
      "submitted_at": "2026-07-03T09:12:44Z",
      "url": "short-lived-pdf-url",
      "field_data_url": "short-lived-json-url"
    },
    "context": { "case": "I-130", "tenant": "acme-eu" }
  }
}
```

GET field_data_url:

```json
{ "fields": [
  { "id": "first_name__widget_1", "name": "First name", "value": "Jane" },
  { "id": "agreed_to_terms__widget_1", "name": "Agreed to terms", "value": "checked" }
] }
```

- [Configure webhooks](https://simplepdf.com/help/how-to/configure-webhooks-pdf-form-submissions)
- [REST submissions](https://simplepdf.com/api/#tag/submission)

## REST API for management

Manage documents, retrieve field schemas, and read submissions: the REST API orchestrates the client-side embed from your server code. Bearer token, server-only: the key never ships to the browser.

API access is plan-dependent; [pricing](https://simplepdf.com/pricing) is the canonical source.

```
https://{companyIdentifier}.simplepdf.com/api/v1

curl https://acme.simplepdf.com/api/v1/documents \
  -H "Authorization: Bearer $SIMPLEPDF_API_KEY"
```

```
GET  /documents
GET  /documents/{document_id}/fields
POST /documents/{document_id}/prefills
GET  /documents/{document_id}/submissions/{submission_id}
```

## Developer FAQ

### Can I build my own toolbar?

Yes. Drive the live editor from your own controls through the typed SDK. The editor is iframe-based, so treat customization as configuration plus programmatic control, not CSS injection.

[Customize the editor](https://simplepdf.com/help/how-to/customize-the-pdf-editor-and-add-branding)

### Can I get submitted form values as structured data?

Yes. submission.created includes a short-lived field_data_url with the submitted field values keyed by stable field ID, so your backend doesn't need to parse the completed PDF.

[Set up webhooks](https://simplepdf.com/help/how-to/configure-webhooks-pdf-form-submissions)

### Can I keep the PDFs in my own storage?

Yes. Bring your own S3-compatible storage, Azure Blob Storage, or SharePoint where supported. With BYOS, document bytes move directly between the browser and your storage over short-lived signed URLs.

[Configure your own storage](https://simplepdf.com/help/how-to/use-your-own-s3-bucket-storage-for-pdf-form-submissions)

### Can I use SimplePDF without AI?

Yes. Embedding, programmatic control, Prefill, submissions, webhooks, storage, and the REST API work without an LLM. AI adapters are an optional extension of the same editor operations.

### Can an AI agent fill a PDF?

Yes. An agent can call tools against the live editor, or a backend or agent can stage known values through Prefill. In the recommended human-in-the-loop workflow, the person reviews, corrects, signs, and submits.

[Try the demo: ask the agent to fill the form](https://copilot.simplepdf.com)

### Does the PDF go to an LLM?

No. SimplePDF parses and extracts the PDF in the browser, outside the LLM. Your app sends the model only the extracted fields or content the task needs, so the PDF itself never goes to the model and you don't spend tokens parsing it.

[PDF to Markdown content extraction](https://simplepdf.com/help/how-to/convert-pdf-to-markdown-for-ai)

## Build with your coding agent

Install one SimplePDF skill, then tell your agent what you want to build. It inspects the repository, asks only what it cannot infer, chooses the smallest correct integration, and implements it.

The skill supports ordinary embeds and programmatic PDF workflows too; it only introduces AI components when your application needs them.

### 1. Install the skill

- Claude Code: `mkdir -p .claude/skills/build-with-simplepdf && curl -fsSL https://raw.githubusercontent.com/SimplePDF/simplepdf-embed/main/skills/build-with-simplepdf/SKILL.md -o .claude/skills/build-with-simplepdf/SKILL.md`
- Codex: `mkdir -p .agents/skills/build-with-simplepdf && curl -fsSL https://raw.githubusercontent.com/SimplePDF/simplepdf-embed/main/skills/build-with-simplepdf/SKILL.md -o .agents/skills/build-with-simplepdf/SKILL.md`
- Cursor: `mkdir -p .cursor/rules && curl -fsSL https://raw.githubusercontent.com/SimplePDF/simplepdf-embed/main/skills/build-with-simplepdf/SKILL.md -o .cursor/rules/build-with-simplepdf.mdc`
- OpenCode: `mkdir -p .opencode/skills/build-with-simplepdf && curl -fsSL https://raw.githubusercontent.com/SimplePDF/simplepdf-embed/main/skills/build-with-simplepdf/SKILL.md -o .opencode/skills/build-with-simplepdf/SKILL.md`
- Any agent, paste this prompt: "Fetch https://raw.githubusercontent.com/SimplePDF/simplepdf-embed/main/skills/build-with-simplepdf/SKILL.md verbatim with curl -fsSL (not a summarizing fetch), then follow it to add SimplePDF to this app."

### 2. Tell your agent what you want to build

```
Add SimplePDF to this app. Inspect the codebase first and use the build-with-simplepdf skill to choose and implement the right integration. Ask me only what you cannot infer.
```

For agents: [Developer Markdown](https://simplepdf.com/developers.md) - [llms.txt](https://simplepdf.com/llms.txt) - [Editor contract](https://simplepdf.com/embed/json) - [REST OpenAPI](https://simplepdf.com/api/json) - [SKILL.md](https://github.com/SimplePDF/simplepdf-embed/blob/main/skills/build-with-simplepdf/SKILL.md)
