OCR Document URLs
The /ocr and /ocr.json endpoints can read a file from a public URL.
Put the URL in the JSON field document_url. OCRskill downloads the file and runs OCR.
A document URL requires a paid API key. A free key returns 403.
Endpoints
POST https://api.ocrskill.com/ocr
POST https://api.ocrskill.com/ocr.json
Each request requires a bearer token.
Authorization: Bearer sk-your-key-here
Quick start
Send a JSON body. Set document_url to an HTTP or HTTPS URL.
curl "https://api.ocrskill.com/ocr" \
-H "Authorization: Bearer sk-your-key-here" \
-H "Content-Type: application/json" \
-d '{
"document_url": "https://cdn.example.com/invoice.pdf"
}'
/ocr returns JSON. The pages array holds the Markdown for each page.
{
"pages": [
{
"index": 0,
"markdown": "# Invoice\n\nTotal: 120.00",
"images": []
}
],
"model": "LightOnOCR-2-1B",
"document_annotation": null,
"usage_info": {
"pages_processed": 1,
"doc_size_bytes": 35
}
}
The response includes the X-OCR-Pages header. The value is the processed page count, then /, then the input page count.
doc_size_bytes counts the characters in the document URL.
Python
Use the standard library. POST the JSON body to /ocr.
import json
import urllib.request
body = json.dumps({
"document_url": "https://cdn.example.com/invoice.pdf",
}).encode("utf-8")
request = urllib.request.Request(
"https://api.ocrskill.com/ocr",
data=body,
headers={
"Authorization": "Bearer sk-your-key-here",
"Content-Type": "application/json",
},
method="POST",
)
with urllib.request.urlopen(request, timeout=120) as response:
print(response.status)
print(response.headers.get("X-OCR-Pages"))
print(response.read().decode("utf-8"))
The status is 200. The body is the JSON document above.
POST the same JSON body to /ocr.json when you want typed fields. Put the field names in the query string.
import json
import urllib.request
body = json.dumps({
"document_url": "https://cdn.example.com/invoice.pdf",
}).encode("utf-8")
request = urllib.request.Request(
"https://api.ocrskill.com/ocr.json?fields=company_name,invoice_date",
data=body,
headers={
"Authorization": "Bearer sk-your-key-here",
"Content-Type": "application/json",
},
method="POST",
)
with urllib.request.urlopen(request, timeout=120) as response:
print(response.status)
print(response.headers.get("X-OCR-Pages"))
print(response.read().decode("utf-8"))
/ocr.json returns the typed fields.
{
"company_name": "Example GmbH",
"invoice_date": "2024-03-01"
}
Field names are in the Structured Data Extraction API.
Node.js
Send the same JSON body with fetch. Use Node.js 18 or newer.
const response = await fetch("https://api.ocrskill.com/ocr", {
method: "POST",
headers: {
Authorization: "Bearer sk-your-key-here",
"Content-Type": "application/json",
},
body: JSON.stringify({
document_url: "https://cdn.example.com/invoice.pdf",
}),
});
console.log(response.status);
console.log(response.headers.get("X-OCR-Pages"));
console.log(await response.json());
Use /ocr.json and a fields query for typed JSON. The request body stays the same.
const response = await fetch(
"https://api.ocrskill.com/ocr.json?fields=company_name,invoice_date",
{
method: "POST",
headers: {
Authorization: "Bearer sk-your-key-here",
"Content-Type": "application/json",
},
body: JSON.stringify({
document_url: "https://cdn.example.com/invoice.pdf",
}),
},
);
console.log(response.status);
console.log(response.headers.get("X-OCR-Pages"));
console.log(await response.json());
Read response.status before you use the body. A 200 status means the body is the OCR result.
Document URL rules
Use an HTTP or HTTPS URL. You can add a query string.
A presigned URL works. Keep its signature in the query string. OCRskill does not add an auth header to the download.
Do not put a user name or a password in the URL.
OCRskill does not send a fragment (#) to the host.
The host must resolve to a public address. A public IPv4 address and a public IPv6 address both work.
OCRskill rejects a loopback address, a private address, a link-local address, and a multicast address.
Every address for that host must be public. OCRskill rejects the URL when any address is private.
OCRskill does not send your API key to the document host.
OCRskill does not check the TLS certificate. The host must still use a public address.
Download limits
The download limit is 300 MB.
The request timeout is 30 seconds. The connect timeout is 5 seconds.
OCRskill sends HEAD, then GET. A failed HEAD still allows the GET.
When HEAD returns 200 and Content-Length is above 300 MB, OCRskill skips GET.
The file must use a supported type. OCRskill reads Content-Type from the document host.
When the host omits that header, or when the header is application/octet-stream, OCRskill reads the file signature.
The signatures for PNG, JPEG, WebP, GIF, and PDF are enough to set the type.
When Content-Type names an image type, the file signature sets the type.
The file name comes from the URL path. OCRskill uses that name when it reads a document.
Redirects
OCRskill follows up to 5 redirects.
Each target must use a public address. OCRskill rejects a target that contains a user name or a password.
An HTTPS URL must not redirect to an HTTP URL.
A 303 status makes the next request a GET.
What /ocr returns
A JSON body with document_url makes /ocr return JSON.
The shape matches a data URI on the same endpoint. Each page object has a markdown field.
A multipart upload and a raw file still return Markdown. Those requests send the file bytes, so they have no document URL.
What /ocr.json returns
/ocr.json returns the same JSON as a file upload. The fields query still selects the fields.
curl "https://api.ocrskill.com/ocr.json?fields=company_name,invoice_date" \
-H "Authorization: Bearer sk-your-key-here" \
-H "Content-Type: application/json" \
-d '{
"document_url": "https://cdn.example.com/invoice.pdf"
}'
Send the result to a callback URL
You can add callback_url next to document_url. Both values require a paid API key.
The endpoint returns 202. OCRskill downloads the file after that response. It then sends PUT with the result.
Read the OCR callback reference.
curl "https://api.ocrskill.com/ocr" \
-H "Authorization: Bearer sk-your-key-here" \
-H "Content-Type: application/json" \
-d '{
"document_url": "https://cdn.example.com/invoice.pdf",
"callback_url": "https://uploads.example.com/result"
}'
Errors
OCRskill checks the URL before it downloads the file. These errors mean that OCRskill did not run OCR.
Access
| Situation | Status | Notes |
|---|---|---|
| Missing or invalid bearer token | 401 |
Send Authorization: Bearer sk-.... |
| Free API key | 403 |
The message is Downloading a document from a URL requires a paid API key. |
Document URL
| Situation | Status | Notes |
|---|---|---|
| URL scheme is not HTTP or HTTPS | 400 |
Use an HTTP or HTTPS URL. |
| URL contains a user name or a password | 400 |
Remove the user and the password. |
| Host is not a public address | 400 |
Use a public IP address. |
| Situation | Status | Notes |
|---|---|---|
| Host name does not resolve | 400 |
Check the host name. |
| Invalid URL or port | 400 |
Check the host and the port. |
Download
| Situation | Status | Notes |
|---|---|---|
| Document is larger than 300 MB | 400 |
OCRskill returns Document exceeds the maximum download size. |
Host returns a status other than 200 |
400 |
The message includes that status code. |
| Response body is empty | 400 |
OCRskill returns Document URL returned an empty body. |
| The download fails | 400 |
OCRskill returns Could not download the document URL. |
| Situation | Status | Notes |
|---|---|---|
| More than 5 redirects | 400 |
OCRskill returns Document URL has too many redirects. |
Redirect has no Location header |
400 |
OCRskill returns Document URL redirect is missing a location. |
| HTTPS URL redirects to HTTP | 400 |
OCRskill returns Document URL must not redirect from HTTPS to HTTP. |
| File type is unknown | 400 |
Send a supported file type. |
| Situation | Status | Notes |
|---|---|---|
Content-Length is not a number |
400 |
OCRskill returns Document URL returned an invalid content length. |
These download errors arrive in the same HTTP response when you omit callback_url.
When you set callback_url, OCRskill checks the document URL before 202. A download error after 202 does not send a PUT.
Upload the file instead
Send the file bytes when you do not have a public URL.
A data URI, a multipart upload, and a raw file work with a free API key.
Read the Structured Data Extraction API for those uploads.
Frequently asked questions
Does a free API key work?
No. A free key returns 403. The message is Downloading a document from a URL requires a paid API key.
Does /ocr return Markdown for a document URL?
No. A JSON document_url makes /ocr return the JSON document. Each page has a markdown field.
A multipart upload and a raw file return Markdown. They do not accept a document URL.
Can the URL use HTTP?
Yes. A document URL can use HTTP or HTTPS. A callback URL must use HTTPS.
Can I use a presigned URL?
Yes. Put the signature in the query string. OCRskill sends that query string on HEAD and on GET.
Does OCRskill follow redirects?
Yes. OCRskill follows up to 5 redirects. Each target must point to a public address.
What does doc_size_bytes count?
It counts the characters in document_url. It does not count the downloaded file.
Can I combine a document URL with typed fields?
Yes. Call /ocr.json and set fields. The JSON body still holds document_url.