curl --request POST \
--url https://api.runpulse.com/form/fill \
--header 'Content-Type: multipart/form-data' \
--header 'x-api-key: <api-key>' \
--form 'instructions=<string>' \
--form file='@example-file' \
--form 'file_url=<string>' \
--form form_id=3c90c3cc-0d44-4b50-8888-8dd25736052a \
--form 'form_fields=<string>' \
--form 'page_range=<string>' \
--form 'async=<string>'import requests
url = "https://api.runpulse.com/form/fill"
files = { "file": ("example-file", open("example-file", "rb")) }
payload = {
"instructions": "<string>",
"file_url": "<string>",
"form_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"form_fields": "<string>",
"page_range": "<string>",
"async": "<string>"
}
headers = {"x-api-key": "<api-key>"}
response = requests.post(url, data=payload, files=files, headers=headers)
print(response.text)const form = new FormData();
form.append('instructions', '<string>');
form.append('file', '<string>');
form.append('file_url', '<string>');
form.append('form_id', '3c90c3cc-0d44-4b50-8888-8dd25736052a');
form.append('form_fields', '<string>');
form.append('page_range', '<string>');
form.append('async', '<string>');
const options = {method: 'POST', headers: {'x-api-key': '<api-key>'}};
options.body = form;
fetch('https://api.runpulse.com/form/fill', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.runpulse.com/form/fill",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"instructions\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file_url\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"form_id\"\r\n\r\n3c90c3cc-0d44-4b50-8888-8dd25736052a\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"form_fields\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"page_range\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"async\"\r\n\r\n<string>\r\n-----011000010111000001101001--",
CURLOPT_HTTPHEADER => [
"Content-Type: multipart/form-data",
"x-api-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.runpulse.com/form/fill"
payload := strings.NewReader("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"instructions\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file_url\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"form_id\"\r\n\r\n3c90c3cc-0d44-4b50-8888-8dd25736052a\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"form_fields\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"page_range\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"async\"\r\n\r\n<string>\r\n-----011000010111000001101001--")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.runpulse.com/form/fill")
.header("x-api-key", "<api-key>")
.body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"instructions\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file_url\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"form_id\"\r\n\r\n3c90c3cc-0d44-4b50-8888-8dd25736052a\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"form_fields\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"page_range\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"async\"\r\n\r\n<string>\r\n-----011000010111000001101001--")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.runpulse.com/form/fill")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<api-key>'
request.body = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"instructions\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file_url\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"form_id\"\r\n\r\n3c90c3cc-0d44-4b50-8888-8dd25736052a\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"form_fields\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"page_range\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"async\"\r\n\r\n<string>\r\n-----011000010111000001101001--"
response = http.request(request)
puts response.read_body{
"form_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"page_count": 2,
"pdf_url": "<string>",
"form_fields": [
{
"page_number": 2,
"bounding_box": [
0.5
],
"text": "<string>",
"type": "text",
"row": 1,
"col": 1,
"table_idx": 1,
"checkbox_details": [
{
"center_coord": [
0.5
],
"selected": true,
"text": "<string>"
}
]
}
],
"fields_filled": 1,
"fields_cleared": 1,
"credits_used": 123,
"plan_info": {
"tier": "<string>",
"total_credits_used": 123,
"pages_used": 1,
"note": "<string>"
}
}{
"job_id": "<string>",
"status": "pending",
"message": "<string>",
"queuedAt": "2023-11-07T05:31:56Z",
"credits_used": 123
}Fill Form
Fill the fields of a PDF form with values inferred from a natural
language instructions prompt. Works on both AcroForm PDFs
(true form fields are written) and flat/scanned PDFs (values
are rendered as an overlay using detected cells from OCR).
Input modes — provide exactly one of:
form_id— reuse a previously processed form from a prior/form/detect,/form/fill, or/form/clearcall. Skips re-detection (fast path); the cachedform_fieldsare reused.file_url— public or pre-signed URL of a PDF Pulse will download.file— direct binary upload of the PDF. Pulse runs cell detection internally before filling.
All three input modes ride on the same multipart/form-data
request body. (Callers sending Content-Type: application/json
with form_id / file_url are still accepted server-side for
backward compatibility, but the SDKs only model the multipart
form.)
Optional form_fields lets callers supply or edit the detected
cells before filling. Optional page_range (alias pages,
e.g. "1-3,5") restricts the operation to a subset of pages.
Synchronous by default — returns the filled FormResult inline
(including a pdf_url you can GET to download the PDF
binary). Set async: true to receive {job_id, status: "pending"} and poll GET /job/.
Billed at 3 credits per page. Requires the form_filler
feature flag to be enabled for your organization.
curl --request POST \
--url https://api.runpulse.com/form/fill \
--header 'Content-Type: multipart/form-data' \
--header 'x-api-key: <api-key>' \
--form 'instructions=<string>' \
--form file='@example-file' \
--form 'file_url=<string>' \
--form form_id=3c90c3cc-0d44-4b50-8888-8dd25736052a \
--form 'form_fields=<string>' \
--form 'page_range=<string>' \
--form 'async=<string>'import requests
url = "https://api.runpulse.com/form/fill"
files = { "file": ("example-file", open("example-file", "rb")) }
payload = {
"instructions": "<string>",
"file_url": "<string>",
"form_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"form_fields": "<string>",
"page_range": "<string>",
"async": "<string>"
}
headers = {"x-api-key": "<api-key>"}
response = requests.post(url, data=payload, files=files, headers=headers)
print(response.text)const form = new FormData();
form.append('instructions', '<string>');
form.append('file', '<string>');
form.append('file_url', '<string>');
form.append('form_id', '3c90c3cc-0d44-4b50-8888-8dd25736052a');
form.append('form_fields', '<string>');
form.append('page_range', '<string>');
form.append('async', '<string>');
const options = {method: 'POST', headers: {'x-api-key': '<api-key>'}};
options.body = form;
fetch('https://api.runpulse.com/form/fill', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.runpulse.com/form/fill",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"instructions\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file_url\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"form_id\"\r\n\r\n3c90c3cc-0d44-4b50-8888-8dd25736052a\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"form_fields\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"page_range\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"async\"\r\n\r\n<string>\r\n-----011000010111000001101001--",
CURLOPT_HTTPHEADER => [
"Content-Type: multipart/form-data",
"x-api-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.runpulse.com/form/fill"
payload := strings.NewReader("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"instructions\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file_url\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"form_id\"\r\n\r\n3c90c3cc-0d44-4b50-8888-8dd25736052a\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"form_fields\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"page_range\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"async\"\r\n\r\n<string>\r\n-----011000010111000001101001--")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.runpulse.com/form/fill")
.header("x-api-key", "<api-key>")
.body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"instructions\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file_url\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"form_id\"\r\n\r\n3c90c3cc-0d44-4b50-8888-8dd25736052a\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"form_fields\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"page_range\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"async\"\r\n\r\n<string>\r\n-----011000010111000001101001--")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.runpulse.com/form/fill")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<api-key>'
request.body = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"instructions\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file_url\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"form_id\"\r\n\r\n3c90c3cc-0d44-4b50-8888-8dd25736052a\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"form_fields\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"page_range\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"async\"\r\n\r\n<string>\r\n-----011000010111000001101001--"
response = http.request(request)
puts response.read_body{
"form_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"page_count": 2,
"pdf_url": "<string>",
"form_fields": [
{
"page_number": 2,
"bounding_box": [
0.5
],
"text": "<string>",
"type": "text",
"row": 1,
"col": 1,
"table_idx": 1,
"checkbox_details": [
{
"center_coord": [
0.5
],
"selected": true,
"text": "<string>"
}
]
}
],
"fields_filled": 1,
"fields_cleared": 1,
"credits_used": 123,
"plan_info": {
"tier": "<string>",
"total_credits_used": 123,
"pages_used": 1,
"note": "<string>"
}
}{
"job_id": "<string>",
"status": "pending",
"message": "<string>",
"queuedAt": "2023-11-07T05:31:56Z",
"credits_used": 123
}Overview
FormResult synchronously by default (with a pdf_url you can GET to download the filled PDF). Set async: true to run in the background and poll GET /jobjobId for the result./form/fill writes values into the fields of a PDF form based on a natural-language instructions prompt. It works on both PDFs with native form fields (where the values are written directly into the form) and on flat or scanned PDFs (where the values are placed into the detected fields).
Providing the PDF
Provide the PDF in exactly one of the following ways:form_id: chain off a prior/form/detect,/form/fill, or/form/clearcall. The cached PDF andform_fieldsare reused, so there is no need to re-upload.file_url: public or presigned URL to a PDF.file: PDF uploaded inline with the request.
400.
multipart/form-data request body — that’s how the SDKs send every call. JSON bodies (Content-Type: application/json) with form_id or file_url are still accepted server-side for backward compatibility, but the SDKs only model the multipart form.Pricing
Billed at 3 credits per page of the PDF being filled. Every response also returns a top-levelcredits_used for this request and a cumulative plan_info.total_credits_used snapshot for your organization.
Request
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
form_id | string (uuid) | One of these | Reuse a previously processed form. Skips re-upload and re-detection. |
file_url | string (uri) | One of these | Public or presigned URL of a PDF to download and fill. |
file | binary | One of these | PDF uploaded inline with the request. |
instructions | string | Yes | Natural-language description of what to fill into the form. Example: "Use John Doe, 123 Main St, born 1990-01-01". |
form_fields | array of FormCell | No | Optional override for the cells used when filling. Useful when the caller has hand-edited the cells returned by /form/detect. |
page_range | string | No | 1-based page filter, for example "1,3-5". Alias pages accepted. |
async | boolean | No | When true, returns { job_id, status: "pending" } immediately (HTTP 202) and processes the job in the background. Default false. |
Response
Sync (200): FormResult
When async is false (default), the call returns a FormResult body directly.
| Field | Type | Description |
|---|---|---|
form_id | string (uuid) | ID of the new form record produced by this run. Pass back via form_id to chain further fills, clears, or detects. |
page_count | integer | Number of pages in the output PDF. |
pdf_url | string (uri) | URL to download the filled PDF binary. Always points at GET /results/jobId/pdf. Requires the same auth (API key or JWT) as the rest of the API and only serves results owned by the calling organization. |
form_fields | array of FormCell | Detected cells of the resulting (filled) PDF, refreshed after the fill. |
fields_filled | integer | Number of cells whose value actually changed during this run (no-op writes are not counted). |
credits_used | number | Credits consumed by this request (3 × page_count). |
plan_info | object | { tier, total_credits_used, pages_used } cumulative billing snapshot for your organization (post-request). |
{
"form_id": "00e2c454-4e6f-429b-bd74-320ad94b2153",
"page_count": 6,
"pdf_url": "https://api.runpulse.com/results/dab7285d-8a65-4cb6-9d24-d5db64d3798e/pdf",
"form_fields": [
{
"page_number": 1,
"type": "text",
"bounding_box": [0.118, 0.226, 0.634, 0.241],
"text": "Acme Logistics LLC"
},
{
"page_number": 1,
"type": "checkbox",
"bounding_box": [0.118, 0.226, 0.634, 0.241],
"text": "Individual/sole proprietor C corporation S corporation Partnership",
"checkbox_details": [
{ "center_coord": [0.125, 0.232], "selected": true, "text": "Individual/sole proprietor" },
{ "center_coord": [0.300, 0.232], "selected": false, "text": "C corporation" },
{ "center_coord": [0.418, 0.232], "selected": false, "text": "S corporation" },
{ "center_coord": [0.535, 0.232], "selected": false, "text": "Partnership" }
]
}
],
"fields_filled": 7,
"credits_used": 18.0,
"plan_info": {
"tier": "pulse_ultra_2",
"total_credits_used": 1284.0,
"pages_used": 428
}
}
bounding_box, checkbox_details[].center_coord) are normalized to [0, 1] with a top-left origin. Multiply by your render width / height to convert to pixel coordinates.Async (202): FormJobAccepted
When async is true:
{
"job_id": "abc123-def456-ghi789",
"status": "pending"
}
result carries the same FormResult shape that the sync flow would have returned inline.
Status Codes
| Code | Description |
|---|---|
| 200 | Filled FormResult returned synchronously. |
| 202 | Async job accepted (async: true). Poll /job/{jobId} for the result. |
| 400 | Missing PDF, more than one PDF source provided, missing instructions, or malformed form_fields. |
| 401 | Authentication failed or missing API key. |
| 404 | Referenced form_id not found (or belongs to a different org). |
| 500 | Internal server error. |
Example Usage
Fill From URL
from pulse import Pulse
client = Pulse(api_key="YOUR_API_KEY")
result = client.form.fill(
file_url="https://example.com/intake-form.pdf",
instructions="Fill in patient name as Jane Doe, DOB 01/15/1990.",
)
print(f"form_id={result.form_id}")
print(f"fields_filled={result.fields_filled}")
print(f"credits_used={result.credits_used}")
print(f"download: {result.pdf_url}")
import { PulseClient } from "pulse-ts-sdk";
const client = new PulseClient({ apiKey: "YOUR_API_KEY" });
const result = await client.form.fill({
file_url: "https://example.com/intake-form.pdf",
instructions: "Fill in patient name as Jane Doe, DOB 01/15/1990.",
});
console.log(`form_id=${result.form_id}`);
console.log(`fields_filled=${result.fields_filled}`);
console.log(`download: ${result.pdf_url}`);
curl -X POST https://api.runpulse.com/form/fill \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"file_url": "https://example.com/intake-form.pdf",
"instructions": "Fill in patient name as Jane Doe, DOB 01/15/1990."
}'
File Upload
with open("intake-form.pdf", "rb") as f:
result = client.form.fill(
file=f,
instructions="Fill in patient name as Jane Doe, DOB 01/15/1990.",
)
import * as fs from "fs";
const fileBuffer = fs.readFileSync("intake-form.pdf");
const blob = new Blob([fileBuffer], { type: "application/pdf" });
const result = await client.form.fill({
file: blob,
instructions: "Fill in patient name as Jane Doe, DOB 01/15/1990.",
});
curl -X POST https://api.runpulse.com/form/fill \
-H "x-api-key: YOUR_API_KEY" \
-F "file=@intake-form.pdf" \
-F "instructions=Fill in patient name as Jane Doe, DOB 01/15/1990."
Detect First, Then Fill
Run/form/detect to inspect the detected cells, optionally edit them, then chain a fill that reuses the same form_id. There is no need to re-upload the PDF.
detect = client.form.detect(file_url="https://example.com/intake-form.pdf")
# (Optional) edit detected cells locally, e.g. retype a misclassified cell
edited = []
for cell in detect.form_fields or []:
if cell.text and cell.text.strip().lower() == "signature":
cell.type = "signature"
edited.append(cell)
result = client.form.fill(
form_id=detect.form_id,
instructions="Fill in patient name as Jane Doe, DOB 01/15/1990.",
form_fields=edited, # omit to use the cached cells from detect
)
const detect = await client.form.detect({
file_url: "https://example.com/intake-form.pdf",
});
const edited = (detect.form_fields ?? []).map((cell) =>
cell.text?.trim().toLowerCase() === "signature"
? { ...cell, type: "signature" as const }
: cell,
);
const result = await client.form.fill({
form_id: detect.form_id!,
instructions: "Fill in patient name as Jane Doe, DOB 01/15/1990.",
form_fields: edited,
});
# Step 1: detect
curl -X POST https://api.runpulse.com/form/detect \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"file_url": "https://example.com/intake-form.pdf"}'
# Step 2: fill via the form_id from step 1
curl -X POST https://api.runpulse.com/form/fill \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"form_id": "<form_id from step 1>",
"instructions": "Fill in patient name as Jane Doe, DOB 01/15/1990."
}'
Async Fill With Polling
Useasync: true for long-running jobs (large PDFs, multi-page fills) so the client does not have to keep a connection open.
import time
submission = client.form.fill(
file_url="https://example.com/big-form.pdf",
instructions="Fill the form for Jane Doe ...",
async_=True, # SDK aliases the reserved keyword
)
while True:
job = client.jobs.get_job(job_id=submission.job_id)
if job.status in ("completed", "failed"):
break
time.sleep(2)
result = job.result # same FormResult body as the sync flow
print(f"fields_filled={result['fields_filled']} pdf_url={result['pdf_url']}")
const submission = await client.form.fill({
file_url: "https://example.com/big-form.pdf",
instructions: "Fill the form for Jane Doe ...",
async: true,
});
let job = await client.jobs.getJob({ jobId: submission.job_id! });
while (job.status !== "completed" && job.status !== "failed") {
await new Promise((r) => setTimeout(r, 2000));
job = await client.jobs.getJob({ jobId: submission.job_id! });
}
const result = job.result as Record<string, unknown>;
console.log(`fields_filled=${result.fields_filled} pdf_url=${result.pdf_url}`);
# Submit async
curl -X POST https://api.runpulse.com/form/fill \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"file_url": "https://example.com/big-form.pdf",
"instructions": "Fill the form for Jane Doe ...",
"async": true
}'
# Poll
curl https://api.runpulse.com/job/<job_id> \
-H "x-api-key: YOUR_API_KEY"
Download The Filled PDF
Thepdf_url returned in FormResult points at GET /results/{job_id}/pdf and requires authentication (API key or JWT).
job_id = result.pdf_url.rstrip("/").split("/")[-2]
with open("filled.pdf", "wb") as out:
for chunk in client.results.get_pdf(job_id=job_id):
out.write(chunk)
const jobId = result.pdf_url!.replace(/\/$/, "").split("/").slice(-2, -1)[0];
const pdfStream = await client.results.getPdf({ jobId });
// pdfStream is a ReadableStream<Uint8Array>; write to disk however you prefer.
curl https://api.runpulse.com/results/<job_id>/pdf \
-H "x-api-key: YOUR_API_KEY" \
--output filled.pdf
Authorizations
Body
/form/fill request body. All three input modes (file,
file_url, form_id) ride on this single multipart/form-data
schema; the server validates that exactly one is provided.
Required natural-language fill prompt.
Direct binary upload of the PDF. Mutually exclusive with file_url and form_id.
Public or pre-signed URL of a PDF Pulse will download. Mutually exclusive with file and form_id.
Reference to a previously processed form. Mutually exclusive with file / file_url.
Optional JSON-encoded array of FormCell objects to override detected cells. Multipart bodies must serialise this field as a string.
Restrict the operation to a subset of pages, e.g. "1-3,5".
Set to "true" to run asynchronously and receive {job_id, status} immediately.
Response
Filled FormResult returned synchronously.
Result body returned by /form/detect, /form/fill, and
/form/clear. For async jobs (async: true) the same shape is
served back under result on
GET /job/{jobId} [blocked].
ID of the form record produced by this run. Pass to a subsequent /form/detect, /form/fill, or /form/clear call as the single input source to iterate without re-uploading the PDF.
Number of pages in the output PDF.
x >= 1URL to download the resulting PDF binary. Always points at GET /results/{jobId}/pdf [blocked] for the originating job. Authenticated callers can replay this URL until the underlying artifact is garbage-collected.
Detected cells of the resulting PDF (refreshed from the filled/cleared output for fill/clear, or freshly detected for /form/detect). Use these as a starting point for further edits.
Show child attributes
Show child attributes
Number of cells that were filled by this run. Present on /form/fill responses only.
x >= 0Number of cells that were cleared by this run. Present on /form/clear responses only.
x >= 0Number of credits consumed by this request. Detect charges 1 credit per page; fill and clear charge 3 credits per page.
Billing tier and cumulative usage information for the calling org, including this form run.
Show child attributes
Show child attributes