MaxDay AI API documentation
Complete an App Run in minutes with these four steps.
- Prepare an API Key Obtain credentials and configure the API Base URL.
- Get a Project ID, select an App, and read its parameters Select a project and one of its published Apps, then prepare the inputs currently declared by that App.
- Create an App Run
Submit the App ID, Project ID, and
inputJson, then save the returned Run ID. - Get the Run result Poll with the Run ID and read outputs or errors after the Run enters a terminal state.
Step 1: Prepare an API Key
Before integrating, prepare:
- API Base URL:
https://api.maxday.ai/bio/dramas/v1; - An active API Key from the API Key page, in a format similar to
ak_live_....
Store them as server-side environment variables:
export MAXDAY_API_BASE_URL="https://api.maxday.ai/bio/dramas/v1"
export MAXDAY_API_KEY="ak_live_REPLACE_WITH_YOUR_API_KEY"
The complete API Key is shown only once. Store it in a server-side secret manager or environment variable. Never commit it to a source repository or put it in browser code, URLs, logs, or error-reporting data.
Step 2: Get a Project ID, select an App, and read its parameters
Get a Project ID
Every Run belongs to a project. Balance checks and charges also belong to that project. The data.id returned by the project list or creation API is the Project ID. Pass it unchanged as projectId when creating a Run.
Reuse an existing Project ID instead of creating a new project for every task. List the projects available to the current account:
curl --fail-with-body --connect-timeout 10 --max-time 30 \
"${MAXDAY_API_BASE_URL}/openapi/v1/projects" \
--header "Authorization: Bearer ${MAXDAY_API_KEY}"
Success response:
{
"code": 200,
"message": "success",
"data": [
{
"id": "PROJECT_ID",
"name": "Advertising Assets"
}
]
}
Select an existing project and save its Project ID:
export MAXDAY_PROJECT_ID="PROJECT_ID"
See List projects for all fields. Create a project only when the list returns data: [] and no usable project exists:
curl --fail-with-body --connect-timeout 10 --max-time 60 \
--request POST "${MAXDAY_API_BASE_URL}/openapi/v1/projects" \
--header "Authorization: Bearer ${MAXDAY_API_KEY}" \
--header "Content-Type: application/json" \
--data '{
"name": "Advertising Assets"
}'
Success response:
{
"code": 200,
"message": "success",
"data": {
"id": "PROJECT_ID",
"name": "Advertising Assets"
}
}
After creation, save the returned Project ID and reuse it for later tasks:
export MAXDAY_PROJECT_ID="PROJECT_ID"
List published Apps in the project
Use the selected Project ID to list the project's published Apps:
curl --fail-with-body --connect-timeout 10 --max-time 30 \
"${MAXDAY_API_BASE_URL}/openapi/v1/apps?projectId=${MAXDAY_PROJECT_ID}&pageNo=1&pageSize=20" \
--header "Authorization: Bearer ${MAXDAY_API_KEY}"
The data.items in a successful response contains App summaries for the current page. Select an App and save its appId. If the page returns items: [], query the next page or check the publication status in the MaxDay App Store. See List published Apps for all fields.
Read App parameters
Before creating a Run, read the inputs, outputs, steps, examples, and estimated price of the App's current published version:
curl --fail-with-body --connect-timeout 10 --max-time 30 \
"${MAXDAY_API_BASE_URL}/openapi/v1/apps/REPLACE_WITH_YOUR_APP_ID" \
--header "Authorization: Bearer ${MAXDAY_API_KEY}"
Every App may declare different inputs. Build inputJson from the data.inputs returned by App details. Fields used later in this guide are only examples.
Step 3: Create an App Run
curl --fail-with-body --connect-timeout 10 --max-time 60 \
--request POST "${MAXDAY_API_BASE_URL}/openapi/v1/app-runs" \
--header "Authorization: Bearer ${MAXDAY_API_KEY}" \
--header "Content-Type: application/json" \
--data "{
\"appId\": \"REPLACE_WITH_YOUR_APP_ID\",
\"projectId\": \"${MAXDAY_PROJECT_ID}\",
\"inputJson\": {
\"outfit_prompt\": \"Fashion outfit flat lay on white background\",
\"character_image\": {
\"url\": \"https://example.com/a.png\"
}
}
}"
Success response:
{
"code": 200,
"message": "success",
"data": {
"runId": "e8f4c7a135d64211a8d2c0019b57ef63",
"estimatedPrice": "12.50000000"
}
}
Save the returned Run ID:
export MAXDAY_RUN_ID="e8f4c7a135d64211a8d2c0019b57ef63"
The creation API does not deduplicate requests. Do not blindly retry the POST after a network interruption; doing so may create another Run and incur another charge. After confirming creation, use the Run ID to query the result.
Step 4: Get the Run result
Runs execute asynchronously. Query the status with the Run ID returned by the creation API:
curl --fail-with-body --connect-timeout 10 --max-time 30 \
--retry 4 --retry-all-errors --retry-delay 1 \
"${MAXDAY_API_BASE_URL}/openapi/v1/app-runs/${MAXDAY_RUN_ID}" \
--header "Authorization: Bearer ${MAXDAY_API_KEY}"
Example response after successful completion:
{
"code": 200,
"message": "success",
"data": {
"runId": "e8f4c7a135d64211a8d2c0019b57ef63",
"status": "succeeded",
"progress": 100,
"estimatedPrice": "12.50000000",
"actualPrice": "12.50000000",
"createdAt": 1786759200000,
"endTime": 1786759260000,
"outputs": [
{
"name": "Final video",
"url": "https://example.com/out.mp4",
"type": "video"
}
],
"steps": [],
"error": null
}
}
Poll every 2 seconds for the first 30 seconds, then gradually increase the interval to 5–10 seconds. Stop polling after entering any terminal state:
| Status | Meaning |
|---|---|
succeeded | All required steps succeeded |
partial_success | Some steps succeeded and produced usable results |
failed | Execution failed; inspect data.error in the response |
canceled | Execution was canceled |
Do not automatically retry the POST that creates a Run. The result-query GET may be retried with backoff after network errors, HTTP 429, or temporary server errors. Prefer the delay in the Retry-After header.
Complete examples
The examples below support Node.js 18+, Python 3.9+, and Java 11+. Update inputJson to match the App details response.
const baseUrl = "https://api.maxday.ai/bio/dramas/v1";
// API Key and reusable Project ID.
const apiKey = process.env.MAXDAY_API_KEY;
const projectId = process.env.MAXDAY_PROJECT_ID;
// Target App ID obtained from the project's App list or platform.
const appId = "REPLACE_WITH_YOUR_APP_ID";
if (!apiKey || !projectId) {
throw new Error("Set MAXDAY_API_KEY and MAXDAY_PROJECT_ID");
}
// Wait for the specified number of milliseconds.
const sleep = (milliseconds) =>
new Promise((resolve) => setTimeout(resolve, milliseconds));
// Send a request and handle HTTP and application errors consistently.
async function request(path, options = {}) {
// Response object for the current request.
const response = await fetch(`${baseUrl}${path}`, {
...options,
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
...options.headers,
},
signal: AbortSignal.timeout(60_000),
});
// Raw response text.
const text = await response.text();
// Parsed response JSON.
let body;
try {
body = JSON.parse(text);
} catch {
throw new Error(text || `HTTP ${response.status}`);
}
if (!response.ok || body.message !== "success") {
throw new Error(body.data?.error?.message || body.message || `HTTP ${response.status}`);
}
return body.data;
}
// Execute one complete App Run flow.
async function runApp() {
// Public parameter definition of the current App.
const app = await request(`/openapi/v1/apps/${appId}`);
console.log("App inputs:", app.inputs);
// Newly created Run.
const createdRun = await request("/openapi/v1/app-runs", {
method: "POST",
body: JSON.stringify({
appId,
projectId,
inputJson: {
outfit_prompt: "Fashion outfit flat lay on white background",
character_image: { url: "https://example.com/a.png" },
},
}),
});
// Wait at most one hour.
const deadline = Date.now() + 60 * 60 * 1000;
// Current polling interval, initially two seconds.
let pollDelay = 2_000;
while (Date.now() < deadline) {
// Latest status of the current Run.
const run = await request(`/openapi/v1/app-runs/${createdRun.runId}`);
if (["succeeded", "partial_success"].includes(run.status)) {
return run;
}
if (["failed", "canceled"].includes(run.status)) {
throw new Error(run.error?.message || `Run ${run.status}`);
}
await sleep(pollDelay);
pollDelay = Math.min(10_000, pollDelay + 1_000);
}
throw new Error(`Timed out waiting for Run ${createdRun.runId}`);
}
runApp().then(console.log).catch(console.error);import json
import os
import time
from urllib.error import HTTPError
from urllib.request import Request, urlopen
BASE_URL = "https://api.maxday.ai/bio/dramas/v1"
# API Key and reusable Project ID.
API_KEY = os.environ.get("MAXDAY_API_KEY")
PROJECT_ID = os.environ.get("MAXDAY_PROJECT_ID")
# Target App ID obtained from the project's App list or platform.
APP_ID = "REPLACE_WITH_YOUR_APP_ID"
if not API_KEY or not PROJECT_ID:
raise RuntimeError("Set MAXDAY_API_KEY and MAXDAY_PROJECT_ID")
# Send a request and handle HTTP and application errors consistently.
def request_api(path, method="GET", payload=None):
data = None if payload is None else json.dumps(payload).encode("utf-8")
request = Request(
BASE_URL + path,
data=data,
method=method,
headers={
"Authorization": "Bearer " + API_KEY,
"Content-Type": "application/json",
},
)
try:
with urlopen(request, timeout=60) as response:
status = response.status
text = response.read().decode("utf-8")
except HTTPError as error:
status = error.code
text = error.read().decode("utf-8")
try:
body = json.loads(text)
except json.JSONDecodeError as error:
raise RuntimeError(text or "HTTP " + str(status)) from error
api_error = body.get("data", {}).get("error", {}) if isinstance(body, dict) else {}
if status < 200 or status >= 300 or body.get("message") != "success":
message = api_error.get("message") if isinstance(api_error, dict) else None
raise RuntimeError(message or body.get("message") or "HTTP " + str(status))
return body["data"]
# Execute one complete App Run flow.
def run_app():
# Read the current App's public parameter definition.
app = request_api("/openapi/v1/apps/" + APP_ID)
print("App inputs:", json.dumps(app.get("inputs"), ensure_ascii=False, indent=2))
# Create a Run.
created_run = request_api(
"/openapi/v1/app-runs",
method="POST",
payload={
"appId": APP_ID,
"projectId": PROJECT_ID,
"inputJson": {
"outfit_prompt": "Fashion outfit flat lay on white background",
"character_image": {"url": "https://example.com/a.png"},
},
},
)
# Wait at most one hour.
deadline = time.monotonic() + 60 * 60
# Current polling interval, initially two seconds.
poll_delay = 2
while time.monotonic() < deadline:
# Latest status of the current Run.
run = request_api("/openapi/v1/app-runs/" + created_run["runId"])
status = run["status"]
if status in {"succeeded", "partial_success"}:
return run
if status in {"failed", "canceled"}:
error = run.get("error") or {}
raise RuntimeError(error.get("message") or "Run " + status)
time.sleep(poll_delay)
poll_delay = min(10, poll_delay + 1)
raise RuntimeError("Timed out waiting for Run " + created_run["runId"])
print(json.dumps(run_app(), ensure_ascii=False, indent=2))import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.Set;
public final class MaxDayAppRunExample {
// JSON serializer and HTTP client.
private static final ObjectMapper JSON = new ObjectMapper();
private static final HttpClient HTTP = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(10))
.build();
private static final String BASE_URL = "https://api.maxday.ai/bio/dramas/v1";
// API Key and reusable Project ID.
private static final String API_KEY = requireEnvironment("MAXDAY_API_KEY");
private static final String PROJECT_ID = requireEnvironment("MAXDAY_PROJECT_ID");
// Target App ID obtained from the project's App list or platform.
private static final String APP_ID = "REPLACE_WITH_YOUR_APP_ID";
// Successful and failed terminal Run statuses.
private static final Set<String> SUCCESS_STATUSES =
Set.of("succeeded", "partial_success");
private static final Set<String> FAILURE_STATUSES =
Set.of("failed", "canceled");
/** Reads a required environment variable. */
private static String requireEnvironment(String name) {
String value = System.getenv(name);
if (value == null || value.isBlank()) {
throw new IllegalStateException("Set " + name);
}
return value;
}
/** Sends a request and handles HTTP and application errors consistently. */
private static JsonNode request(String path, String method, JsonNode payload)
throws Exception {
HttpRequest.BodyPublisher publisher = payload == null
? HttpRequest.BodyPublishers.noBody()
: HttpRequest.BodyPublishers.ofString(JSON.writeValueAsString(payload));
HttpRequest request = HttpRequest.newBuilder(URI.create(BASE_URL + path))
.timeout(Duration.ofSeconds(60))
.header("Authorization", "Bearer " + API_KEY)
.header("Content-Type", "application/json")
.method(method, publisher)
.build();
HttpResponse<String> response = HTTP.send(
request,
HttpResponse.BodyHandlers.ofString()
);
JsonNode body;
try {
body = JSON.readTree(response.body());
} catch (Exception error) {
throw new IllegalStateException(
response.body().isBlank() ? "HTTP " + response.statusCode() : response.body(),
error
);
}
if (response.statusCode() < 200
|| response.statusCode() >= 300
|| !"success".equals(body.path("message").asText())) {
throw new IllegalStateException(
body.path("data").path("error").path("message").asText(
body.path("message").asText("HTTP " + response.statusCode())
)
);
}
return body.path("data");
}
/** Executes one complete App Run flow. */
public static void main(String[] args) throws Exception {
// Read the current App's public parameter definition.
JsonNode app = request("/openapi/v1/apps/" + APP_ID, "GET", null);
System.out.println("App inputs: " + app.path("inputs").toPrettyString());
// Create a Run.
ObjectNode runPayload = JSON.createObjectNode();
runPayload.put("appId", APP_ID);
runPayload.put("projectId", PROJECT_ID);
ObjectNode inputJson = runPayload.putObject("inputJson");
inputJson.put("outfit_prompt", "Fashion outfit flat lay on white background");
inputJson.putObject("character_image").put("url", "https://example.com/a.png");
JsonNode createdRun = request("/openapi/v1/app-runs", "POST", runPayload);
// Wait at most one hour.
long deadline = System.currentTimeMillis() + Duration.ofHours(1).toMillis();
// Current polling interval, initially two seconds.
long pollDelay = 2_000;
while (System.currentTimeMillis() < deadline) {
// Latest status of the current Run.
JsonNode run = request(
"/openapi/v1/app-runs/" + createdRun.path("runId").asText(),
"GET",
null
);
String status = run.path("status").asText();
if (SUCCESS_STATUSES.contains(status)) {
System.out.println(run.toPrettyString());
return;
}
if (FAILURE_STATUSES.contains(status)) {
throw new IllegalStateException(
run.path("error").path("message").asText("Run " + status)
);
}
Thread.sleep(pollDelay);
pollDelay = Math.min(10_000, pollDelay + 1_000);
}
throw new IllegalStateException(
"Timed out waiting for Run " + createdRun.path("runId").asText()
);
}
}API summary
| Item | Value |
|---|---|
| Base URL | https://api.maxday.ai/bio/dramas/v1 |
| Authentication header | Authorization: Bearer <API_KEY> |
| POST Content-Type | application/json |
| Successful creation | HTTP 201 |
| Successful query | HTTP 200 |
| Application error | HTTP 200, top-level message is not success, details are in data.error |
Next steps
- Authentication and conventions: API Keys, security, the error protocol, and rate limits;
- API overview: all available APIs;
- List published Apps: obtain an App ID by Project ID;
- Get App details: dynamic inputs, outputs, and examples;
- Create an App Run: complete request rules;
- Get an App Run: status, steps, and result fields.