API Specifications
Overview
AISAY provides three synchronous REST APIs. All APIs use multipart form data for file uploads and return JSON responses.
Base URL: https://api.aisay.tech.gov.sg
Authentication
All API calls require a Bearer token in the Authorization header:
Authorization: Bearer <your-api-key>Request API keys at https://go.gov.sg/aisaykey.
Note: For staging/dev endpoints using self-signed certificates, you may need to disable SSL verification (
verify=Falsein Python).
Document Key Information Extraction (KIE)
Extract specific information from documents using a JSON schema.
Endpoint
POST /v1/extractRequest (Multipart Form Data)
| Parameter | Type | Required | Description |
|---|---|---|---|
file |
file | Yes | The document file (PDF, JPG, PNG, TIFF, XLSX, DOCX, PPTX) |
model_type |
string | Yes | GENERAL |
data_classification |
string | Yes | RSN (Flagship) or CCE (Local) |
vlm_prompt |
string | Yes | JSON schema as a stringified JSON object |
source |
string | Yes | API |
Model Limits
| Limit | Flagship (RSN) |
Local (CCE) |
|---|---|---|
| Max pages | 150 | 50 |
| Max file size | 500 MB | โ |
| Supported formats | PDF, JPG, TIFF, PNG, XLSX, DOCX, PPTX | PDF, JPG, TIFF, PNG |
Schema Format
The vlm_prompt must be a valid JSON schema (stringified with json.dumps()) with:
- Root type
"object"with a"properties"field - Each property must have
"type"and"description" - Supported types:
string,number,boolean,array,object - Arrays must include an
"items"definition - Use
"required"to list mandatory fields - Set
"additionalProperties": falseto prevent unexpected fields
Example: Simple Extraction
import requests
import json
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
API_KEY = "YOUR_API_KEY_HERE"
API_URL = "https://api.aisay.tech.gov.sg/v1/extract"
FILE_PATH = "path/to/your/document.pdf"
vlm_prompt = {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "The full name of the individual as displayed in the document"
},
"nric": {
"type": "string",
"description": "The NRIC number, e.g. S1234567A"
}
},
"required": ["name", "nric"],
"additionalProperties": False
}
payload = {
"model_type": "GENERAL",
"data_classification": "RSN",
"vlm_prompt": json.dumps(vlm_prompt),
"source": "API"
}
files = [
('file', ('document.pdf', open(FILE_PATH, 'rb'), 'application/pdf'))
]
headers = {
'Authorization': f'Bearer {API_KEY}'
}
response = requests.post(API_URL, headers=headers, files=files, data=payload, verify=False)
if response.status_code == 200:
print(json.dumps(response.json(), indent=2))
else:
print(f"Error {response.status_code}: {response.text}")Example: Extraction with Arrays (Nested Objects)
This example extracts both simple fields and a list of transactions from a bank statement:
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
}
# Send using the same payload/files/headers pattern as above
payload = {
"model_type": "GENERAL",
"data_classification": "RSN",
"vlm_prompt": json.dumps(vlm_prompt),
"source": "API"
}Document Classification
Classify documents into pre-defined categories.
Endpoint
POST /v1/classifyRequest (Multipart Form Data)
| Parameter | Type | Required | Description |
|---|---|---|---|
file |
file | Yes | The document file |
data_classification |
string | Yes | RSN (Flagship) or CCE (Local) |
document_categories |
string | Yes | Array of category/description objects, stringified with json.dumps() |
Model Limits
| Limit | Flagship (RSN) |
Local (CCE) |
|---|---|---|
| Max pages | 150 | 50 |
| Max file size | 20 MB | โ |
| Supported formats | PDF, JPG, TIFF, PNG, XLSX, DOCX | PDF, JPG, TIFF, PNG, XLSX, DOCX |
Example
import requests
import json
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
API_KEY = "YOUR_API_KEY_HERE"
API_URL = "https://api.aisay.tech.gov.sg/v1/classify"
FILE_PATH = "path/to/your/document.pdf"
document_categories = [
{
"category": "PASSPORT",
"description": "Official government-issued identity document for international travel, typically containing a photograph, personal details like name, date of birth, nationality, signature, and an expiry date."
},
{
"category": "BANK_STATEMENT",
"description": "A periodic summary from a financial institution detailing all transactions (deposits, withdrawals, transfers) in a specific account over a defined period, showing opening and closing balances, and often the account holder's name and address."
},
{
"category": "PAYSLIP",
"description": "A document issued by an employer to an employee, detailing the employee's gross earnings, itemized deductions (e.g., CPF contributions, income tax), and net pay for a specific pay period."
},
{
"category": "UNCLASSIFIED",
"description": "Any document that does not fit into the defined categories above."
}
]
headers = {
"Authorization": f"Bearer {API_KEY}"
}
files = {
"file": open(FILE_PATH, "rb")
}
data = {
"document_categories": json.dumps(document_categories),
"data_classification": "RSN"
}
response = requests.post(API_URL, headers=headers, files=files, data=data, verify=False)
if response.status_code == 200:
result = response.json()
print(f"Document Type: {result['document_type']}")
print(json.dumps(result, indent=2))
else:
print(f"Error {response.status_code}: {response.text}")Document OCR
Extract all visible text from a document in markdown format.
Endpoint
POST /v1/parseRequest (Multipart Form Data)
| Parameter | Type | Required | Description |
|---|---|---|---|
file |
file | Yes | The document file (PDF, JPG, PNG, TIFF) |
data_classification |
string | Yes | RSN only โ this endpoint does not accept CCE |
Important: The OCR endpoint only supports the Flagship model (
RSN). Local model (CCE) is not available for this endpoint.
Example
import requests
import json
API_KEY = "YOUR_API_KEY_HERE"
API_URL = "https://api.aisay.tech.gov.sg/v1/parse"
headers = {
"Authorization": f"Bearer {API_KEY}"
}
files = {
"file": open("path/to/your/document.pdf", "rb"),
"data_classification": "RSN"
}
response = requests.post(API_URL, headers=headers, files=files)
if response.status_code == 200:
result = response.json()
print(result["parsed_document"])
else:
print(f"Error {response.status_code}: {response.text}")See Also
- API Integration Guide โ Step-by-step getting started
- Data Extraction (KIE) โ Full Guide
- Document Classification โ Full Guide
- Pricing