개요

MAIDEPOT Public API를 사용하면 API 토큰을 사용하여 프로그래밍 방식으로 AI 프롬프트(앱, 이미지 생성, 매쉬업)를 실행할 수 있습니다. 모든 실행은 비동기적으로 실행되며 트랜잭션 엔드포인트를 통해 진행 상황을 추적하거나 웹훅을 통해 알림을 받을 수 있습니다.

주요 기능

  • 모든 프롬프트 유형 실행 (앱, 이미지, 매쉬업)
  • 상태 추적이 가능한 비동기 실행
  • 문서, 이미지, 오디오 및 비디오 파일 업로드 지원
  • 완료된 실행에 대한 웹훅 알림
  • 트랜잭션 기록에 대한 커서 기반 페이지네이션
  • 실패한 트랜잭션 재시도
  • 크레딧 사용량 추적

요구사항

  • API 액세스에는 유료 플랜(Pro, Business 또는 Enterprise)이 필요합니다
  • 적절한 권한이 있는 유효한 API 토큰

인증

모든 API 요청은 헤더에 Bearer 토큰을 사용한 인증이 필요합니다. Authorization

bash
Authorization: Bearer YOUR_API_TOKEN

프로필에서 API 토큰을 생성하고 관리할 수 있습니다. API 토큰 관리

예제

bash
curl https://api.maidepot.com/api/v1/prompts \
  -H "Authorization: Bearer maid_zzFC7on8-HxX_n-4PvAuTj_8OFvJYdYA3AzI4E57nSQVo2w9M6tF3aTtKp4VJ-bz"

속도 제한

속도 제한은 계정당 적용되며 엔드포인트 유형에 따라 다릅니다:

  • 실행 엔드포인트: 분당 120개 요청
  • 메타데이터 읽기 엔드포인트: 분당 300개 요청
  • 폴링 엔드포인트: 분당 600개 요청
  • 관리 작업: 분당 180개 요청
  • 파일 업로드: 분당 60개 요청

속도 제한 헤더

모든 응답에는 헤더에 속도 제한 정보가 포함됩니다:

http
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 119
X-RateLimit-Reset: 1612345678

속도 제한 초과 응답 (429)

json
{
  "error": {
    "type": "rate_limit_error",
    "message": "Rate limit exceeded",
    "code": "rate_limit_exceeded"
  }
}

오류 처리

모든 API 오류는 RFC 7807 Problem Details 패턴을 기반으로 한 표준화된 구조를 따릅니다.

오류 응답 구조

json
{
  "error": {
    "type": "validation_error",
    "message": "Human-readable error message",
    "code": "invalid_request",
    "param": "inputs",
    "details": ["Additional context"]
  }
}

HTTP 상태 코드

상태 코드오류 유형설명
400validation_errorInvalid request data or missing required fields
401authentication_errorInvalid or missing API token
402insufficient_creditsNot enough credits to complete operation
403permission_errorToken doesn't have permission for this resource
404not_foundResource not found (prompt, transaction, etc.)
415unsupported_media_typeUnsupported file format
429rate_limit_errorRate limit exceeded (requests per minute)
500internal_errorInternal server error

Note: 402 Insufficient Credits는 계정의 크레딧 할당량이 소진되었을 때 사용되며, 429 Rate Limit는 분당 요청 제한을 초과했을 때 사용됩니다. 둘 다 다른 처리 전략이 필요합니다 (크레딧 추가 vs. 백오프 구현).

오류 예제

400 - 유효성 검사 오류

json
{
  "error": {
    "type": "validation_error",
    "message": "Missing required input field: THING",
    "code": "invalid_request",
    "param": "inputs"
  }
}

401 - 인증 오류

json
{
  "error": {
    "type": "authentication_error",
    "message": "Invalid or missing authentication credentials",
    "code": "invalid_token"
  }
}

402 - 크레딧 부족

json
{
  "error": {
    "type": "insufficient_credits",
    "message": "Insufficient credits to complete this operation",
    "code": "insufficient_credits"
  }
}

403 - 권한 오류

json
{
  "error": {
    "type": "permission_error",
    "message": "This token is not authorized to execute this prompt",
    "code": "prompt_not_allowed"
  }
}

415 - 지원되지 않는 미디어 유형

json
{
  "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"
    ]
  }
}

엔드포인트

토큰 관리

GET/tokens/current

현재 API 토큰에 대한 정보를 가져옵니다.

응답

json
{
  "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
}

예제

python
import requests

response = requests.get(
    "https://api.maidepot.com/api/v1/tokens/current",
    headers={"Authorization": "Bearer maid_..."}
)

print(response.json())

프롬프트

GET/prompts

현재 토큰에서 사용 가능한 모든 프롬프트를 나열합니다.

응답

json
{
  "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: 빈 배열이 반환되면 해당 토큰이 모든 프롬프트를 실행할 수 있는 권한이 있음을 의미합니다.

예제

python
import requests

response = requests.get(
    "https://api.maidepot.com/api/v1/prompts",
    headers={"Authorization": "Bearer maid_..."}
)

prompts = response.json()["data"]
print(prompts)
GET/prompts/{prompt_id}

입력 필드를 포함한 특정 프롬프트에 대한 자세한 정보를 가져옵니다.

요청 매개변수: prompt_id (string, required): The ID of the prompt

응답

json
{
  "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"
    }
  ]
}

예제

python
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']})")
POST/prompts/{prompt_id}/run

제공된 입력으로 프롬프트를 실행합니다.

요청 매개변수: prompt_id (string, required): The ID of the prompt to execute

요청 본문

json
{
  "inputs": {
    "field_id": "value"
  },
  "webhook_url": "https://your-domain.com/webhook"
}

입력 값 유형:

1. 간단한 텍스트 입력:

json
{
  "inputs": {
    "THING": "a beautiful sunset"
  }
}

2. 파일 입력 (이미지, 문서, 오디오, 비디오):

json
{
  "inputs": {
    "DOCUMENT": {
      "file_url": "gs://bucket/path/file.pdf",
      "content_type": "application/pdf",
      "ocr_mode": "normal"
    }
  }
}

응답 (201 Created)

json
{
  "object": "execution",
  "id": "tx_abc123def456",
  "status": "in_progress",
  "created_at": 1644567890123
}

예제: Simple Text Input

python
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}")

트랜잭션

GET/transactions

커서 기반 페이지네이션으로 모든 트랜잭션을 나열합니다.

쿼리 매개변수

이름타입필수설명
limitinteger선택사항Number of results per page (1-100, default: 20)
afterstring선택사항Transaction ID to start after (for next page)
beforestring선택사항Transaction ID to start before (for previous page)
orderstring선택사항Sort order: "asc" or "desc" (default: "desc")
statusstring선택사항Filter by status: "in_progress", "done", or "failed"
prompt_idstring선택사항Filter by prompt ID

Important: 동일한 요청에서 'after'와 'before' 매개변수를 함께 사용할 수 없습니다.

응답

json
{
  "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
}
GET/transactions/{transaction_id}

특정 트랜잭션의 상태와 결과를 가져옵니다.

요청 매개변수: transaction_id (string, required): The ID of the transaction

응답 (진행 중)

json
{
  "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
}

응답 (완료 - 텍스트)

json
{
  "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
}

응답 (완료 - 이미지)

json
{
  "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)

json
{
  "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
}

예제: Poll Transaction Until Complete

python
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")
POST/transactions/{transaction_id}/retry

동일한 입력과 구성을 사용하여 실패한 트랜잭션을 재시도합니다.

요청 매개변수: transaction_id (string, required): The ID of the failed transaction to retry

응답

json
{
  "object": "execution",
  "id": "tx_abc123",
  "status": "in_progress",
  "created_at": 1644567900000
}

작동 방식:

  • 원래 트랜잭션에서 저장된 입력 값을 검색합니다
  • 동일한 처리된 입력으로 프롬프트를 다시 실행합니다 (파일 재처리 없음)
  • 추적을 위해 retry_count를 증가시킵니다
  • 동일한 transaction_id를 반환합니다 (새 ID가 아님)
  • 상태가 'failed'인 트랜잭션만 재시도할 수 있습니다

제한사항:

  • 상태가 "failed"인 트랜잭션만 재시도 가능
  • "in_progress", "done" 트랜잭션은 재시도 불가
  • 충분한 크레딧 필요
DELETE/transactions/{transaction_id}

'done' 또는 'failed' 트랜잭션에서만 작동하는 소프트 삭제입니다.

요청 매개변수: transaction_id (string, required): The ID of the transaction to delete

응답

json
{
  "object": "transaction.deleted",
  "id": "tx_abc123",
  "deleted_at": 1644567900000
}

파일 업로드

POST/files/upload

프롬프트 입력에 사용할 파일을 Firebase Storage에 업로드합니다.

요청:

  • 메서드: POST
  • Content-Type: multipart/form-data
  • 본문 매개변수: file (file, 필수) - 업로드할 파일

예제

bash
curl -X POST "https://api.maidepot.com/api/v1/files/upload" \
  -H "Authorization: Bearer maid_..." \
  -F "file=@document.pdf"

응답 (201 Created)

json
{
  "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
}
파일 제한
  • 최대 크기: 100 MB
  • 오디오/비디오 길이:
    • Basic/Standard plans: Max 1 hour
    • Premium+ plans: Max 5 hours
지원되는 형식
  • 문서: PDF, DOCX, PPTX, XLSX, TXT, HTML, MD
  • 이미지: JPEG, PNG, JPG, GIF, WEBP, BMP
  • 오디오: MP3, WAV, FLAC, OGG, M4A
  • 비디오: MP4, WEBM, MKV, AVI, MOV, WMV, FLV

파일 작업

업로드 흐름

  1. POST /files/upload를 사용하여 파일 업로드
  2. 응답에서 gs_path 받기
  3. 프롬프트 실행 입력에 gs_path 사용

파일 처리 옵션

프롬프트에서 파일을 사용할 때 문서 처리 방법을 제어할 수 있습니다:

모드속도적합한 용도
normal빠름깔끔한 텍스트가 있는 간단한 문서
advanced느림복잡한 레이아웃, 표, 다단 문서

예제

json
{
  "inputs": {
    "DOCUMENT": {
      "file_url": "gs://bucket/path/document.pdf",
      "content_type": "application/pdf",
      "ocr_mode": "advanced"
    }
  }
}

일반적인 워크플로우

워크플로우 1: 간단한 텍스트 프롬프트 실행

bash
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
done

워크플로우 2: 파일 업로드 및 프롬프트 실행

bash
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
done

워크플로우 3: 웹훅 사용

bash
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 automatically

워크플로우 4: 실패한 트랜잭션 나열 및 재시도

bash
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')"
done

워크플로우 5: 트랜잭션 기록 페이지네이션

bash
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')"

웹훅

웹훅은 트랜잭션이 완료되면 실시간 알림을 제공합니다. 프롬프트 실행 시 webhook_url을 지정하세요.

요구사항

  • HTTPS 프로토콜을 사용해야 합니다
  • localhost 또는 사설 네트워크를 가리킬 수 없습니다
  • 엔드포인트는 2xx 상태 코드로 응답해야 합니다

웹훅 헤더

http
X-Webhook-Event: transaction.completed
X-Transaction-Id: tx_abc123
Content-Type: application/json

웹훅 페이로드 (성공)

json
{
  "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
}

웹훅 페이로드 (실패)

json
{
  "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
}

웹훅 엔드포인트 예제 (Flask)

python
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