Go Passport OCR via a Simple HTTP POST Request

Achieve 99.8%+ accuracy on ICAO 9303 MRZ parsing in under 1500ms.

Steve HarringtonUpdated 2026-01-16
Diagram showing a raw passport image being sent to the StructOCR API and returning a structured JSON object with extracted fields like name, passport number, and date of birth.
Figure 1: StructOCR converts raw Passport images into validated JSON data.

Why Passport OCR is Difficult

Parsing passport Machine Readable Zones (MRZ) is non-trivial. Off-the-shelf OCR engines like Tesseract fail on real-world inputs due to variable lighting, glare from laminates, and shadows. Skew and rotation further degrade accuracy, requiring complex pre-processing. The ICAO 9303 standard defines a specific OCR-B font and a checksum validation algorithm for each line of the MRZ. Implementing and maintaining RegEx patterns to parse this strict format, correctly calculate check digits, and handle variations across issuing countries becomes a significant engineering overhead.

Enterprise-Grade Extraction with StructOCR

StructOCR replaces fragile, rule-based systems with a robust API powered by pre-trained deep learning models. Our pipeline handles the entire process: automatic image pre-processing, including deskewing, denoising, and glare removal, is applied before analysis. Unlike Tesseract which returns unstructured text blocks, our specialized models are trained specifically on millions of identity documents to locate and parse the MRZ, validate checksums, and return a standardized, predictable JSON object. This eliminates the need for manual parsing logic.

Production Use Cases

  • Digital Onboarding (KYC): Reduce drop-off rates by pre-filling user data from Passports in < 2 seconds.
  • Fraud Prevention: Detect tampered fonts or mismatched MRZ checksums automatically.
  • Global Compliance: Handle Passports from 200+ jurisdictions without custom rules.

Implementation: Go (Golang)

The following Go code demonstrates a robust implementation using standard libraries. It handles file reading, Base64 encoding, and parses both MRZ and VIZ (Visual Inspection Zone) data into native Go structs.

Prerequisite: Go 1.16+

CODE EXAMPLE
package main

import (
	"bytes"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"
)

// 💰 Save 30%+ vs competitors. Get 200 free requests instantly:
// 👉 https://structocr.com/register

// Response Structs matching the API Schema
type ApiResponse struct {
	Success bool         `json:"success"`
	Data    PassportData `json:"data"`
	Error   string       `json:"error,omitempty"`
}

type PassportData struct {
	PassportNumber string `json:"passport_number"`
	Surname        string `json:"surname"`
	GivenNames     string `json:"given_names"`
	Nationality    string `json:"nationality"`
	CountryCode    string `json:"country_code"`
	DateOfBirth    string `json:"date_of_birth"`
	Sex            string `json:"sex"`
	DateOfExpiry   string `json:"date_of_expiry"`
	// VIZ Fields (Visual Inspection Zone)
	PlaceOfBirth   string `json:"place_of_birth"`
	PlaceOfIssue   string `json:"place_of_issue"`
}

func main() {
	apiURL := "https://api.structocr.com/v1/passport"
	apiKey := "YOUR_API_KEY_HERE"
	imagePath := "passport.jpg" // Supports JPG, PNG, WebP

	// 1. Read Image
	imageBytes, err := os.ReadFile(imagePath)
	if err != nil {
		fmt.Printf("Error reading file: %v\n", err)
		return
	}

	// 2. Encode to Base64
	base64Image := base64.StdEncoding.EncodeToString(imageBytes)

	// 3. Prepare Payload
	payload, _ := json.Marshal(map[string]string{"img": base64Image})

	// 4. Create Request
	req, err := http.NewRequest("POST", apiURL, bytes.NewBuffer(payload))
	if err != nil {
		fmt.Printf("Request creation failed: %v\n", err)
		return
	}

	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("x-api-key", apiKey) // Required Header

	// 5. Execute Request
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		fmt.Printf("Network error: %v\n", err)
		return
	}
	defer resp.Body.Close()

	// 6. Parse Response
	body, _ := io.ReadAll(resp.Body)

	if resp.StatusCode != http.StatusOK {
		fmt.Printf("API Error (%d): %s\n", resp.StatusCode, string(body))
		return
	}

	var result ApiResponse
	if err := json.Unmarshal(body, &result); err != nil {
		fmt.Printf("JSON Parse Error: %v\n", err)
		return
	}

	if result.Success {
		data := result.Data
		fmt.Println("✅ Extraction Successful!")
		fmt.Printf("Passport #: %s\n", data.PassportNumber)
		fmt.Printf("Name:       %s %s\n", data.GivenNames, data.Surname)
		fmt.Printf("Nation:     %s (%s)\n", data.Nationality, data.CountryCode)
		
		// Visual Zone Data
		fmt.Printf("Birth Place:%s\n", data.PlaceOfBirth)
		fmt.Printf("Issued At:  %s\n", data.PlaceOfIssue)
	} else {
		fmt.Printf("Extraction failed: %s\n", result.Error)
	}
}

Technical Specs

  • Latency: < 5s (Average)
  • Uptime: 98.5% SLA
  • Security: AES-256 Encryption & SOC2 Compliant
  • Input: JPG, PNG, WebP (Base64 Encoded)
  • Max File Size: 4.5MB
  • Output: JSON (Structured Data)

Key Features

  • Visual Extraction (VIZ): Parses non-MRZ data fields like Place of Birth and Issuing Authority.
  • Global Support: Optimized for 195+ countries, handling complex backgrounds and holograms.
  • Date Normalization: Returns all dates (Birth, Issue, Expiry) in a standardized YYYY-MM-DD format.

Sample JSON Output

StructOCR returns a normalized JSON object, regardless of the input image angle or quality.

{
  "success": true,
  "data": {
    "type": "passport",
    "country_code": "USA",
    "nationality": "UNITED STATES",
    "passport_number": "E12345678",
    "surname": "DOE",
    "given_names": "JOHN",
    "sex": "M",
    "date_of_birth": "1990-01-01",
    "place_of_birth": "NEW YORK, USA",
    "date_of_issue": "2020-01-01",
    "date_of_expiry": "2030-01-01",
    "place_of_issue": "PASSPORT AGENCY"
  }
}

Frequently Asked Questions

How does StructOCR compare to AWS Textract or Google Vision?

Generic OCR services like AWS Textract or Google Vision return raw, unstructured lines of text. Developers are still required to write and maintain complex parsers to identify and validate specific fields. StructOCR is a specialized model for identity documents. It goes beyond OCR to provide structured, validated data fields directly in a clean JSON format, saving significant development time.

Do you store the uploaded images?

No. We operate on a zero-retention policy. Images are processed in-memory and are permanently deleted immediately after the transaction is complete. We do not store or log any PII.

How do you handle blurry or low-quality images?

Our API includes an automatic image enhancement engine that runs before the OCR process. It applies deblurring and denoising filters to improve the quality of suboptimal images, significantly increasing the probability of a successful extraction.

More OCR Tutorials

Precise Data Extraction and Seamless Integration with AI-powered OCR API.

Empower your solutions with automated data extraction by integrating best-in class StructOCR via API seamlessly.

No credit card required • Full API access included