Overview
Authentication
API Key Authentication
The recommended way to authenticate. Go to Settings → API Key to generate your key. Include it in every request via the X-Api-Key header:
cURL
curl -X POST https://api.sangtao.ai/v2/images/generations \
-H "X-Api-Key: your-api-key-here" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-image-latest",
"prompt": "A vintage travel poster of Ha Long Bay at sunset",
"aspectRatio": "9:16",
"resolution": "2k"
}'Your API key is a secret. Do not expose it in client-side code (browsers, mobile apps). Only use it in server-side applications.
Credits System
Every job consumes credits. Check your balance before submitting:
JSON
GET /api/v2/account/balance
// Response
{
"freeCredit": 100, // Monthly plan credits
"purchasedCredit": 50, // Purchased credits
"lockedCredit": 10, // Held for running jobs
"availableCredit": 140 // free + purchased - locked
}| Phase | Description |
|---|---|
| Lock | Credits are estimated and locked when you submit a job |
| Process | Job runs. Actual cost may be lower than estimate |
| Settle | When complete, excess credits are automatically refunded |
Deduction order: free credits are used first, then purchased credits.
Job Polling
All creation endpoints return a jobId. Poll the job status endpoint to track progress:
pending→processing→complete|error
JavaScript
// 1. Submit job
const res = await fetch('https://api.sangtao.ai/v2/images/generations', {
method: 'POST',
headers: {
'X-Api-Key': 'your-api-key',
'Content-Type': 'application/json',
},
body: JSON.stringify({
model: 'gpt-image-latest',
prompt: 'A vintage travel poster of Ha Long Bay at sunset',
aspectRatio: '9:16',
resolution: '2K',
}),
})
const { data } = await res.json()
// 2. Poll until complete
const poll = setInterval(async () => {
const job = await fetch(`https://api.sangtao.ai/v2/images/generations/${data.jobId}`, {
headers: { 'X-Api-Key': 'your-api-key' },
}).then(r => r.json())
const status = job.data.status.toLowerCase()
if (status === 'complete') {
clearInterval(poll)
console.log('Image URL:', job.data.resultUrl)
} else if (status === 'error') {
clearInterval(poll)
console.error('Job failed:', job.data.error)
}
}, 5000) // Poll every 5 seconds