Data Extraction (Key Information Extraction)
The Document Key Information Extraction (KIE) API is AISAY’s most powerful capability. It extracts specific pieces of information from documents using a combination of OCR and Large Language Models (LLMs).
Use this API for all your extraction, analysis, and verification needs.
How It Works
- You send a document (PDF or image) along with a JSON schema describing what you want to extract
- AISAY runs OCR to reliably extract text from each page
- The LLM intelligently identifies which text is relevant to your query and returns structured results
- You receive a JSON response with the extracted data matching your schema
Unlike traditional OCR which relies on keyword matching, AISAY understands context. For example, if you search for “Groom’s Name” and a marriage certificate uses the label “Husband” instead, AISAY will still find the correct value.
Available Models
| Feature | Flagship Model | Local Model |
|---|---|---|
| Invoke with | data_classification='RSN' |
data_classification='CCE' |
| Hosting | Overseas | Singapore |
| Best for | Text-heavy documents | Image-heavy / visual documents |
| Processing speed | Slightly slower | Slightly faster |
| Max pages | 150 pages | 50 pages |
| Max file size | 500 MB | — |
| Supported formats | PDF, JPG, TIFF, PNG, XLSX, DOCX, PPTX | PDF, JPG, TIFF, PNG |
Tip: Try both models on your use case and compare results. Flagship tends to be more accurate for text-heavy content, while Local performs better on image-heavy documents.
Schema Structure
The KIE API requires a vlm_prompt, a JSON schema that describes the fields you want to extract. The schema follows JSON Schema format.
Basic Example
Extract a name and NRIC from a document:
{
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "The full name of the individual as displayed in the document"
},
"nric": {
"type": "string",
"description": "The NRIC (National Registration Identity Card) number of the individual"
}
},
"required": ["name", "nric"],
"additionalProperties": false
}Supported Field Types
| Type | Use When | Example |
|---|---|---|
string |
Extracting text, names, addresses, descriptions | "type": "string" |
number |
Extracting numeric values (no symbols or units) | "type": "number" |
boolean |
Checking a true/false condition | "type": "boolean" |
array |
Extracting a list of items (variable length) | "type": "array" |
object |
Grouping related fields together | "type": "object" |
Extracting Lists
When the number of items is unknown (e.g., line items on an invoice), use an array:
{
"type": "object",
"properties": {
"vendor_name": {
"type": "string",
"description": "The name of the vendor"
},
"line_items": {
"type": "array",
"description": "All line items found on the invoice",
"items": {
"type": "object",
"properties": {
"item_name": {
"type": "string",
"description": "The name or description of the item"
},
"quantity": {
"type": "number",
"description": "The quantity ordered"
},
"unit_price": {
"type": "string",
"description": "The unit price including currency symbol, e.g. $50.00"
}
}
}
}
},
"required": ["vendor_name", "line_items"],
"additionalProperties": false
}Nested Objects (Grouped Related Fields)
When you need to maintain the association between related pieces of data, use objects within arrays. For example, extracting directors from an annual report:
{
"type": "object",
"properties": {
"directors": {
"type": "array",
"description": "List of all board of directors found in the annual report",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "The director's name, e.g. Mr Tan Ah Kow"
},
"designation": {
"type": "string",
"description": "The director's designation or title"
},
"years_of_experience": {
"type": "number",
"description": "Years of experience, e.g. 10"
},
"profile_summary": {
"type": "string",
"description": "A 100-word summary of the director's profile"
}
}
}
}
},
"required": ["directors"],
"additionalProperties": false
}Using KIE for Analysis
The KIE API is not limited to extracting facts — you can also use it to evaluate, assess, and generate commentary about documents.
Example: Analysing a sustainability report
{
"type": "object",
"properties": {
"community_involvement": {
"type": "string",
"description": "How does the organisation engage local communities? Include donations, volunteering, programs, and partnerships. If none found, state 'Not found in report.'"
},
"areas_for_improvement": {
"type": "string",
"description": "Identify 3-6 gaps or weaknesses in the report. Look for: missing Scope 3, no targets, unclear methodology, weak metrics, vague claims."
},
"overall_rating": {
"type": "string",
"description": "Rate the report quality from 1-10. Include 3 strengths with evidence, 3 weaknesses, and 3 fixes to raise the score."
}
}
}Using KIE for Verification
You can also use the KIE API for verification and anomaly detection tasks.
Example: Checking bank statements for suspicious activity
{
"type": "object",
"properties": {
"missing_information": {
"type": "string",
"description": "Check if the statement is missing crucial information like the account holder's name or address, which could indicate the applicant is submitting someone else's statements."
},
"large_transactions": {
"type": "string",
"description": "Identify any significant deposits, large cash withdrawals, or large fund transfers that warrant further investigation."
},
"financial_difficulty": {
"type": "string",
"description": "Check for signs of financial difficulty such as repeatedly drawing down the account or dangerously low balances."
},
"overall_recommendation": {
"type": "string",
"description": "Based on all analysis, provide an overall conclusion and recommendation on whether to approve the application or seek a follow-up review."
}
}
}API Request
import requests
import json
import urllib3
# Disable SSL warnings for dev/internal endpoints
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
# 1. Configuration
API_KEY = "YOUR_API_KEY_HERE"
API_URL = "https://api.aisay.tech.gov.sg/v1/extract"
FILE_PATH = "path/to/your/document.pdf"
# 2. Define the Extraction Prompt Schema
# (Booleans are now capitalized for Python compatibility)
vlm_prompt = {
"type": "object",
"properties": {
"account_holder_name": {
"type": "string",
"description": "Full name of the account holder as it appears on the bank statement. For example: John Tan Wee Kiat"
},
"statement_date": {
"type": "string",
"description": "The date when the bank statement was issued or covers. For example: 31/12/2023",
"pattern": "^\\d{2}/\\d{2}/\\d{4}$"
},
"transactions": {
"type": "array",
"description": "A list of individual financial transactions recorded on the bank statement.",
"items": {
"type": "object",
"properties": {
"transaction_date": {
"type": "string",
"description": "Date the transaction occurred. For example: 15/12/2023",
"pattern": "^\\d{2}/\\d{2}/\\d{4}$"
},
"transaction_description": {
"type": "string",
"description": "Brief description of the transaction, such as vendor name, type of payment, or transfer details. For example: Groceries at NTUC, Salary Deposit, ATM Withdrawal."
},
"transaction_amount": {
"type": "number",
"description": "The monetary value of the transaction. For example: -50.25 (for a debit), 2500.00 (for a credit)."
}
},
"required": [
"transaction_date",
"transaction_description",
"transaction_amount"
],
"additionalProperties": False
}
}
},
"required": [
"account_holder_name",
"statement_date",
"transactions"
],
"additionalProperties": False
}
# 3. Prepare Payload
payload = {
"model_type": "GENERAL",
"data_classification": "RSN",
"vlm_prompt": json.dumps(vlm_prompt),
"source": "API"
}
# Note: Python `requests` handles multipart boundary automatically
files = [
('file', ('document.pdf', open(FILE_PATH, 'rb'), 'application/pdf'))
]
headers = {
'Authorization': f'Bearer {API_KEY}'
}
# 4. Make Request
print("Sending request to AISAY...")
# verify=False is REQUIRED for dev endpoints using self-signed certs
response = requests.post(API_URL, headers=headers, files=files, data=payload, verify=False)
# 5. Handle Response
if response.status_code == 200:
print("Success!")
# The API will return JSON that matches your Schema structure
print(json.dumps(response.json(), indent=2))
else:
print(f"Error {response.status_code}: {response.text}")Prompt Writing Tips
The description field in your schema is where you write your extraction instructions. Good descriptions lead to accurate results.
- Be specific” describe what the value looks like and give examples
- Handle edge cases” tell the AI what to return if the field is missing (e.g., “Return empty string if not found”)
- Provide context” mention where in the document the information is typically located
- Correct known errors” if the AI commonly misreads a value, explain the issue in your prompt
For detailed prompt-writing guidance, see the Prompt Writing Tips page.
Quick Start with Helper Tool
Visit https://tools.getaisay.com/API_Extraction_Helper to generate Python and cURL scripts for your extraction use case without writing code from scratch.
See Also
- API Integration Guide” How to get API keys and make your first call
- API Specifications” Full API reference
- Pricing” Cost per page