Overview
The MAIDEPOT Public API allows you to programmatically execute AI prompts (apps, image generation, and mashups) using API tokens. All executions run asynchronously, and you can track their progress through transaction endpoints or receive notifications via webhooks.
Key Features
- Execute any prompt type (app, image, mashup)
- Asynchronous execution with status tracking
- File upload support for documents, images, audio, and video
- Webhook notifications for completed executions
- Cursor-based pagination for transaction history
- Retry failed transactions
- Credit usage tracking
Requirements
- API access requires a paid plan (Pro, Business, or Enterprise)
- Valid API token with appropriate permissions
Authentication
All API requests require authentication using a Bearer token in the header. Authorization
Authorization: Bearer YOUR_API_TOKENYou can create and manage your API tokens from your profile. Manage API Tokens
Example
curl https://api.maidepot.com/api/v1/prompts \
-H "Authorization: Bearer maid_zzFC7on8-HxX_n-4PvAuTj_8OFvJYdYA3AzI4E57nSQVo2w9M6tF3aTtKp4VJ-bz"Rate Limiting
Rate limits are applied per account and vary by endpoint type:
- Execution endpoints: 120 requests/minute
- Metadata read endpoints: 300 requests/minute
- Polling endpoints: 600 requests/minute
- Management operations: 180 requests/minute
- File uploads: 60 requests/minute
Rate Limit Headers
Every response includes rate limit information in the headers:
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 119
X-RateLimit-Reset: 1612345678Rate Limit Exceeded Response (429)
{
"error": {
"type": "rate_limit_error",
"message": "Rate limit exceeded",
"code": "rate_limit_exceeded"
}
}Error Handling
All API errors follow a standardized structure based on RFC 7807 Problem Details pattern.
Error Response Structure
{
"error": {
"type": "validation_error",
"message": "Human-readable error message",
"code": "invalid_request",
"param": "inputs",
"details": ["Additional context"]
}
}HTTP Status Codes
| Status Code | Error Type | Description |
|---|---|---|
400 | validation_error | Invalid request data or missing required fields |
401 | authentication_error | Invalid or missing API token |
402 | insufficient_credits | Not enough credits to complete operation |
403 | permission_error | Token doesn't have permission for this resource |
404 | not_found | Resource not found (prompt, transaction, etc.) |
415 | unsupported_media_type | Unsupported file format |
429 | rate_limit_error | Rate limit exceeded (requests per minute) |
500 | internal_error | Internal server error |
Note: 402 Insufficient Credits is used when your account has exhausted its credit allocation, while 429 Rate Limit is used when you exceed the requests-per-minute limit. Both require different handling strategies (add credits vs. implement backoff).
Error Examples
400 - Validation Error
{
"error": {
"type": "validation_error",
"message": "Missing required input field: THING",
"code": "invalid_request",
"param": "inputs"
}
}401 - Authentication Error
{
"error": {
"type": "authentication_error",
"message": "Invalid or missing authentication credentials",
"code": "invalid_token"
}
}402 - Insufficient Credits
{
"error": {
"type": "insufficient_credits",
"message": "Insufficient credits to complete this operation",
"code": "insufficient_credits"
}
}403 - Permission Error
{
"error": {
"type": "permission_error",
"message": "This token is not authorized to execute this prompt",
"code": "prompt_not_allowed"
}
}415 - Unsupported Media Type
{
"error": {
"type": "unsupported_media_type",
"message": "Unsupported file format '.exe'",
"code": "unsupported_format",
"details": [
"Supported formats: avi, docx, flac, html, jpeg, jpg, m4a, mkv, mov, mp3, mp4, ogg, pdf, png, pptx, txt, wav, webm, wmv, xlsx"
]
}
}Endpoints
Token Management
/tokens/currentGet information about the current API token.
Response
{
"object": "token",
"id": 123,
"name": "Production API Token",
"token_prefix": "maid_zzFC7on8",
"allowed_prompts": ["prompt_1", "prompt_2"],
"monthly_limit": 1000.0,
"credits_used": 150.5,
"credits_remaining": 849.5,
"total_requests": 1234,
"expires_at": 1704067200000,
"created_at": 1640995200000
}Example
import requests
response = requests.get(
"https://api.maidepot.com/api/v1/tokens/current",
headers={"Authorization": "Bearer maid_..."}
)
print(response.json())Prompts
/promptsList all prompts available to the current token.
Response
{
"object": "list",
"data": [
{
"id": "KXJmXkjeUnh2ziK1JREA",
"name": "Image Generator",
"ai_model": "imagen-3-fast-generate",
"description": "Generate images from text descriptions"
},
{
"id": "dwFRshByvRrRhZD8xura",
"name": "Photo Mashup",
"ai_model": "vertex_ai",
"description": "Combine multiple images"
}
],
"has_more": false
}Note: When an empty array is returned, it means the token has permission to execute any prompt.
Example
import requests
response = requests.get(
"https://api.maidepot.com/api/v1/prompts",
headers={"Authorization": "Bearer maid_..."}
)
prompts = response.json()["data"]
print(prompts)/prompts/{prompt_id}Get detailed information about a specific prompt including input fields.
Request Parameters: prompt_id (string, required): The ID of the prompt
Response
{
"object": "prompt",
"id": "KXJmXkjeUnh2ziK1JREA",
"name": "Image Generator",
"ai_model": "imagen-3-fast-generate",
"description": "Generate images from text descriptions",
"input_fields": [
{
"id": "THING",
"label": "What to generate"
}
]
}Example
prompt_id = "KXJmXkjeUnh2ziK1JREA"
response = client.get(f"https://api.maidepot.com/api/v1/prompts/{prompt_id}")
prompt = response.json()
print(f"Prompt: {prompt['name']}")
print(f"Model: {prompt['ai_model']}")
print("Input fields:")
for field in prompt['input_fields']:
print(f" - {field['label']} (ID: {field['id']})")/prompts/{prompt_id}/runExecute a prompt with the provided inputs.
Request Parameters: prompt_id (string, required): The ID of the prompt to execute
Request Body
{
"inputs": {
"field_id": "value"
},
"webhook_url": "https://your-domain.com/webhook"
}Input Value Types:
1. Simple text input:
{
"inputs": {
"THING": "a beautiful sunset"
}
}2. File input (images, documents, audio, video):
{
"inputs": {
"DOCUMENT": {
"file_url": "gs://bucket/path/file.pdf",
"content_type": "application/pdf",
"ocr_mode": "normal"
}
}
}Response (201 Created)
{
"object": "execution",
"id": "tx_abc123def456",
"status": "in_progress",
"created_at": 1644567890123
}Example: Simple Text Input
import requests
response = requests.post(
"https://api.maidepot.com/api/v1/prompts/KXJmXkjeUnh2ziK1JREA/run",
headers={"Authorization": "Bearer maid_..."},
json={"inputs": {"THING": "a beautiful sunset"}}
)
transaction_id = response.json()["id"]
print(f"Transaction ID: {transaction_id}")Transactions
/transactionsList all transactions with cursor-based pagination.
Query Parameters
| Name | Type | Required | Description |
|---|---|---|---|
limit | integer | Optional | Number of results per page (1-100, default: 20) |
after | string | Optional | Transaction ID to start after (for next page) |
before | string | Optional | Transaction ID to start before (for previous page) |
order | string | Optional | Sort order: "asc" or "desc" (default: "desc") |
status | string | Optional | Filter by status: "in_progress", "done", or "failed" |
prompt_id | string | Optional | Filter by prompt ID |
Important: You cannot use both 'after' and 'before' parameters in the same request.
Response
{
"object": "list",
"data": [
{
"id": "tx_abc123",
"status": "done",
"prompt_id": "KXJmXkjeUnh2ziK1JREA",
"prompt_name": "Image Generator",
"ai_model": "imagen-3-fast-generate",
"created_at": 1644567890123,
"updated_at": 1644567895456
}
],
"first_id": "tx_abc123",
"last_id": "tx_xyz789",
"has_more": true
}/transactions/{transaction_id}Get the status and result of a specific transaction.
Request Parameters: transaction_id (string, required): The ID of the transaction
Response (In Progress)
{
"object": "transaction",
"id": "tx_abc123",
"status": "in_progress",
"prompt_id": "KXJmXkjeUnh2ziK1JREA",
"prompt_name": "Image Generator",
"ai_model": "imagen-3-fast-generate",
"created_at": 1644567890123,
"updated_at": 1644567890123,
"result": null,
"error": null
}Response (Completed - Text)
{
"object": "transaction",
"id": "tx_abc123",
"status": "done",
"prompt_id": "KXJmXkjeUnh2ziK1JREA",
"prompt_name": "Text Generator",
"ai_model": "gpt-4",
"created_at": 1644567890123,
"updated_at": 1644567895456,
"result": {
"type": "text",
"content": "Generated text result...",
"content_preview": "First 1000 characters...",
"content_url": "https://storage.googleapis.com/...",
"image_url": null,
"image_format": null,
"size_bytes": 12345,
"truncated": false
},
"credits_used": 0.15,
"tokens_used": 1234,
"execution_time_ms": 4500,
"error": null
}Response (Completed - Image)
{
"object": "transaction",
"id": "tx_abc123",
"status": "done",
"prompt_id": "KXJmXkjeUnh2ziK1JREA",
"prompt_name": "Image Generator",
"ai_model": "imagen-3-fast-generate",
"created_at": 1644567890123,
"updated_at": 1644567895456,
"result": {
"type": "image",
"content": null,
"content_preview": null,
"content_url": null,
"image_url": "https://storage.googleapis.com/signed-url-to-image.png",
"image_format": "png",
"size_bytes": 54321,
"truncated": false
},
"credits_used": 0.25,
"tokens_used": null,
"execution_time_ms": 3200,
"error": null
}Response (Failed)
{
"object": "transaction",
"id": "tx_abc123",
"status": "failed",
"prompt_id": "KXJmXkjeUnh2ziK1JREA",
"prompt_name": "Image Generator",
"ai_model": "imagen-3-fast-generate",
"created_at": 1644567890123,
"updated_at": 1644567950123,
"result": null,
"error": {
"type": "execution_error",
"message": "Model timeout after 60 seconds",
"code": "model_timeout"
},
"credits_used": 0.0,
"tokens_used": null,
"execution_time_ms": 60000
}Example: Poll Transaction Until Complete
import time
def poll_transaction(transaction_id, max_wait=300, interval=5):
"""Poll transaction until done or failed"""
start = time.time()
while time.time() - start < max_wait:
response = client.get(
f"https://api.maidepot.com/api/v1/transactions/{transaction_id}"
)
if response.status_code == 200:
data = response.json()
status = data["status"]
print(f"[{int(time.time() - start)}s] status={status}")
if status == "done":
print(f"✓ DONE | credits={data['credits_used']}")
return data
elif status == "failed":
print(f"✗ FAILED | error={data['error']}")
return data
time.sleep(interval)
return None
result = poll_transaction("tx_abc123")/transactions/{transaction_id}/retryRetry a failed transaction using the same inputs and configuration.
Request Parameters: transaction_id (string, required): The ID of the failed transaction to retry
Response
{
"object": "execution",
"id": "tx_abc123",
"status": "in_progress",
"created_at": 1644567900000
}How it works:
- Retrieves stored input values from the original transaction
- Re-executes the prompt with the same processed inputs (no file re-processing)
- Increments the retry_count for tracking
- Returns the same transaction_id (not a new one)
- Can only retry transactions with status 'failed'
Restrictions:
- Can only retry transactions with status "failed"
- Cannot retry "in_progress" or "done" transactions
- Requires sufficient credits
/transactions/{transaction_id}Soft delete a transaction (only works for "done" or "failed" transactions).
Request Parameters: transaction_id (string, required): The ID of the transaction to delete
Response
{
"object": "transaction.deleted",
"id": "tx_abc123",
"deleted_at": 1644567900000
}File Upload
/files/uploadUpload a file to Firebase Storage for use in prompt inputs.
Request:
- Method: POST
- Content-Type: multipart/form-data
- Body Parameter:
file(file, Required) - The file to upload
Example
curl -X POST "https://api.maidepot.com/api/v1/files/upload" \
-H "Authorization: Bearer maid_..." \
-F "file=@document.pdf"Response (201 Created)
{
"object": "file",
"id": "abc123def456",
"gs_path": "gs://bucket/IO-users/acc_456/api-input-files/abc123def456.pdf",
"filename": "document.pdf",
"content_type": "application/pdf",
"size_bytes": 1048576
}File Limits
- Max size: 100 MB
- Audio/Video duration:
- Basic/Standard plans: Max 1 hour
- Premium+ plans: Max 5 hours
Supported Formats
- Documents: PDF, DOCX, PPTX, XLSX, TXT, HTML, MD
- Images: JPEG, PNG, JPG, GIF, WEBP, BMP
- Audio: MP3, WAV, FLAC, OGG, M4A
- Video: MP4, WEBM, MKV, AVI, MOV, WMV, FLV
Working with Files
Upload Flow
- Upload your file using POST /files/upload
- Receive gs_path in the response
- Use the gs_path in your prompt execution inputs
File Processing Options
When using files in prompts, you can control how documents are processed:
| Mode | Speed | Best For |
|---|---|---|
normal | Fast | Simple documents with clean text |
advanced | Slower | Complex layouts, tables, multi-column documents |
Example
{
"inputs": {
"DOCUMENT": {
"file_url": "gs://bucket/path/document.pdf",
"content_type": "application/pdf",
"ocr_mode": "advanced"
}
}
}Common Workflows
Workflow 1: Execute Simple Text Prompt
API_TOKEN="maid_..."
BASE_URL="https://api.maidepot.com/api/v1"
# 1. Execute prompt
RESPONSE=$(curl -X POST "$BASE_URL/prompts/KXJmXkjeUnh2ziK1JREA/run" \
-H "Authorization: Bearer $API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"inputs": {"THING": "a beautiful sunset"}}')
TRANSACTION_ID=$(echo $RESPONSE | jq -r '.id')
# 2. Poll for result
while true; do
STATUS_RESPONSE=$(curl -s "$BASE_URL/transactions/$TRANSACTION_ID" \
-H "Authorization: Bearer $API_TOKEN")
STATUS=$(echo $STATUS_RESPONSE | jq -r '.status')
if [ "$STATUS" = "done" ]; then
echo "Result: $(echo $STATUS_RESPONSE | jq '.result')"
break
elif [ "$STATUS" = "failed" ]; then
echo "Error: $(echo $STATUS_RESPONSE | jq '.error')"
break
fi
sleep 5
doneWorkflow 2: Upload File and Execute Prompt
API_TOKEN="maid_..."
BASE_URL="https://api.maidepot.com/api/v1"
PROMPT_ID="3l5gXVtFs4LS0eqk2Bmn"
# 1. Upload file
UPLOAD_RESPONSE=$(curl -X POST "$BASE_URL/files/upload" \
-H "Authorization: Bearer $API_TOKEN" \
-F "file=@document.pdf")
GS_PATH=$(echo $UPLOAD_RESPONSE | jq -r '.gs_path')
# 2. Execute prompt with file
EXEC_PAYLOAD=$(jq -n \
--arg gs_path "$GS_PATH" \
'{inputs: {DOCUMENT: {file_url: $gs_path, content_type: "application/pdf", ocr_mode: "advanced"}, LANGUAGE: "Spanish"}}')
RESPONSE=$(curl -X POST "$BASE_URL/prompts/$PROMPT_ID/run" \
-H "Authorization: Bearer $API_TOKEN" \
-H "Content-Type: application/json" \
-d "$EXEC_PAYLOAD")
TRANSACTION_ID=$(echo $RESPONSE | jq -r '.id')
# 3. Poll for result
while true; do
STATUS_RESPONSE=$(curl -s "$BASE_URL/transactions/$TRANSACTION_ID" \
-H "Authorization: Bearer $API_TOKEN")
STATUS=$(echo $STATUS_RESPONSE | jq -r '.status')
if [ "$STATUS" = "done" ]; then
echo "Result: $(echo $STATUS_RESPONSE | jq '.result')"
break
elif [ "$STATUS" = "failed" ]; then
echo "Error: $(echo $STATUS_RESPONSE | jq '.error')"
break
fi
sleep 5
doneWorkflow 3: Using Webhooks
API_TOKEN="maid_..."
BASE_URL="https://api.maidepot.com/api/v1"
PROMPT_ID="KXJmXkjeUnh2ziK1JREA"
# 1. Execute with webhook
curl -X POST "$BASE_URL/prompts/$PROMPT_ID/run" \
-H "Authorization: Bearer $API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"inputs": {"THING": "a sunset"}, "webhook_url": "https://your-domain.com/webhook"}'
# 2. Your webhook endpoint receives POST when done
# No polling needed - webhook is called automaticallyWorkflow 4: List and Retry Failed Transactions
API_TOKEN="maid_..."
BASE_URL="https://api.maidepot.com/api/v1"
# 1. Get failed transactions
FAILED_RESPONSE=$(curl -s "$BASE_URL/transactions?status=failed&limit=10" \
-H "Authorization: Bearer $API_TOKEN")
FAILED_TXS=$(echo $FAILED_RESPONSE | jq -r '.data[]')
# 2. Retry each failed transaction
echo "$FAILED_TXS" | jq -c '.' 2>/dev/null | while read -r tx; do
TX_ID=$(echo $tx | jq -r '.id')
echo "Retrying $TX_ID"
curl -X POST "$BASE_URL/transactions/$TX_ID/retry" \
-H "Authorization: Bearer $API_TOKEN"
sleep 10
STATUS_RESPONSE=$(curl -s "$BASE_URL/transactions/$TX_ID" \
-H "Authorization: Bearer $API_TOKEN")
echo " Status: $(echo $STATUS_RESPONSE | jq -r '.status')"
doneWorkflow 5: Pagination Through Transaction History
API_TOKEN="maid_..."
BASE_URL="https://api.maidepot.com/api/v1"
fetch_all_transactions() {
local status=$1
all_transactions="[]"
after=""
while true; do
if [ -n "$after" ]; then
url="$BASE_URL/transactions?limit=100&order=desc&after=$after"
else
url="$BASE_URL/transactions?limit=100&order=desc"
fi
[ -n "$status" ] && url="$url&status=$status"
response=$(curl -s "$url" -H "Authorization: Bearer $API_TOKEN")
data=$(echo $response | jq -c '.')
all_transactions=$(echo $all_transactions | jq -s "add + ($data.data // [])")
has_more=$(echo $response | jq -r '.has_more')
if [ "$has_more" != "true" ]; then
break
fi
after=$(echo $response | jq -r '.last_id')
done
echo $all_transactions
}
DONE_TXS=$(fetch_all_transactions "done")
echo "Total done transactions: $(echo $DONE_TXS | jq 'length')"Webhooks
Webhooks provide real-time notifications when transactions complete. Specify a webhook_url when executing a prompt.
Requirements
- Must use HTTPS protocol
- Cannot point to localhost or private networks
- Endpoint must respond with 2xx status code
Webhook Headers
X-Webhook-Event: transaction.completed
X-Transaction-Id: tx_abc123
Content-Type: application/jsonWebhook Payload (Success)
{
"object": "transaction",
"event": "transaction.completed",
"id": "tx_abc123",
"status": "done",
"prompt_id": "KXJmXkjeUnh2ziK1JREA",
"prompt_name": "Image Generator",
"ai_model": "imagen-3-fast-generate",
"result": {
"type": "text",
"content": "Full content here...",
"content_preview": "First 1000 chars...",
"content_url": "https://storage.googleapis.com/...",
"image_url": null,
"image_format": null,
"size_bytes": 12345,
"truncated": false
},
"credits_used": 0.15,
"tokens_used": 1234,
"execution_time_ms": 4500,
"error": null,
"created_at": 1644567890123,
"updated_at": 1644567895456
}Webhook Payload (Failed)
{
"object": "transaction",
"event": "transaction.completed",
"id": "tx_abc123",
"status": "failed",
"prompt_id": "KXJmXkjeUnh2ziK1JREA",
"prompt_name": "Image Generator",
"ai_model": "imagen-3-fast-generate",
"result": null,
"error": {
"type": "execution_error",
"message": "Model timeout",
"code": "model_timeout"
},
"credits_used": 0.0,
"tokens_used": null,
"execution_time_ms": 60000,
"created_at": 1644567890123,
"updated_at": 1644567950123
}Example Webhook Endpoint (Flask)
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route('/webhook', methods=['POST'])
def webhook():
event = request.headers.get('X-Webhook-Event')
transaction_id = request.headers.get('X-Transaction-Id')
payload = request.json
if event == 'transaction.completed':
status = payload['status']
if status == 'done':
result = payload['result']
print(f"✓ Transaction {transaction_id} completed")
print(f" Result type: {result['type']}")
print(f" Credits used: {payload['credits_used']}")
elif status == 'failed':
error = payload['error']
print(f"✗ Transaction {transaction_id} failed")
print(f" Error: {error['message']}")
return jsonify({"received": True}), 200