API Documentation
Integrate AltFrame into your application with our REST API. Generate AI-powered alt text, titles, captions, and Open Graph descriptions for any image.
Single Generation
Synchronous. Process one image and receive results immediately.
Bulk Generation
Asynchronous. Submit up to 100 images and poll or receive a webhook.
Usage & History
Track credits, monitor usage, and browse generation history.
Base URL
All API endpoints are relative to the following base URL:
https://altframe.appAll requests must be made over HTTPS. HTTP requests will be rejected.
Authentication
All API requests require authentication using an API key. You can create and manage keys in the API Keys section of your dashboard.
Include your key in one of these request headers:
x-api-key: af_live_your_api_key
# or
Authorization: Bearer af_live_your_api_keyKeep your API key secret
Do not expose your API key in client-side code, public repositories, or browser network requests. Always call the AltFrame API from your server.
Quick Start
Generate alt text for an image with a single API call:
curl -X POST https://altframe.app/api/v1/generate \
-H "x-api-key: af_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"image_url": "https://example.com/photo.jpg",
"mode": "standard",
"language": "en",
"keywords": ["organic gardening", "tomato seeds"],
"max_length": 125,
"fields": ["alt_text", "title", "caption", "og_description"]
}'Response
{
"id": "job_abc123",
"status": "completed",
"results": {
"alt_text": "Hands planting organic tomato seeds in rich dark soil in a raised garden bed",
"title": "Planting Organic Tomato Seeds in Garden",
"caption": "A gardener carefully plants organic tomato seeds into nutrient-rich soil in a raised bed.",
"og_description": "Learn sustainable gardening with organic tomato seed planting techniques."
},
"meta": {
"language": "en",
"model": "gpt-4.1-nano",
"tokens": { "input": 1180, "output": 142 },
"processing_ms": 820,
"credits_used": 1,
"credits_remaining": 999
}
}/api/v1/generateGenerate alt text, title, caption, and OG description for a single image. The request is processed synchronously and the result is returned immediately.
Request Body
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| image_url | string | Required* | — | Publicly accessible URL of the image to process. |
| image_base64 | string | Required* | — | Base64-encoded image data. Use this when the image is not publicly accessible. |
| mode | string | Optional | "standard" | Generation mode: "standard", "ecommerce", or "decorative". |
| language | string | Optional | "en" | ISO 639-1 language code for the generated text. Falls back to your account default language. |
| keywords | string[] | Optional | — | SEO keywords to naturally incorporate into the generated text. |
| max_length | number | Optional | 125 | Maximum character length for the alt text output. |
| page_url | string | Optional | — | URL of the page where the image appears. Provides additional context for more accurate results. |
| page_context | string | Optional | — | Surrounding text or heading near the image. Helps the AI understand the image's role on the page. |
| product_name | string | Optional | — | Product name for ecommerce mode. Most useful when mode is "ecommerce". |
| product_sku | string | Optional | — | Product SKU or identifier for reference. |
| product_attributes | Record<string, string> | Optional | — | Key-value pairs of product attributes (e.g. {"color": "red", "size": "large"}). |
| fields | string[] | Optional | all four | Which output fields to generate: "alt_text", "title", "caption", "og_description". Defaults to all four. |
| custom_prompt | string | Optional | — | Custom instructions appended to the AI prompt. Available on Tier 2 plans and above. |
* One of image_url or image_base64 is required. If both are provided, image_url takes precedence.
Response 200 OK
{
"id": "job_abc123",
"status": "completed",
"results": {
"alt_text": "Hands planting organic tomato seeds in rich dark soil in a raised garden bed",
"title": "Planting Organic Tomato Seeds in Garden",
"caption": "A gardener carefully plants organic tomato seeds into nutrient-rich soil in a raised bed.",
"og_description": "Learn sustainable gardening with organic tomato seed planting techniques."
},
"meta": {
"language": "en",
"model": "gpt-4.1-nano",
"tokens": { "input": 1180, "output": 142 },
"processing_ms": 820,
"credits_used": 1,
"credits_remaining": 999
}
}| Field | Type | Description |
|---|---|---|
| id | string | Unique job identifier. |
| status | string | "completed" on success. |
| results.alt_text | string | Generated alt text for the image. |
| results.title | string | Generated title / heading. |
| results.caption | string | Generated caption with more detail. |
| results.og_description | string | Generated Open Graph description. |
| meta.language | string | Language used for generation. |
| meta.model | string | AI model used. |
| meta.tokens.input | number | Input tokens consumed. |
| meta.tokens.output | number | Output tokens generated. |
| meta.processing_ms | number | Server-side processing time in milliseconds. |
| meta.credits_used | number | Credits deducted for this request. |
| meta.credits_remaining | number | Your remaining credit balance. |
Code Examples
curl -X POST https://altframe.app/api/v1/generate \
-H "x-api-key: af_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"image_url": "https://example.com/photo.jpg",
"mode": "standard",
"language": "en",
"keywords": ["organic gardening", "tomato seeds"],
"max_length": 125,
"fields": ["alt_text", "title", "caption", "og_description"]
}'/api/v1/generate/bulkSubmit a batch of up to 100 images for asynchronous processing. Credits are reserved upfront. The API returns immediately with a batch_id that you can poll for status, or provide a webhook_url to be notified when the batch completes.
Request Body
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| images | object[] | Required | — | Array of image objects (max 100). Each object can include the fields listed below. |
| mode | string | Optional | "standard" | Generation mode applied to all images: "standard", "ecommerce", or "decorative". |
| language | string | Optional | "en" | ISO 639-1 language code applied to all images. |
| keywords | string[] | Optional | — | SEO keywords applied to all images in the batch. |
| fields | string[] | Optional | all four | Output fields to generate for every image: "alt_text", "title", "caption", "og_description". |
| webhook_url | string | Optional | — | URL to receive a POST request when the batch finishes. See the Webhooks section below. |
Image Object Fields
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| image_url | string | Required* | — | Publicly accessible URL of the image. |
| image_base64 | string | Required* | — | Base64-encoded image data. |
| page_url | string | Optional | — | Page URL for context. |
| page_context | string | Optional | — | Surrounding text for context. |
| product_name | string | Optional | — | Product name (ecommerce mode). |
| product_sku | string | Optional | — | Product SKU or identifier. |
| product_attributes | Record<string, string> | Optional | — | Key-value product attributes. |
* One of image_url or image_base64 is required per image.
Response 202 Accepted
{
"batch_id": "b47ac10b-58cc-4372-a567-0e02b2c3d479",
"total_images": 3,
"credits_reserved": 3,
"estimated_seconds": 6,
"status_url": "/api/v1/batches/b47ac10b-58cc-4372-a567-0e02b2c3d479"
}| Field | Type | Description |
|---|---|---|
| batch_id | string (UUID) | Unique identifier for this batch. |
| total_images | number | Number of images submitted. |
| credits_reserved | number | Total credits reserved for the batch. |
| estimated_seconds | number | Estimated processing time in seconds. |
| status_url | string | Relative URL to poll for batch status. |
Code Examples
curl -X POST https://altframe.app/api/v1/generate/bulk \
-H "x-api-key: af_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"images": [
{
"image_url": "https://example.com/product-1.jpg",
"product_name": "Organic Tomato Seeds",
"product_sku": "SKU-TOM-001"
},
{
"image_url": "https://example.com/product-2.jpg",
"product_name": "Garden Trowel Set",
"product_sku": "SKU-TRW-042"
},
{
"image_url": "https://example.com/product-3.jpg"
}
],
"mode": "ecommerce",
"language": "en",
"keywords": ["gardening", "organic"],
"fields": ["alt_text", "title"],
"webhook_url": "https://yourapp.com/webhooks/altframe"
}'/api/v1/batches/:batch_idCheck the processing status of a batch. Returns completed results, in-progress counts, and any errors.
URL Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| batch_id | string (UUID) | Required | — | The batch_id returned from the bulk generation endpoint. |
Response 200 OK
{
"batch_id": "b47ac10b-58cc-4372-a567-0e02b2c3d479",
"status": "completed",
"total": 3,
"completed": 3,
"failed": 0,
"results": [
{
"id": "job_def456",
"image_url": "https://example.com/product-1.jpg",
"results": {
"alt_text": "Packet of organic heirloom tomato seeds with planting instructions",
"title": "Organic Heirloom Tomato Seeds"
},
"meta": {
"model": "gpt-4.1-nano",
"tokens": { "input": 1024, "output": 96 },
"processing_ms": 740
}
},
{
"id": "job_ghi789",
"image_url": "https://example.com/product-2.jpg",
"results": {
"alt_text": "Three-piece stainless steel garden trowel set with ergonomic handles",
"title": "3-Piece Garden Trowel Set"
},
"meta": {
"model": "gpt-4.1-nano",
"tokens": { "input": 980, "output": 88 },
"processing_ms": 690
}
},
{
"id": "job_jkl012",
"image_url": "https://example.com/product-3.jpg",
"results": {
"alt_text": "Wooden raised garden bed kit with soil and seedlings",
"title": "Raised Garden Bed Starter Kit"
},
"meta": {
"model": "gpt-4.1-nano",
"tokens": { "input": 1100, "output": 102 },
"processing_ms": 810
}
}
],
"errors": []
}| Field | Type | Description |
|---|---|---|
| batch_id | string | The batch identifier. |
| status | string | "processing", "completed", "partial", or "failed". |
| total | number | Total images in the batch. |
| completed | number | Number of successfully processed images. |
| failed | number | Number of images that failed processing. |
| results | object[] | Array of completed results with id, image_url, results, and meta. |
| errors | object[] | Array of failed items with id, image_url, and error message. |
Batch Status Values
| Status | Meaning |
|---|---|
| processing | One or more images are still being processed. |
| completed | All images have been successfully processed. |
| partial | Processing is done but some images failed. |
| failed | All images in the batch failed. |
Code Examples
curl https://altframe.app/api/v1/batches/b47ac10b-58cc-4372-a567-0e02b2c3d479 \
-H "x-api-key: af_live_your_api_key"/api/v1/historyRetrieve your generation history with pagination. Results are ordered by creation date, newest first.
Query Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| limit | number | Optional | 50 | Number of results per page (1 to 100). |
| offset | number | Optional | 0 | Number of results to skip for pagination. |
| status | string | Optional | — | Filter by job status: "completed", "failed", "pending", or "processing". |
Response 200 OK
{
"jobs": [
{
"id": "job_abc123",
"status": "completed",
"image_url": "https://example.com/photo.jpg",
"results": {
"alt_text": "Hands planting organic tomato seeds in rich dark soil",
"title": "Planting Organic Tomato Seeds",
"caption": "A gardener plants tomato seeds into nutrient-rich soil.",
"og_description": "Sustainable organic tomato seed planting techniques."
},
"mode": "standard",
"language": "en",
"meta": {
"model": "gpt-4.1-nano",
"tokens": { "input": 1180, "output": 142 },
"processing_ms": 820,
"cost_usd": 0.0004
},
"source": "api",
"batch_id": null,
"error": null,
"created_at": "2025-07-15T10:30:00.000Z",
"completed_at": "2025-07-15T10:30:00.820Z"
}
],
"pagination": {
"total": 142,
"limit": 10,
"offset": 0,
"has_more": true
}
}| Field | Type | Description |
|---|---|---|
| jobs | object[] | Array of job objects. |
| jobs[].id | string | Unique job identifier. |
| jobs[].status | string | Job status: "completed", "failed", "pending", "processing". |
| jobs[].image_url | string | null | Original image URL (null if base64 was used). |
| jobs[].results | object | Generated alt_text, title, caption, og_description. |
| jobs[].mode | string | Generation mode used. |
| jobs[].language | string | Language used. |
| jobs[].meta | object | Model, tokens, processing_ms, cost_usd. |
| jobs[].source | string | "api", "bulk", or "dashboard". |
| jobs[].batch_id | string | null | Batch ID if part of a bulk job. |
| jobs[].error | string | null | Error message if the job failed. |
| jobs[].created_at | string | ISO 8601 timestamp when the job was created. |
| jobs[].completed_at | string | null | ISO 8601 timestamp when the job finished. |
| pagination.total | number | Total number of jobs matching your query. |
| pagination.limit | number | Page size used. |
| pagination.offset | number | Current offset. |
| pagination.has_more | boolean | Whether more results are available. |
Code Examples
curl "https://altframe.app/api/v1/history?limit=10&offset=0&status=completed" \
-H "x-api-key: af_live_your_api_key"/api/v1/usageCheck your current plan, credit balance, and overage settings. No request parameters required.
Response 200 OK
{
"plan": "pro",
"credits": {
"monthly_allocation": 5000,
"remaining": 4832,
"rollover": 0,
"used_this_period": 168,
"period_resets_at": "2025-08-01T00:00:00.000Z"
},
"overage": {
"enabled": true,
"rate": 0.03
}
}| Field | Type | Description |
|---|---|---|
| plan | string | Your current plan name (e.g. "free", "starter", "pro", "business"). |
| credits.monthly_allocation | number | Total credits included in your plan per billing period. |
| credits.remaining | number | Credits remaining in the current period. |
| credits.rollover | number | Unused credits rolled over from the previous period. |
| credits.used_this_period | number | Credits consumed so far this period. |
| credits.period_resets_at | string | ISO 8601 timestamp when credits reset (1st of next month UTC). |
| overage.enabled | boolean | Whether overage billing is enabled on your account. |
| overage.rate | number | Price per credit (USD) when exceeding your allocation. |
Code Examples
curl https://altframe.app/api/v1/usage \
-H "x-api-key: af_live_your_api_key"Webhooks
When submitting a bulk generation request, you can include a webhook_url parameter. AltFrame will send a POST request to that URL when the entire batch has finished processing.
How It Works
- Include
webhook_urlin your bulk generation request. - AltFrame processes all images asynchronously.
- When the batch is fully complete (all images succeeded or failed), AltFrame sends a POST to your webhook URL.
- Your server should respond with a
2xxstatus code to acknowledge receipt.
Webhook Payload
// Your server receives a POST request when a batch completes:
POST https://yourapp.com/webhooks/altframe
Content-Type: application/json
{
"event": "batch.completed",
"batch_id": "b47ac10b-58cc-4372-a567-0e02b2c3d479",
"status": "completed",
"total": 3,
"completed": 3,
"failed": 0,
"results": [
{
"id": "job_def456",
"image_url": "https://example.com/product-1.jpg",
"results": {
"alt_text": "Packet of organic heirloom tomato seeds",
"title": "Organic Heirloom Tomato Seeds"
}
}
],
"errors": []
}Example Handler
// Express.js webhook handler example
app.post("/webhooks/altframe", (req, res) => {
const { event, batch_id, status, results, errors } = req.body;
if (event === "batch.completed") {
console.log(`Batch ${batch_id} finished: ${status}`);
// Update your database with the generated alt text
for (const item of results) {
db.images.update({
where: { url: item.image_url },
data: {
alt_text: item.results.alt_text,
title: item.results.title,
},
});
}
// Handle any failures
for (const err of errors) {
console.error(`Failed: ${err.image_url} - ${err.error}`);
}
}
res.status(200).json({ received: true });
});Best Practices
- Respond quickly (within 5 seconds) and process results asynchronously in your own queue.
- Your webhook endpoint should be idempotent -- you may receive the same payload more than once on retry.
- Use the
batch_idto correlate webhook payloads with your original request. - If your server is unavailable, you can always poll the batch status endpoint as a fallback.
Rate Limits
Rate limits are applied per API key. When you exceed a limit, the API returns a 429 status code.
| Endpoint | Rate Limit | Window |
|---|---|---|
| POST /api/v1/generate | 60 requests | Per minute |
| POST /api/v1/generate/bulk | 10 requests | Per minute |
| GET /api/v1/batches/:batch_id | 120 requests | Per minute |
| GET /api/v1/history | 120 requests | Per minute |
| GET /api/v1/usage | 120 requests | Per minute |
Rate Limit Headers
Every response includes headers to help you track your rate limit status:
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 58
X-RateLimit-Reset: 1700000060Credit Costs
- Standard image (JPEG, PNG, WebP): 1 credit
- Advanced format (AVIF, HEIC, TIFF): 2 credits
- Additional language: +1 credit
Handling 429 Errors
- Wait until the
X-RateLimit-Resettimestamp. - Use exponential backoff for retries.
- For high-volume workloads, use the bulk endpoint instead.
Error Codes
All error responses return a JSON body with an error field describing the issue.
{
"error": "Either image_url or image_base64 is required."
}HTTP Status Codes
| Code | Name | Description | What to Do |
|---|---|---|---|
| 400 | Bad Request | Missing or invalid parameters in the request body. | Check the error message and fix the request payload. |
| 401 | Unauthorized | Invalid, missing, or revoked API key. | Verify your API key is correct and included in the x-api-key or Authorization header. |
| 402 | Payment Required | No credits remaining and overage billing is disabled. | Upgrade your plan, wait for credits to reset, or enable overage billing in your dashboard. |
| 404 | Not Found | The requested resource (e.g. batch) does not exist or does not belong to you. | Verify the resource ID and that you are using the correct API key. |
| 429 | Too Many Requests | Rate limit exceeded for this endpoint. | Wait for the rate limit window to reset. Use the X-RateLimit-Reset header. |
| 500 | Internal Server Error | An unexpected error occurred on our servers. | Retry the request with exponential backoff. If the error persists, contact support. |
Need help?
If you encounter issues not covered here, contact us at support@altframe.ai with your request ID and error details.