SA Document Validator API
Validate and extract structured data from South African identity documents. Supports ID cards, ID books, passports, and driver's licenses.
https://api.kcstudios.co.zaAuthentication
All API requests require an API key passed in the Authorization header as a Bearer token.
- Sign up at kcstudios.co.za
- Navigate to Dashboard > API Keys
- Click “Create New Key” and copy the generated key
Include the key in your requests:
Authorization: Bearer sk_live_your_api_keyKeep your API keys secret. Do not share them in client-side code, public repositories, or anywhere publicly accessible. If a key is compromised, revoke it immediately from the dashboard.
Validate Endpoint
https://api.kcstudios.co.za/api/v1/validate-documentUpload an image of a South African identity document and receive validated, extracted data as JSON. The API performs OCR extraction and validates the document fields for consistency and correctness.
Each successful validation consumes 2 tokens from your balance. Failed validations do not consume tokens.
Request Format
Option 1: Multipart Form Data (Recommended)
Send the document image as a file upload using multipart/form-data.
| Field | Type | Required | Description |
|---|---|---|---|
file | File | Yes | The document image file (JPEG, PNG, WebP, HEIC, or PDF) |
documentType | String | No | Document type hint. If omitted, the API will auto-detect the document type. |
curl -X POST https://api.kcstudios.co.za/api/v1/validate-document \
-H "Authorization: Bearer sk_live_your_api_key" \
-F "file=@id_card.jpg" \
-F "documentType=sa_id_card"Option 2: JSON with Base64
Send the document image as a base64-encoded string in a JSON body.
| Field | Type | Required | Description |
|---|---|---|---|
image | String | Yes | Base64-encoded image with data URI prefix |
documentType | String | No | Document type hint for faster processing |
curl -X POST https://api.kcstudios.co.za/api/v1/validate-document \
-H "Authorization: Bearer sk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"image": "data:image/jpeg;base64,/9j/4AAQ...",
"documentType": "sa_id_card"
}'Supported Document Types
Pass the documentType parameter to specify the type of document being uploaded. If omitted, the API will attempt to auto-detect the document type.
| Type | Description | Extracted Fields |
|---|---|---|
sa_id_card | South African smart ID card | ID number, name, DOB, gender, citizenship, nationality, document number |
sa_id_book | South African green ID book | ID number, name, DOB, gender, citizenship, country of birth |
sa_passport | South African passport | ID number, name, DOB, gender, nationality, passport number, issue/expiry dates |
foreign_passport | Foreign/international passport | Name, DOB, gender, nationality, passport number, issue/expiry dates, country code |
sa_drivers_license | South African driver's license | ID number, name, DOB, license number, vehicle codes, issue/expiry dates, restrictions |
Tip: Providing the documentType parameter improves accuracy and processing speed. When omitted, the API uses an extra detection step to identify the document type.
Response Format
Successful responses return a JSON object with validation results, extracted data, and metadata.
Successful Validation
{
"success": true,
"data": {
"documentType": "sa_id_card",
"isValid": true,
"validationErrors": [],
"extractedData": {
"idNumber": "9001015009087",
"firstName": "JOHN",
"lastName": "SMITH",
"dateOfBirth": "1990-01-01",
"gender": "Male",
"citizenship": "South African",
"countryOfBirth": "South Africa",
"dateOfIssue": "2015-03-15",
"expiryDate": null,
"documentNumber": "ABC123456"
},
"confidence": "high"
},
"meta": {
"scanId": "abc123",
"processingTimeMs": 2340,
"tokensUsed": 2,
"remainingTokens": 48
}
}Validation with Errors
When the document is processed but validation issues are found, isValid is set to false and the validationErrors array contains descriptions of the issues found.
{
"success": true,
"data": {
"documentType": "sa_id_card",
"isValid": false,
"validationErrors": [
"ID number checksum digit is invalid",
"Date of birth does not match ID number"
],
"extractedData": {
"idNumber": "9001015009088",
"firstName": "JOHN",
"lastName": "SMITH",
"dateOfBirth": "1991-01-01",
"gender": "Male",
"citizenship": "South African",
"countryOfBirth": "South Africa",
"dateOfIssue": "2015-03-15",
"expiryDate": null,
"documentNumber": "ABC123456"
},
"confidence": "medium"
},
"meta": {
"scanId": "def456",
"processingTimeMs": 2580,
"tokensUsed": 2,
"remainingTokens": 46
}
}Response Fields
| Field | Type | Description |
|---|---|---|
data.documentType | string | Detected or confirmed document type |
data.isValid | boolean | Whether the document passed all validation checks |
data.validationErrors | string[] | List of validation errors found (empty if valid) |
data.extractedData.idNumber | string | South African ID number (13 digits) |
data.extractedData.firstName | string | First name as it appears on the document |
data.extractedData.lastName | string | Last name / surname as it appears on the document |
data.extractedData.dateOfBirth | string | Date of birth in YYYY-MM-DD format |
data.extractedData.gender | string | Gender as stated on the document (“Male” or “Female”) |
data.extractedData.citizenship | string | Citizenship status |
data.extractedData.countryOfBirth | string | Country of birth if available |
data.extractedData.dateOfIssue | string | Document issue date in YYYY-MM-DD format |
data.extractedData.expiryDate | string | null | Document expiry date (null for non-expiring documents like SA ID cards) |
data.extractedData.documentNumber | string | Unique document/card number |
data.confidence | string | Confidence level: “high”, “medium”, or “low” |
meta.scanId | string | Unique identifier for this validation |
meta.processingTimeMs | number | Processing time in milliseconds |
meta.tokensUsed | number | Tokens consumed for this request (always 2) |
meta.remainingTokens | number | Remaining token balance |
Error Codes
Errors return a JSON object with success: false and an error object.
{
"success": false,
"error": {
"code": "INSUFFICIENT_TOKENS",
"message": "Not enough tokens. Balance: 1, required: 2.",
"status": 402
}
}| Status | Code | Description |
|---|---|---|
| 400 | BAD_REQUEST | Invalid request format or missing required fields. |
| 401 | UNAUTHORIZED | Missing or invalid API key. |
| 402 | INSUFFICIENT_TOKENS | Not enough tokens to process the request. Requires 2 tokens. |
| 403 | FORBIDDEN | API key has been revoked or account is suspended. |
| 404 | NOT_FOUND | The requested endpoint does not exist. |
| 413 | FILE_TOO_LARGE | Image exceeds the maximum file size of 10MB. |
| 415 | UNSUPPORTED_TYPE | File type not supported. Use JPEG, PNG, WebP, HEIC, or PDF. |
| 422 | PROCESSING_FAILED | Could not extract or validate data from the document image. |
| 429 | RATE_LIMITED | Too many requests. Check rate limit headers. |
| 500 | INTERNAL_ERROR | An unexpected server error occurred. |
Code Examples
curl -X POST https://api.kcstudios.co.za/api/v1/validate-document \
-H "Authorization: Bearer sk_live_your_api_key" \
-F "file=@id_card.jpg" \
-F "documentType=sa_id_card"Rate Limits
Rate limits are applied per API key and per user account to ensure fair usage.
| Scope | Limit | Window |
|---|---|---|
| Per API Key | 60 requests | 1 minute |
| Per API Key | 1,000 requests | 1 hour |
| Per User Account | 5,000 requests | 24 hours |
Rate limit information is included in response headers:
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 58
X-RateLimit-Reset: 1706012400