Feedback
The feedback namespace is how you close the loop between your users and the AI fill pipeline. Record where each filled PDF is stored, retrieve version history, let users report errors directly from your interface, and pull those reports for review - all in one place.
How feedback works
The fill pipeline is AI-driven, which means it is not perfect. The feedback system exists so your users can report mistakes, and the AI can learn from them over time. There are two distinct steps you integrate into your application.
Once the AI fill pipeline finishes and you have stored the filled PDF, call filledPdf.recordSaveEvent(). This registers the output location so the platform knows which file belongs to which session - a required step for any feedback submitted in Step 2 to be correctly attributed.
Surface a "Report an issue" or "This is wrong" action in your interface. When a user submits a report, call user.submit() with details about which field was wrong and why. The report appears in your admin dashboard and feeds directly into AI model improvement.
import Pdffillr from '@pdffillr/sdk';
import fs from 'fs';
const client = new Pdffillr({
apiKey: process.env['PDFFILLR_API_KEY'], // This is the default and can be omitted
});
// Step 1 - Upload the blank PDF template.
const doc = await client.sdk.docs.upload({
file: fs.createReadStream('form.pdf'),
});
// Step 2 - Create a session and run the AI fill pipeline.
const session = await client.sdk.chat.sessions.create({ title: 'KYC Form' });
// ...fill pipeline runs asynchronously...
// Step 3 - Once the filled PDF is stored, record the save event.
// This tells the feedback loop exactly where the filled output lives.
await client.sdk.feedback.filledPdf.recordSaveEvent({
filled_pdf_location: `filled-pdfs/${session.session_id}/output.pdf`,
pdf_id: String(doc.doc_id),
session_id: session.session_id,
});
// Step 4 - If the user reports an error via your UI, submit feedback.
await client.sdk.feedback.user.submit({
session_id: session.session_id,
pdf_id: String(doc.doc_id),
field_name: 'Tax ID',
field_type: 'text',
page_number: 1,
error_type: 'wrong_field',
feedback: 'Value placed in Tax ID field but should have gone into the EIN field.',
});
console.log('Feedback loop complete - this session is now tracked for AI improvement.');filledPdf.recordSaveEvent() before exposing the filled PDF to your users.1. Record a Save Event
Call this method on your server immediately after the AI fill pipeline completes and you have stored the filled PDF. It logs the storage location of the output and ties it to the originating session and PDF template - this is what makes the version history and feedback attribution work correctly.
client.sdk.feedback.filledPdf.recordSaveEvent(body, options?)POST/v1/sdk/feedback/filled-pdfReturns/void| Parameter | Type | Description |
|---|---|---|
| filled_pdf_location | string | The S3 key, file path, or URL where the filled PDF has been stored. |
| pdf_id | string | The ID of the blank PDF template that was used for this fill job. |
| session_id | string | The ID of the session that produced this filled output. |
import Pdffillr from '@pdffillr/sdk';
const client = new Pdffillr({
apiKey: process.env['PDFFILLR_API_KEY'], // This is the default and can be omitted
});
// Call this on your server once the fill pipeline has completed
// and the filled PDF has been stored.
await client.sdk.feedback.filledPdf.recordSaveEvent({
// Where the filled PDF is stored - S3 key, file path, or URL.
filled_pdf_location: 'filled-pdfs/dev-123/session-abc/v1.pdf',
// The ID of the blank PDF template used for this fill job.
pdf_id: '42',
// The session that produced this filled output.
session_id: 'clx9f2k3n0000abc123xyz',
});
console.log('Save event recorded. The AI feedback loop can now track this output.');recordSaveEvent() from your backend - not the browser. It should run in the same flow where you move the filled PDF to its final storage location (S3 bucket, database, CDN, etc.).2. Get Version History
Retrieves all recorded versions for a given session and PDF, ordered by date descending. Every time you call recordSaveEvent for the same session and document, a new version is added to the history logs.
client.sdk.feedback.filledPdf.getVersionHistory(query, options?)GET/v1/sdk/feedback/filled-pdfReturns/Array of version objects| Parameter | Type | Description |
|---|---|---|
| pdf_id | string | The ID of the PDF template. |
| session_id | string | The ID of the session. |
import Pdffillr from '@pdffillr/sdk';
const client = new Pdffillr({
apiKey: process.env['PDFFILLR_API_KEY'], // This is the default and can be omitted
});
// Fetch all recorded versions for a specific document in a session.
const history = await client.sdk.feedback.filledPdf.getVersionHistory({
pdf_id: '42',
session_id: 'clx9f2k3n0000abc123xyz',
});
console.log('Version history retrieved successfully.');3. Submit User Feedback
Records a user's report about an incorrectly filled field. This is intended to be called from your application whenever a user flags a problem - for example, by clicking a "Report an issue" button next to a filled field. Reports are visible in the admin analytics dashboard and feed directly into AI model improvement.
client.sdk.feedback.user.submit(body, options?)POST/v1/sdk/feedback/userReturns/void| Parameter | Type | Description |
|---|---|---|
| session_id | string | The session where the incorrectly filled PDF was produced. |
| pdf_id | string | The ID of the PDF template involved in this report. |
| field_name | string | The name or label of the form field being reported. |
| field_type | string | The type of the field: text, checkbox, radio, date, signature, or dropdown. |
| page_number | number | The page number (1-based) where the field appears. |
| error_type | string | The category of error. See the error_type table below. |
| feedback | string | A plain-English description of what went wrong. |
| corners | unknown | (Optional) Bounding box { x1, y1, x2, y2 } of the field on the page. |
wrong_valueThe field was filled but with the wrong value or inaccurate data.
wrong_fieldThe value was placed in the incorrect form field.
missing_fieldThe required information was provided but the field was left empty.
extra_fieldThe AI filled a field that should have been left blank or untouched.
formattingThe data is correct but the format is wrong (e.g., incorrect date format).
otherAny other feedback or issue that does not fit into the standard categories.
import Pdffillr from '@pdffillr/sdk';
const client = new Pdffillr({
apiKey: process.env['PDFFILLR_API_KEY'], // This is the default and can be omitted
});
// Triggered when a user clicks "Report an issue" or "This is wrong" in your UI.
await client.sdk.feedback.user.submit({
// Which session and PDF this report is about.
session_id: 'clx9f2k3n0000abc123xyz',
pdf_id: '42',
// The specific field the user is reporting a problem with.
field_name: 'Date of Birth',
field_type: 'date',
page_number: 2,
// Optional: Provide bounding box coordinates of the field
corners: { x1: 100, y1: 200, x2: 250, y2: 220 },
// What kind of error occurred (see error_type values below).
error_type: 'formatting',
// A plain-English description of what went wrong.
feedback: 'Date was filled as MM/DD/YYYY but form requires DD/MM/YYYY.',
});
console.log('Feedback submitted. This will appear in your admin analytics dashboard.');session_id and pdf_id from the fill result you already have in state; collect field_name, error_type, and feedback from a small form the user submits.4. List Feedback
Retrieves all feedback submitted under your developer account. Results are paginated and ordered by submission date, newest first. You can filter by a specific PDF or session to narrow down reports for a particular fill job. Use this to build an admin view of reported issues or to export feedback data for review.
client.sdk.feedback.user.list(query?, options?)GET/v1/sdk/feedback/userReturns/Paginated feedback list| Parameter | Type | Default | Description |
|---|---|---|---|
| page | number | 1 | Page number to retrieve. 1-indexed. |
| limit | number | 20 | Number of items per page. |
| pdf_id | string | - | Filter to feedback for a specific PDF template. |
| session_id | string | - | Filter to feedback for a specific session. |
import Pdffillr from '@pdffillr/sdk';
const client = new Pdffillr({
apiKey: process.env['PDFFILLR_API_KEY'], // This is the default and can be omitted
});
// Fetch all feedback across your account.
const result = await client.sdk.feedback.user.list();
result.data?.forEach((item) => {
console.log(`[${item.error_type}] "${item.field_name}" - ${item.feedback}`);
});
// Filter down to a specific PDF or session.
const forPdf = await client.sdk.feedback.user.list({ pdf_id: '42' });
const forSession = await client.sdk.feedback.user.list({
session_id: 'clx9f2k3n0000abc123xyz',
});
// Paginate through a large set of reports.
const page2 = await client.sdk.feedback.user.list({ page: 2, limit: 20 });
console.log(`Page 2 has ${page2.data?.length || 0} feedback items.`);user.list() is designed for your backend admin views - not for end-users. Use the session_id or pdf_id filters to scope the results to a specific job when building a per-document feedback review panel.What to read next
PDFFILLR.AI
The intelligent layer for modern fund
administration. Automating high-stakes
documentation with precision and speed.