Detect signatures in a PDF
Send a PDF to the same detection endpoint. The response lists every page at the top level, with the same bounding-box objects the image API returns, and tells you how many credits the file used.
A new account starts with 10 detection credits. The playground asks you to sign in, then calls the same API.
Request
The PDF body uses the same URL and the same x-api-key header as an image call. Pick one source.
curl -X POST https://signature-detector.com/api/detect \
-H "Content-Type: application/json" \
-H "x-api-key: your_api_key_here" \
-d '{
"pdfUrl": "https://example.com/contract.pdf"
}'For a file on disk, base64-encode the bytes and send pdfBase64 instead of pdfUrl. A private storage link fails the same way a private image URL fails: the server fetches pdfUrl with a plain HTTP GET and no cookies.
The official clients send those fields from Python detect_pdf (pdf_url or pdf_base64) and from Node detectPdf (pdfUrl or pdfBase64) in the signature-detector package. Sending PDF bytes through imageUrl or imageBase64 also works when the file starts with %PDF or the response content type says PDF. New code should use the PDF fields.
from signature_detector import SignatureDetector
with SignatureDetector("your_api_key_here", timeout=120) as client:
pdf = client.detect_pdf(pdf_url="https://example.com/contract.pdf")
# or client.detect_pdf(pdf_base64=pdf_base64)
print(pdf.page_count, pdf.credits_used, pdf.pages[0].count)import { SignatureDetector } from "signature-detector";
const client = new SignatureDetector({
apiKey: "your_api_key_here",
timeoutMs: 120_000,
});
const pdf = await client.detectPdf({
pdfUrl: "https://example.com/contract.pdf",
});
// or client.detectPdf({ pdfBase64 })
console.log(pdf.pageCount, pdf.creditsUsed, pdf.pages[0].count);detect_pdf and detectPdf read pages, count, and creditsUsed from the top level. Python exposes them as pages, count, page_count, and credits_used. A short balance raises InsufficientCreditsError from either package. The default client timeout is 60 seconds, and PDF processing is allowed 80 seconds on the server, so pass 120 seconds.
Pages in the response
Read pages, count, and creditsUsed on the JSON object. A page with count 0 had no mark at or above the server threshold of 0.1. width and height are the raster that was detected: 150 DPI, with the long edge capped at 2,000 pixels. A US Letter page is 1275 by 1650. Boxes use the same shape as the image API. Crop that raster, not the PDF point size.
{
"success": true,
"documentType": "pdf",
"signed": true,
"count": 1,
"pageCount": 2,
"confidenceThreshold": 0.1,
"pages": [
{
"page": 1,
"width": 1275,
"height": 1650,
"count": 1,
"detections": [
{
"bbox": {
"x1": 120.5,
"y1": 980.2,
"x2": 460.8,
"y2": 1104.0
},
"confidence": 0.91,
"class": 0,
"class_name": "signature"
}
]
},
{
"page": 2,
"width": 1275,
"height": 1650,
"count": 0,
"detections": []
}
],
"creditsUsed": 2,
"creditsRemaining": 98,
"detectionId": "clxxxx"
}A repeated identical file looks the same, with "cached": true and "creditsUsed": 0. detectionId is omitted on a fresh call if storing the row fails. The detections are still returned.
Find pages with no mark
import requests
response = requests.post(
"https://signature-detector.com/api/detect",
headers={
"Content-Type": "application/json",
"x-api-key": "your_api_key_here",
},
json={"pdfUrl": "https://example.com/contract.pdf"},
timeout=120,
)
response.raise_for_status()
data = response.json()
unsigned_pages = [
page["page"] for page in data["pages"] if page["count"] == 0
]
print("Pages with no signature mark:", unsigned_pages)
print("Total marks:", data["count"])
print("Credits used:", data["creditsUsed"])The step-by-step version, including pdfBase64, is Detect signatures in PDFs with Python. PDF pages always use 0.1. An optional threshold from 0 to 1 applies to images only. An image response still nests detections under result. Do not share one parser between the two shapes.
Not enough credits
The page count is known before any page is rendered. If the balance is short, the call stops with HTTP 402 and the balance does not change.
{
"error": "Insufficient credits. This PDF has 12 pages and costs 12 credits (1 per page). You have 3.",
"code": "insufficient_credits",
"credits": 3,
"creditsRequired": 12,
"pageCount": 12,
"needsPurchase": true
}A file over 20 MB is HTTP 413. More than 20 pages, an encrypted PDF, or a file that is not a readable PDF is HTTP 400. If rendering or detection fails after the charge, the credits for that request are refunded. A timeout is HTTP 504.
Pricing
- $10 per 100,000 credits, which is $0.0001 each. An image that is not served from cache spends 1 credit. A PDF spends 1 credit per page.
- 10 credits are added when the account is created.
- $1 minimum purchase. That is 10,000 credits. There is no subscription.
- Credits do not expire. The balance stays on the account until a detection spends it. A failed detection puts the credit back. Repeating an image or an identical PDF returns
cached: trueand does not spend a credit. On a PDF that hit iscreditsUsed: 0. - Buy credits from the dashboard or estimate a volume on the pricing page.
For a PDF, multiply the page count by one credit. 100,000 PDF pages that are not cached cost the same $10 as 100,000 uncached images. Sending each page as its own image is also 1 credit per page. The difference is one request versus one request per page, not the price.
Where this fits
Lending packets and contracts are usually PDFs. The lending and contracts pages describe what to do with a page that comes back empty. Checking whether a document is signed still means a visual mark was found. On a PDF, signed is that check and nothing more.
FAQ
Which fields does a PDF request use?
POST https://signature-detector.com/api/detect with header x-api-key. The JSON body is exactly one of pdfUrl or pdfBase64. pdfUrl is an http or https URL the server downloads with a plain GET. pdfBase64 is the PDF file as base64. Do not send both, and do not send those fields together with imageUrl or imageBase64.
Where are pages, count, and creditsUsed?
They are top-level fields on the 200 JSON, next to success. They are not nested under result. pages is an array. Each item has a 1-based page number, width and height in pixels of that rendered page, a detections array, and a count for that page. count is the total across pages. pageCount is the number of pages. creditsUsed is pageCount on a new file and 0 when the same PDF bytes were already detected. PDFs always use confidenceThreshold 0.1. An image request may send threshold from 0 to 1, and that value is not applied to PDF pages. A threshold outside 0 to 1 is HTTP 400. Each detection has bbox (x1, y1, x2, y2), confidence, class, and class_name. The origin is the top-left of the raster.
How are PDF requests billed?
A PDF spends 1 credit per page, including pages with no detections. A 10-page file is 10 credits ($0.001) the first time those bytes are seen. The balance is checked before any page is rasterized or detected. If the balance is lower than the page count, the response is HTTP 402 with code insufficient_credits, credits, creditsRequired, pageCount, and needsPurchase true, and nothing is charged. Images stay at 1 credit per uncached request. Signup still includes 10 credits, the minimum purchase is still $1, and credits still do not expire.
What happens when the same PDF is sent again?
The cache key is pdf: plus the SHA-256 of the whole file. An identical file returns the stored page summary with cached true, creditsUsed 0, and creditsRemaining unchanged. Re-saving or re-encoding the PDF changes the bytes, so it is a new file and is charged again.
Does this read a digital signature certificate?
No. signed is true only when count is greater than zero, meaning a visual mark was returned. A PDF can contain a cryptographic signature with no visible ink, and it can contain a scanned handwritten mark with no certificate. This endpoint does not parse the PDF signature dictionary. An empty page does not prove the file is unsigned in the cryptographic sense.
Related reading
- Signature detection API
Request fields, response boxes, credits, and the errors the endpoint actually returns.
- Detect signatures in PDFs with Python
pdfUrl, pdfBase64, and how to list pages that came back empty.
- Contracts
Record where signature marks sit on an agreement, then crop them for a human.
- Check if a document is signed
Turn a detection count into a review decision without treating it as identity proof.
- Lending packets
Check each required page of a loan packet and count the credits before you run it.
- Pricing
$10 per 100,000 credits. Images cost 1 credit. PDFs cost 1 credit per page.
Try it on your own file
Upload an image in the playground, or create an API key from the dashboard after signup. Read the API docs for the request fields.
