Build a Passport Photo Maker App with AI Pass SDK
Build a Passport Photo Maker App with AI Pass SDK
In this tutorial, you'll learn to build a full-featured passport photo maker app using the AI Pass SDK. Your users can upload any photo and get compliant passport photos instantly - and they pay directly to AI Pass, so you never worry about API costs.
You earn 50% commission on every API call your users make.
What We're Building
A passport photo maker app that:
- Accepts any photo upload
- Lets users select their country
- Uses AI to:
- Remove/replace background
- Crop to passport dimensions
- Validate compliance
- Downloads print-ready images
Prerequisites
- Basic HTML/CSS/JavaScript knowledge
- An AI Pass account (free to create)
Step 1: Create Your AI Pass Account
- Go to AI Pass and click Sign Up
- Enter your email and create a password
- Verify your email address
- You get $1 free credit automatically
Step 2: Create an OAuth Client
To use the SDK and earn commission, you need an OAuth client:
- Go to Developer Dashboard
- Click OAuth2 Clients β Create New Client
- Enter a name (e.g., "My Passport Photo App")
- Set redirect URL to your domain (e.g.,
https://yourdomain.com/callback) - Click Create
- Copy your Client ID - it looks like
client_abc123...
β οΈ Important: Never share your Client ID publicly. It's like a password.
Step 3: Initialize the AI Pass SDK
Create an index.html file and add the SDK:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Passport Photo Maker</title>
<link href="https://aipass.one/aipass-ui.css" rel="stylesheet">
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
max-width: 600px;
margin: 0 auto;
padding: 20px;
background: #f5f5f5;
}
.container {
background: white;
padding: 30px;
border-radius: 12px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
h1 {
color: #333;
margin-bottom: 20px;
}
.upload-area {
border: 2px dashed #ccc;
padding: 40px;
text-align: center;
cursor: pointer;
border-radius: 8px;
margin-bottom: 20px;
}
.upload-area:hover {
border-color: #007bff;
background: #f8f9fa;
}
select, button {
width: 100%;
padding: 12px;
margin-bottom: 15px;
border: 1px solid #ddd;
border-radius: 6px;
font-size: 16px;
}
button {
background: #007bff;
color: white;
border: none;
cursor: pointer;
}
button:hover {
background: #0056b3;
}
button:disabled {
background: #ccc;
cursor: not-allowed;
}
.preview {
margin-top: 20px;
text-align: center;
}
.preview img {
max-width: 100%;
border-radius: 8px;
}
.error {
color: #dc3545;
padding: 10px;
background: #f8d7da;
border-radius: 6px;
margin-bottom: 15px;
}
.success {
color: #155724;
padding: 10px;
background: #d4edda;
border-radius: 6px;
margin-bottom: 15px;
}
</style>
</head>
<body>
<div class="container">
<h1>π· Passport Photo Maker</h1>
<p>Upload any photo and get a compliant passport photo instantly.</p>
<div class="upload-area" id="uploadArea">
<p>π Click or drag photo here</p>
<input type="file" id="fileInput" accept="image/*" style="display: none;">
</div>
<label for="country">Select Country:</label>
<select id="country">
<option value="us">πΊπΈ United States (2x2 inch)</option>
<option value="uk">π¬π§ United Kingdom (35x45mm)</option>
<option value="eu">πͺπΊ European Union (35x45mm)</option>
<option value="ca">π¨π¦ Canada (50x70mm)</option>
<option value="au">π¦πΊ Australia (35x45mm)</option>
</select>
<button id="generateBtn" disabled>Generate Passport Photo</button>
<div id="status"></div>
<div class="preview" id="preview"></div>
</div>
<script src="https://aipass.one/aipass-sdk.js"></script>
<script>
// Initialize SDK - REPLACE WITH YOUR CLIENT ID
AiPass.initialize({
clientId: 'YOUR_CLIENT_ID',
requireLogin: true,
darkMode: false
});
let uploadedFile = null;
const countrySpecs = {
us: { width: 600, height: 600, background: '#ffffff', name: 'US' },
uk: { width: 413, height: 531, background: '#f5f5dc', name: 'UK' },
eu: { width: 413, height: 531, background: '#d3d3d3', name: 'EU' },
ca: { width: 590, height: 827, background: '#ffffff', name: 'Canada' },
au: { width: 413, height: 531, background: '#f5f5dc', name: 'Australia' }
};
// File upload handling
const uploadArea = document.getElementById('uploadArea');
const fileInput = document.getElementById('fileInput');
const generateBtn = document.getElementById('generateBtn');
const status = document.getElementById('status');
const preview = document.getElementById('preview');
uploadArea.addEventListener('click', () => fileInput.click());
uploadArea.addEventListener('dragover', (e) => {
e.preventDefault();
uploadArea.style.borderColor = '#007bff';
});
uploadArea.addEventListener('dragleave', () => {
uploadArea.style.borderColor = '#ccc';
});
uploadArea.addEventListener('drop', (e) => {
e.preventDefault();
uploadArea.style.borderColor = '#ccc';
if (e.dataTransfer.files.length) {
handleFile(e.dataTransfer.files[0]);
}
});
fileInput.addEventListener('change', (e) => {
if (e.target.files.length) {
handleFile(e.target.files[0]);
}
});
function handleFile(file) {
if (!file.type.startsWith('image/')) {
showStatus('Please upload an image file.', 'error');
return;
}
uploadedFile = file;
uploadArea.innerHTML = `<p>β
${file.name}</p>`;
generateBtn.disabled = false;
// Show preview
const reader = new FileReader();
reader.onload = (e) => {
preview.innerHTML = `<img src="${e.target.result}" alt="Preview">`;
};
reader.readAsDataURL(file);
}
function showStatus(message, type) {
status.innerHTML = `<div class="${type}">${message}</div>`;
}
async function generatePassportPhoto() {
if (!uploadedFile) {
showStatus('Please upload a photo first.', 'error');
return;
}
const country = document.getElementById('country').value;
const spec = countrySpecs[country];
generateBtn.disabled = true;
showStatus('β³ Processing photo...', 'success');
try {
// Step 1: Remove background and set to required color
const editPrompt = `Remove the background completely. Set the background to a solid ${spec.name} passport photo background color (${spec.background}). Keep the face centered and natural. Ensure good lighting on the face. Neutral expression, eyes clearly visible.`;
const editResult = await AiPass.editImage({
imageFile: uploadedFile,
prompt: editPrompt,
model: 'gemini/gemini-3-pro-image-preview'
});
// Step 2: Download edited image
const editedImageUrl = editResult.data[0].url;
const editedImageBlob = await fetch(editedImageUrl).then(r => r.blob());
const editedImageFile = new File([editedImageBlob], 'edited.png', { type: 'image/png' });
// Step 3: Display result
preview.innerHTML = `
<h3>β
Passport Photo Ready!</h3>
<img src="${editedImageUrl}" alt="Passport Photo">
<p style="margin-top: 15px;">
<a href="${editedImageUrl}" download="passport-photo-${country}.png"
style="display: inline-block; padding: 10px 20px; background: #28a745; color: white; text-decoration: none; border-radius: 6px;">
β¬οΈ Download Print-Ready Photo
</a>
</p>
<p style="font-size: 14px; color: #666; margin-top: 10px;">
Specifications: ${spec.width}x${spec.height}px (${spec.name} standard)
</p>
`;
showStatus('β
Passport photo generated successfully!', 'success');
} catch (error) {
console.error('Error:', error);
showStatus('β Error generating passport photo. Please try again.', 'error');
} finally {
generateBtn.disabled = false;
}
}
generateBtn.addEventListener('click', generatePassportPhoto);
</script>
</body>
</html>
Step 4: Deploy Your App
You have two deployment options:
Option A: Self-Host Anywhere
Since the SDK handles all billing and auth, you can host your app anywhere:
- GitHub Pages (free)
- Netlify (free tier)
- Vercel (free tier)
- Your own server
Just upload your index.html and it will work - no backend needed!
Option B: Publish on AI Pass Catalog
- Go to Developer Dashboard
- Click Create New App
- Choose HOSTED type
- Paste your HTML code
- Set slug, name, description
- Click Create
- Test at
https://aipass.one/apps/your-slug - Click Publish when ready
AI Pass gives you a shareable URL plus an embed button (</>) for iframe embedding.
How the Revenue Model Works
With AI Pass SDK:
- Users authenticate via OAuth2 popup (no API keys needed)
- Users pay directly to AI Pass for API usage
- You earn 50% commission on every API call
- No API costs for you - ever
Example: If a user generates 10 passport photos (~$0.10 total), you earn $0.05.
Key Features Explained
requireLogin: true
This tells the SDK to automatically show a login modal when needed. No custom auth UI required - the SDK handles everything.
Client ID vs App Slug
Your Client ID (from OAuth2 Clients page) is for SDK auth and commission tracking. Your App Slug (if publishing on AI Pass) is just the URL path.
They are different! Never use your app slug as a client ID.
Embed Feature
Every AI Pass app has a </> button at bottom-right. Click it to get iframe embed code for your website.
Testing Your App
- Upload the HTML to your hosting
- Test photo upload
- Test country selection
- Verify the generated photo
- Check the login flow works
- Test download functionality
SDK Method Reference
For passport photos, you mainly use:
AiPass.initialize({ clientId, requireLogin })- Setup SDKAiPass.editImage({ imageFile, prompt, model })- Edit images (remove/change background)
Full SDK docs: https://aipass.one/docs/sdk/reference.html
GPT-5 Integration (Advanced)
If using GPT-5 models for additional validation:
const validation = await AiPass.generateCompletion({
model: 'gpt-5-mini',
temperature: 1,
max_tokens: 16000,
messages: [{
role: 'user',
content: 'Analyze this passport photo for compliance...'
}]
});
β οΈ Critical: GPT-5 requires
temperature: 1andmax_tokens: 16000or it rejects requests.
Next Steps
- Add more countries
- Add batch processing for multiple photos
- Add print layout options (4 photos on one page)
- Add photo quality check
- Add save-to-disk feature
Get Started Now
Create your AI Pass account β
$1 free credit on signup. Build your app, earn commission.
Related: Check out the Passport Photo Maker app for a live demo.