Introduction

Welcome to the BeamGo API documentation. Our API allows you to integrate powerful AI video generation features directly into your applications.

Core Concepts

Before you begin, it's important to understand a few core concepts about the API's design:

  • Asynchronous Nature: Video generation can take time. Our API is asynchronous. When you submit a request, we immediately return a job_id. You then use this ID to check the job's status until it's complete.
  • Workflows: A "workflow" defines a type of task you can perform, such as text_to_video. Each workflow has its own parameters and credit cost.
  • Jobs: A "job" represents a single, specific task you've requested, like generating a video from a particular prompt.
  • Webhooks: Instead of constantly checking a job's status (polling), we highly recommend using webhooks to receive a notification on your server as soon as a job is finished.
API Base URL: https://api.yourdomain.com
Try it Live! For a hands-on experience, you can explore and test our API endpoints interactively in our Swagger UI playground.

Authentication

All API requests must be authenticated. The API uses API Keys to identify your account.

To authenticate, include your API Key in the X-API-Key header of every request.

X-API-Key: ndfy_your_secret_api_key_here

You can generate and manage your API Keys from the "API" section of your dashboard.

Important: Treat your API Keys like passwords. Never expose them in client-side code (like a web browser's JavaScript) and do not share them publicly.

Workflows

Workflows are the main entry points for creating content. The first step is usually to see which workflows are available.

GET /workflows

List Available Workflows

Retrieves a list of all available workflows, their descriptions, and their cost in credits.

Example Request

cURL
Python
curl "https://api.yourdomain.com/workflows"   -H "X-API-Key: ndfy_your_api_key_here"
import requests
API_KEY = "ndfy_your_api_key_here"
API_URL = "https://api.yourdomain.com/workflows"

response = requests.get(API_URL, headers={"X-API-Key": API_KEY})

if response.ok:
    print(response.json())
else:
    print(f"Error: {response.status_code} - {response.text}")

Example Response

200OK
{
  "workflows": [
    {
      "id": "text_to_video",
      "description": "Generate a video from a text prompt and aspect ratio.",
      "cost": 25
    },
    {
      "id": "image_to_video",
      "description": "Animate an image, optionally guided by a text prompt.",
      "cost": 30
    }
  ]
}
POST /workflows/text-to-video/run

Run Text-to-Video Workflow

Submits a job to generate a video from a text prompt. The order of fields in the JSON body does not matter.

Request Body (application/json)

FieldTypeRequiredDescription
promptstringYesDetailed description of the video content. Max 1000 characters.
aspect_ratiostringYesAspect ratio. Allowed: "1:1", "landscape (16:9)", "portrait (9:16)".
seedintegerNoA number for reproducibility. Default: 0 (which means random).

Example Request

cURL
Python
Node.js
curl -X POST "https://api.yourdomain.com/workflows/text-to-video/run"   -H "Content-Type: application/json"   -H "X-API-Key: ndfy_your_api_key_here"   -d '{
    "prompt": "A majestic eagle soaring through clouds",
    "aspect_ratio": "landscape (16:9)",
    "seed": 42
  }'
import requests
API_KEY = "ndfy_your_api_key_here"
API_URL = "https://api.yourdomain.com/workflows/text-to-video/run"

payload = {
    "prompt": "A majestic eagle soaring through clouds",
    "aspect_ratio": "landscape (16:9)",
    "seed": 42
}
response = requests.post(API_URL, headers={"X-API-Key": API_KEY}, json=payload)
# On success (202), response.json() will be:
# {"job_id": "...", "message": "..."}
print(response.status_code, response.json())
// Using node-fetch: npm install node-fetch
import fetch from 'node-fetch';

const payload = {
    prompt: "A majestic eagle soaring through clouds",
    aspect_ratio: "landscape (16:9)",
    seed: 42
};
const response = await fetch("...", {
    method: 'POST',
    headers: { 'X-API-Key': '...', 'Content-Type': 'application/json' },
    body: JSON.stringify(payload)
});
const data = await response.json();
console.log(response.status, data);

Example Response

202Accepted
{
  "job_id": "123e4567-e89b-12d3-a456-426614174000",
  "message": "Text-to-Video job accepted."
}
POST /workflows/image-to-video/run

Run Image-to-Video Workflow

Submits a job to animate an image. This endpoint uses multipart/form-data.

Request Body (multipart/form-data)

FieldTypeRequiredDescription
input_imagefileYesImage file to animate (PNG, JPG, WEBP). Max size: 1MB.
promptstringNoOptional text prompt to guide the animation.
seedintegerNoA number for reproducibility. Default: 0 (which means random).

Example Request

cURL
Python
Node.js
curl -X POST "https://api.yourdomain.com/workflows/image-to-video/run"   -H "X-API-Key: ndfy_your_api_key_here"   -F "input_image=@path/to/my_image.png"   -F "prompt=make the character's eyes glow"   -F "seed=12345"
import requests
API_KEY = "ndfy_your_api_key_here"
API_URL = "https://api.yourdomain.com/workflows/image-to-video/run"

data = {
    "prompt": "make the character's eyes glow",
    "seed": 12345
}
with open("my_image.png", "rb") as image_file:
    files = {"input_image": image_file}
    response = requests.post(API_URL, headers={"X-API-Key": API_KEY}, data=data, files=files)

print(response.status_code, response.json())
// Using 'form-data': npm install form-data
import FormData from 'form-data';
import fs from 'fs';
import fetch from 'node-fetch';

const form = new FormData();
form.append('input_image', fs.createReadStream('./my_image.png'));
form.append('prompt', "make the character's eyes glow");
form.append('seed', 12345);

const response = await fetch("...", {
    method: 'POST',
    headers: { 'X-API-Key': '...' }, // Content-Type is set automatically
    body: form
});
const data = await response.json();
console.log(response.status, data);

Example Response

202Accepted
{
  "job_id": "3e456712-e89b-12d3-a456-426614174001",
  "message": "Image-to-Video job accepted."
}

Jobs

Endpoints for managing and retrieving information about your generation jobs.

GET /jobs/{id}/status

Get Job Status

Retrieves the current status, progress, and result of a specific job.

Path Parameters

ParameterTypeDescription
idUUIDThe unique identifier of the job.

Example Request

cURL
Python
curl "https://api.yourdomain.com/jobs/123e4567-e89b-12d3-a456-426614174000/status"   -H "X-API-Key: ndfy_your_api_key_here"
import requests
API_KEY = "ndfy_your_api_key_here"
JOB_ID = "123e4567-e89b-12d3-a456-426614174000"
API_URL = f"https://api.yourdomain.com/jobs/{JOB_ID}/status"

response = requests.get(API_URL, headers={"X-API-Key": API_KEY})
print(response.json())

Response Body

The response contains the full job object. When status is COMPLETED, result_video_url will contain a temporary, pre-signed URL to the output file.

{
  "id": "123e4567-e89b-12d3-a456-426614174000",
  "status": "COMPLETED",
  "progress": 100,
  "result_video_url": "https://s3.your-region.amazonaws.com/...",
  "error_message": null,
  "credits_cost": 25,
  "credits_deducted": true,
  "created_at": "2024-05-21T10:30:00Z",
  "updated_at": "2024-05-21T10:35:00Z",
  "source": "api_key",
  "engine_workflow": "text_to_video",
  "parameters": { "prompt": "...", "aspect_ratio": "..." }
}

Possible Status Values

  • PENDING: Job is in the queue, waiting to be processed.
  • PROCESSING: Job is actively being processed by a worker.
  • COMPLETED: Job finished successfully. The result is available.
  • FAILED: Job failed. Check the error_message field for details.
GET /jobs/{id}/download

Get Download URL

Retrieves only the download URL for a completed job. This is a lightweight alternative to the full status endpoint if you only need the result URL.

Example Request

cURL
Python
curl "https://api.yourdomain.com/jobs/123e4567-e89b-12d3-a456-426614174000/download"   -H "X-API-Key: ndfy_your_api_key_here"
import requests
API_KEY = "ndfy_your_api_key_here"
JOB_ID = "123e4567-e89b-12d3-a456-426614174000"
API_URL = f"https://api.yourdomain.com/jobs/{JOB_ID}/download"

response = requests.get(API_URL, headers={"X-API-Key": API_KEY})
print(response.json())

Responses

200OK
{
  "download_url": "https://s3.your-region.amazonaws.com/..."
}
400Bad Request
{
  "detail": "Video not ready. Current status: PROCESSING"
}
GET /jobs

List Jobs

Returns a paginated list of your most recent jobs.

Query Parameters

ParameterTypeDefaultDescription
limitinteger10Number of jobs to return (1-50).
offsetinteger0Number of jobs to skip for pagination.

Example Request

cURL
Python
# Gets jobs 11 through 20
curl "https://api.yourdomain.com/jobs?limit=10&offset=10"   -H "X-API-Key: ndfy_your_api_key_here"
import requests
API_KEY = "ndfy_your_api_key_here"
API_URL = "https://api.yourdomain.com/jobs"

params = {"limit": 10, "offset": 10}
response = requests.get(API_URL, headers={"X-API-Key": API_KEY}, params=params)

# The total number of jobs is in the response headers
total_count = response.headers.get("X-Total-Count")

print(f"Total jobs: {total_count}")
print(response.json())

Response Headers

The response includes an X-Total-Count header indicating the total number of jobs for your account, which is useful for building pagination controls.

DELETE /jobs/{id}

Delete a Job

Deletes a job. This action is irreversible and will also delete the associated result file from storage. You can only delete jobs that are in a terminal state (COMPLETED, FAILED) or PENDING.

Note: You cannot delete a job that is currently PROCESSING.

Example Request

cURL
Python
# Use -i to see the status code in the response headers
curl -X DELETE -i "https://api.yourdomain.com/jobs/123e4567-e89b-12d3-a456-426614174000"   -H "X-API-Key: ndfy_your_api_key_here"
import requests
API_KEY = "ndfy_your_api_key_here"
JOB_ID = "123e4567-e89b-12d3-a456-426614174000"
API_URL = f"https://api.yourdomain.com/jobs/{JOB_ID}"

response = requests.delete(API_URL, headers={"X-API-Key": API_KEY})

if response.status_code == 204:
    print("Job deleted successfully.")
else:
    print(f"Error: {response.status_code} - {response.text}")

Response

A successful deletion returns a 204 No Content status code with no body.


Webhooks

Webhooks are the recommended way to get notified about job status changes. Instead of polling for status, you can provide a URL and we will send a POST request to it when an event occurs.

Webhook Events

You can subscribe to the following events:

  • job.completed: Triggered when a job finishes successfully.
  • job.failed: Triggered when a job fails.

Webhook Payload

All webhook requests are sent with a JSON body containing the following structure:

{
  "id": "whk_1684678800.12345",
  "event": "job.completed",
  "created": "2024-05-21T11:00:00Z",
  "data": {
    "job_id": "123e4567-e89b-12d3-a456-426614174000",
    "status": "COMPLETED",
    "workflow": "text_to_video",
    "created_at": "2024-05-21T10:55:00Z",
    "completed_at": "2024-05-21T11:00:00Z",
    "result_url": "https://s3.your-region.amazonaws.com/...",
    "error_message": null,
    "credits_cost": 25,
    "credits_deducted": true
  }
}

Verifying Signatures

To ensure that a webhook request genuinely came from us, we include a signature in the X-Webhook-Signature header. You should verify this signature using your webhook's secret token.

Your webhook's Secret Token is only shown to you once, when you create the webhook. Store it securely.
Python (FastAPI)
Node.js (Express)
import hmac
import hashlib
from fastapi import Request, HTTPException, Depends

WEBHOOK_SECRET = "whsec_your_secret_token_here"

async def verify_signature(request: Request):
    signature_header = request.headers.get("X-Webhook-Signature")
    if not signature_header:
        raise HTTPException(status_code=400, detail="Missing X-Webhook-Signature header")
    
    try: sig_type, signature = signature_header.split("=", 1)
    except ValueError: raise HTTPException(status_code=400, detail="Invalid signature format")
    if sig_type != "sha256": raise HTTPException(status_code=400, detail="Unsupported signature type")

    payload = await request.body()
    expected_signature = hmac.new(WEBHOOK_SECRET.encode(), payload, hashlib.sha256).hexdigest()

    if not hmac.compare_digest(expected_signature, signature):
        raise HTTPException(status_code=401, detail="Invalid signature")
    return True

# Usage: @app.post("/your-webhook-url", dependencies=[Depends(verify_signature)])
# async def handle_webhook(request: Request):
#     webhook_data = await request.json() ...
const crypto = require('crypto');
const express = require('express');

// Middleware to verify the signature
const verifySignature = (req, res, next) => {
    const signature = req.headers['x-webhook-signature'];
    if (!signature) return res.status(400).send('Missing signature');
    const [sigType, sig] = signature.split('=');
    if (sigType !== 'sha256') return res.status(400).send('Unsupported signature type');

    const WEBHOOK_SECRET = 'whsec_your_secret_token_here';
    const expectedSignature = crypto.createHmac('sha256', WEBHOOK_SECRET).update(req.body).digest('hex');

    if (!crypto.timingSafeEqual(Buffer.from(expectedSignature), Buffer.from(sig))) {
        return res.status(401).send('Invalid signature');
    }
    next();
};

const app = express();
// Use express.raw() to get the raw body, required for signature verification
app.post('/your-webhook-url', express.raw({ type: 'application/json' }), verifySignature, (req, res) => {
    const webhook_data = JSON.parse(req.body.toString());
    console.log('Received event:', webhook_data.event);
    res.status(200).send({ received: true });
});

Webhook Management Endpoints

POST/webhooks

Create Webhook

Creates a new webhook endpoint. A maximum of 10 webhooks are allowed per user.

Request Body
FieldTypeRequiredDescription
urlstring (URL)YesThe HTTPS URL to receive webhook events.
eventsarray[string]YesArray of events to subscribe to (e.g., ["job.completed", "job.failed"]).
descriptionstringNoAn optional description for your webhook.
Example Request
cURL
Python
curl -X POST "https://api.yourdomain.com/webhooks"   -H "X-API-Key: ndfy_your_api_key_here"   -H "Content-Type: application/json"   -d '{
    "url": "https://myapp.com/api/ai-video-webhook",
    "events": ["job.completed", "job.failed"],
    "description": "Production notifications"
  }'
import requests
payload = {
    "url": "https://myapp.com/api/ai-video-webhook",
    "events": ["job.completed", "job.failed"],
    "description": "Production notifications"
}
response = requests.post(
    "https://api.yourdomain.com/webhooks",
    headers={"X-API-Key": "..."},
    json=payload
)
print(response.json())
Example Response (Success)

The secret_token is only returned on creation. Save it immediately.

{
    "id": "e4a7a2a7-12d4-4f4c-83de-724f33a8b4a5",
    "url": "https://myapp.com/api/ai-video-webhook",
    "events": ["job.completed", "job.failed"],
    "description": "Production notifications",
    "is_active": true,
    "created_at": "2024-05-21T12:00:00Z",
    "secret_token": "whsec_..."
}
GET/webhooks

List Webhooks

Lists all of your currently configured webhooks. The secret token is not returned.

Example Request
cURL
Python
curl "https://api.yourdomain.com/webhooks" -H "X-API-Key: ..."
import requests
response = requests.get("https://api.yourdomain.com/webhooks", headers={"X-API-Key": "..."})
print(response.json())
DELETE/webhooks/{id}

Delete Webhook

Deletes the webhook configuration with the specified ID.

Example Request
cURL
Python
curl -X DELETE "https://api.yourdomain.com/webhooks/e4a7a2a7-12d4-4f4c-83de-724f33a8b4a5"   -H "X-API-Key: ..."
import requests
WEBHOOK_ID = "e4a7a2a7-12d4-4f4c-83de-724f33a8b4a5"
response = requests.delete(
    f"https://api.yourdomain.com/webhooks/{WEBHOOK_ID}",
    headers={"X-API-Key": "..."}
)
print(f"Status Code: {response.status_code}") # Expect 204 for success
POST/webhooks/{id}/test

Test Webhook

Sends a test job.completed event to the specified webhook URL. The request body must be empty.

Example Request
cURL
Python
curl -X POST "https://api.yourdomain.com/webhooks/e4a7a2a7-12d4-4f4c-83de-724f33a8b4a5/test"   -H "X-API-Key: ..."
import requests
WEBHOOK_ID = "e4a7a2a7-12d4-4f4c-83de-724f33a8b4a5"
response = requests.post(
    f"https://api.yourdomain.com/webhooks/{WEBHOOK_ID}/test",
    headers={"X-API-Key": "..."}
)
print(response.status_code, response.json())
Example Response
202Accepted
{
    "message": "Test webhook dispatch initiated. Check your endpoint for the payload.",
    "test_payload": {
        "job_id": "...", "status": "COMPLETED", ...
    }
}

Account

Endpoints related to your account information.

GET/users/me/profile

Get User Profile

Retrieves your full profile, including your current plan and credit balances. This is useful for programmatically checking your available credits.

Example Request

cURL
Python
curl "https://api.yourdomain.com/users/me/profile" -H "X-API-Key: ..."
import requests
response = requests.get("https://api.yourdomain.com/users/me/profile", headers={"X-API-Key": "..."})
print(response.json())

Response Body

{
  "id": "123e4567-e89b-12d3-a456-426614174000",
  "username": "api_user_1",
  "plan_id": "pro",
  "created_at": "2024-05-20T12:00:00Z",
  "monthly_credits_allowance": 10000,
  "monthly_credits_balance": 8500,
  "purchased_credits_balance": 500,
  "reserved_credits": 55,
  "current_period_end": "2024-06-20T12:00:00Z",
  "next_plan_id": null,
  "available_credits": 8945
}

Rate Limits

To ensure platform stability, we apply several types of rate limits. Exceeding these limits will result in a 429 Too Many Requests error.

Concurrent Jobs

This is the number of jobs you can have in PENDING or PROCESSING status at the same time.

PlanConcurrent Jobs
Free2
Basic4
Pro8

Temporal Limits

These limits control the number of jobs you can submit over a period of time.

PlanHourly LimitDaily Limit
Free1050
Basic100500
Pro5002500

Error Codes

The API uses standard HTTP status codes to indicate the success or failure of a request.

CodeStatusMeaning
200 OKSuccessThe request was successful.
202 AcceptedSuccessThe job was accepted for processing.
204 No ContentSuccessThe request was successful, and there is no content to return (e.g., after a DELETE).
400 Bad RequestClient ErrorThe request was malformed. Check your parameters, JSON body, or file uploads. This can also be triggered by our content moderation service.
401 UnauthorizedClient ErrorAuthentication failed. Check that your X-API-Key is correct and valid.
402 Payment RequiredClient ErrorYou do not have enough credits to perform this action.
404 Not FoundClient ErrorThe requested resource (e.g., a job) could not be found.
413 Payload Too LargeClient ErrorThe uploaded file exceeds the maximum allowed size (1MB).
429 Too Many RequestsClient ErrorYou have exceeded a rate limit (e.g., too many concurrent jobs or too many requests per hour/day).
500 Internal Server ErrorServer ErrorSomething went wrong on our end. Please try again later. If the problem persists, contact support.
503 Service UnavailableServer ErrorA required downstream service (like our moderation service) is temporarily unavailable.