Rendley docs

Platform

Credits and cost

Direct AI operations and exports cost credits. Price depends on the model, input, duration, and output settings. Five seconds from one video model may cost a different amount from five seconds on another.

The API quotes each request on demand.

Check the price first

Every direct AI and export endpoint has a /cost twin. It accepts the same request body and returns the credit cost without running the operation or charging you. Agent runs are the exception because the agent chooses its operations after it starts.

const API_KEY = "YOUR_API_KEY";
const API = "https://api.rendley.com/v1";

const headers = {
  "Authorization": `Bearer ${API_KEY}`,
  "Content-Type": "application/json",
};

const BUDGET = 100;

// Same body, two endpoints: one prices it, one runs it.
const body = JSON.stringify({
  params: { prompt: "A slow aerial push over a city at sunset" },
});


// The /cost twin charges nothing and runs nothing. It only quotes.
const priceResponse = await fetch(`${API}/ai/generate-video/cost`, {
  method: "POST",
  headers,
  body,
});

if (!priceResponse.ok) {
  throw new Error("Could not calculate the cost: " + priceResponse.status);
}

const priceBody = await priceResponse.json();
const price = priceBody.data;

if (price > BUDGET) {
  throw new Error("Too expensive: " + price + " credits");
}

// Under budget, so send the same body to the endpoint that does the work.
const jobResponse = await fetch(`${API}/ai/generate-video`, {
  method: "POST",
  headers,
  body,
});

if (!jobResponse.ok) {
  throw new Error("Could not start the job: " + jobResponse.status);
}

const jobBody = await jobResponse.json();
const job = jobBody.data;
curl -X POST https://api.rendley.com/v1/ai/generate-video/cost \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "params": { "prompt": "A slow aerial push over a city at sunset" } }'
# -> { "data": 45 }
import requests

API_KEY = "YOUR_API_KEY"
API = "https://api.rendley.com/v1"

HEADERS = {"Authorization": f"Bearer {API_KEY}"}

BUDGET = 100

# Same body, two endpoints: one prices it, one runs it.
body = {"params": {"prompt": "A slow aerial push over a city at sunset"}}


# The /cost twin charges nothing and runs nothing. It only quotes.
price_response = requests.post(f"{API}/ai/generate-video/cost", headers=HEADERS, json=body)
price_response.raise_for_status()

price = price_response.json()["data"]

if price > BUDGET:
    raise RuntimeError(f"Too expensive: {price} credits")

# Under budget, so send the same body to the endpoint that does the work.
job_response = requests.post(f"{API}/ai/generate-video", headers=HEADERS, json=body)
job_response.raise_for_status()

job = job_response.json()["data"]

The two bodies are identical. Quote and run from the same object.

Endpoints that price themselves

EndpointCost endpoint
POST /ai/generate-videoPOST /ai/generate-video/cost
POST /ai/generate-imagePOST /ai/generate-image/cost
POST /ai/generate-musicPOST /ai/generate-music/cost
POST /ai/generate-sound-effectPOST /ai/generate-sound-effect/cost
POST /ai/generate-motion-graphicsPOST /ai/generate-motion-graphics/cost
POST /ai/text-to-speechPOST /ai/text-to-speech/cost
POST /ai/transcribePOST /ai/transcribe/cost
POST /ai/lipsyncPOST /ai/lipsync/cost
POST /ai/video-translatePOST /ai/video-translate/cost
POST /ai/voice-changerPOST /ai/voice-changer/cost
POST /ai/voice-isolationPOST /ai/voice-isolation/cost
POST /ai/remove-video-backgroundPOST /ai/remove-video-background/cost
POST /ai/remove-image-backgroundPOST /ai/remove-image-background/cost
POST /ai/upscale-videoPOST /ai/upscale-video/cost
POST /ai/upscale-imagePOST /ai/upscale-image/cost
POST /exportPOST /export/cost

The AI cost endpoints return the number directly, as { "data": 45 }. The export one wraps it: POST /export/cost returns { "data": { "credits": 45 } }.

When you run out

A billable request you cannot afford fails immediately with 400 Bad Request and the code NOT_ENOUGH_CREDITS:

{
  "error": {
    "code": "NOT_ENOUGH_CREDITS",
    "message": "You don't have enough credits."
  }
}

Nothing is queued and nothing is charged. Retrying will not help until you top up, so branch on the code and treat it as a stop, not a backoff.

Plan quotas are separate from credits and return 402 Payment Required. Transcription minutes, text-to-speech characters and free music seconds each have a monthly ceiling on some plans, reported as TRANSCRIPTION_LIMIT_REACHED, TTS_CHARS_LIMIT_REACHED, MUSIC_SECONDS_LIMIT_REACHED or USAGE_METER_LIMIT_REACHED. Topping up credits does not clear those. Upgrading the plan does.

Budgeting a bulk run

For batch work, quote the actual request bodies before you start. You can reuse one quote only when the model and every cost-sensitive parameter are identical. Duration, resolution, reference files, and model choice can all change the price.

const API_KEY = "YOUR_API_KEY";
const API = "https://api.rendley.com/v1";

const headers = {
  "Authorization": "Bearer " + API_KEY,
  "Content-Type": "application/json",
};

const BUDGET = 100;

// Whatever you are about to render, one row per output video.
const rows = [
  { prompt: "A slow aerial push over a city at sunset" },
  { prompt: "A close-up of rain on a window at night" },
];

// Quote each request. This stays correct if rows later use different
// durations, resolutions, reference files, or models.
const prices = await Promise.all(
  rows.map(async (row) => {
    const response = await fetch(`${API}/ai/generate-video/cost`, {
      method: "POST",
      headers,
      body: JSON.stringify({ params: { prompt: row.prompt } }),
    });

    if (!response.ok) {
      throw new Error("Could not calculate the cost: " + response.status);
    }

    return (await response.json()).data;
  }),
);

const estimate = prices.reduce((sum, price) => sum + price, 0);

console.log(rows.length + " videos, roughly " + estimate + " credits");

if (estimate > BUDGET) {
  throw new Error("Batch exceeds the budget, not starting");
}
import requests

API_KEY = "YOUR_API_KEY"
API = "https://api.rendley.com/v1"

HEADERS = {"Authorization": f"Bearer {API_KEY}"}

BUDGET = 100

# Whatever you are about to render, one row per output video.
rows = [
    {"prompt": "A slow aerial push over a city at sunset"},
    {"prompt": "A close-up of rain on a window at night"},
]

# Quote each request. This stays correct if rows later use different
# durations, resolutions, reference files, or models.
prices = []

for row in rows:
    response = requests.post(
        f"{API}/ai/generate-video/cost",
        headers=HEADERS,
        json={"params": {"prompt": row["prompt"]}},
    )
    response.raise_for_status()
    prices.append(response.json()["data"])

estimate = sum(prices)

print(f"{len(rows)} videos, roughly {estimate} credits")

if estimate > BUDGET:
    raise RuntimeError("Batch exceeds the budget, not starting")

Where the numbers live

Your balance and plan are on your Rendley account. GET /v1/users/me returns the same account details from code.