sangtao.ai
API key

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
}
PhaseDescription
LockCredits are estimated and locked when you submit a job
ProcessJob runs. Actual cost may be lower than estimate
SettleWhen 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