Apps API

Img2Vid apps are preconfigured generation workflows. Use the Apps API when you want to call an app by id instead of choosing a media model, mode, and model-specific options yourself.

The public app API is intentionally minimal. It returns only the app id and flat input parameters, then accepts those parameter names directly in the generation request body.

Endpoints

Method Endpoint Purpose
GET /api/v1/apps List callable apps and their input parameters.
GET /api/v1/apps/{app} Get one app's input parameters.
POST /api/v1/apps/{app}/generations Create an asynchronous generation task from an app.
GET /api/v1/apps/{app}/generations/{id} Query an app generation task.

All endpoints require Authorization: Bearer $BUBLE_API_KEY.

List apps

GET /api/v1/apps

Query parameters

Name Type Required Description
page number No Page number. Defaults to 1.
limit number No Page size. Defaults to 50, max 100.

Example request

curl "https://img2vid.net/api/v1/apps?limit=20" \
  -H "Authorization: Bearer $BUBLE_API_KEY"

Response shape

{
  "data": [
    {
      "id": "video-background-remover",
      "input_parameters": [
        {
          "name": "source_video",
          "type": "array"
        },
        {
          "name": "output_format",
          "type": "string",
          "values": ["webm", "mp4"]
        }
      ]
    }
  ]
}

Input parameters

Each app exposes a flat list of input parameters.

Field Description
name Parameter name to send in the generation request body.
type JSON value type: string, number, boolean, or array.
values Optional allowed value range for parameters with configured discrete values.

For media inputs, type is array; send an array of source file URLs.

Get one app

GET /api/v1/apps/{app}
curl https://img2vid.net/api/v1/apps/video-background-remover \
  -H "Authorization: Bearer $BUBLE_API_KEY"

The response uses the same data shape as a single item from GET /api/v1/apps.

Create an app generation

POST /api/v1/apps/{app}/generations
Content-Type: application/json

The request body is flat. Use only parameter names returned by /api/v1/apps; unknown fields are rejected.

Example request

curl https://img2vid.net/api/v1/apps/video-background-remover/generations \
  -H "Authorization: Bearer $BUBLE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "source_video": ["https://example.com/source-video.mp4"]
  }'

Response shape

{
  "data": {
    "id": "task_id",
    "status": "pending"
  }
}

If an app uses video-duration billing, Img2Vid calculates the source video duration server-side from the submitted video URL. Do not send duration fields to control pricing.

Query app generation

GET /api/v1/apps/{app}/generations/{id}
curl https://img2vid.net/api/v1/apps/video-background-remover/generations/task_id \
  -H "Authorization: Bearer $BUBLE_API_KEY"

Status values

Status Meaning
pending The task has been accepted and is waiting to run.
processing The provider is generating the output.
success Generation completed successfully.
failed Generation failed. Check error.
canceled Generation was canceled.

Success response example

{
  "data": {
    "id": "task_id",
    "status": "success",
    "result": {
      "videos": [
        {
          "url": "https://..."
        }
      ]
    }
  }
}

Failed response example

{
  "data": {
    "id": "task_id",
    "status": "failed",
    "error": {
      "message": "Generation failed."
    }
  }
}

App API vs media model API

Use /api/v1/apps when you want a preconfigured workflow with simple app-level inputs. Use /api/v1/media_models and /api/v1/generations when you want to choose a specific media model, mode, and model controls directly.

SDK examples

SDK app generation methods map to POST /api/v1/apps/{app}/generations. Use only parameter names returned by list or retrieve; media parameters must receive URLs, not local file paths.

The snippets below assume you have already initialized the SDK client as shown in the Quickstart and imported the required language SDK types.

JavaScript / TypeScript

const app = await buble.apps.retrieve('video-background-remover');
console.log(app.data.input_parameters);

const task = await buble.apps.generations.create('video-background-remover', {
  source_video: ['https://example.com/source.mp4'],
  refine_foreground_edges: true,
  subject_is_person: true,
});

const result = await buble.apps.generations.wait(
  'video-background-remover',
  task.data.id
);

Python

app = client.apps.retrieve("video-background-remover")
print(app["data"]["input_parameters"])

task = client.apps.generations.create(
    "video-background-remover",
    source_video=["https://example.com/source.mp4"],
    refine_foreground_edges=True,
    subject_is_person=True,
)

result = client.apps.generations.wait("video-background-remover", task["data"]["id"])

Go

app, err := client.Apps.Retrieve(ctx, "video-background-remover")
if err != nil {
	return err
}
fmt.Println(app.Data.InputParameters)

task, err := client.Apps.Generations.Create(ctx, "video-background-remover", map[string]any{
	"source_video":            []string{"https://example.com/source.mp4"},
	"refine_foreground_edges": true,
	"subject_is_person":       true,
})
if err != nil {
	return err
}

result, err := client.Apps.Generations.Wait(ctx, "video-background-remover", task.Data.ID)

Rust

let app = client.apps().retrieve("video-background-remover").await?;
println!("{:?}", app.data.input_parameters);

let mut body = serde_json::Map::new();
body.insert(
    "source_video".to_string(),
    serde_json::json!(["https://example.com/source.mp4"]),
);
body.insert("refine_foreground_edges".to_string(), serde_json::json!(true));
body.insert("subject_is_person".to_string(), serde_json::json!(true));

let task = client
    .apps()
    .generations()
    .create("video-background-remover", body)
    .await?;

let result = client
    .apps()
    .generations()
    .wait("video-background-remover", &task.data.id, WaitOptions::default())
    .await?;

Swift

let app = try await client.apps.retrieve("video-background-remover")
print(app.data.inputParameters)

let task = try await client.apps.generations.create(
    "video-background-remover",
    body: [
        "source_video": ["https://example.com/source.mp4"],
        "refine_foreground_edges": true,
        "subject_is_person": true
    ]
)

let result = try await client.apps.generations.wait(
    "video-background-remover",
    task.data.id
)

Dart / Flutter

final app = await client.apps.retrieve('video-background-remover');
print(app.data.inputParameters);

final task = await client.apps.generations.create('video-background-remover', {
  'source_video': ['https://example.com/source.mp4'],
  'refine_foreground_edges': true,
  'subject_is_person': true,
});

final result = await client.apps.generations.wait(
  'video-background-remover',
  task.data.id,
);

Elixir

{:ok, app} = Buble.Apps.retrieve(client, "video-background-remover")
IO.inspect(app["data"]["input_parameters"])

{:ok, task} =
  Buble.Apps.Generations.create(client, "video-background-remover", %{
    source_video: ["https://example.com/source.mp4"],
    refine_foreground_edges: true,
    subject_is_person: true
  })

{:ok, result} =
  Buble.Apps.Generations.wait(client, "video-background-remover", task["data"]["id"])

Java

Envelope<PublicApp> app = client.apps().retrieve("video-background-remover");
System.out.println(app.getData().getInputParameters());

Envelope<AppGenerationTask> task = client.apps().generations().create(
        "video-background-remover",
        Map.of(
                "source_video", List.of("https://example.com/source.mp4"),
                "refine_foreground_edges", true,
                "subject_is_person", true));

Envelope<AppGenerationTask> result = client.apps().generations().wait(
        "video-background-remover",
        task.getData().getId());

.NET

var app = await client.Apps.RetrieveAsync("video-background-remover");
Console.WriteLine(app!.Data!.InputParameters);

var task = await client.Apps.Generations.CreateAsync(
    "video-background-remover",
    new Dictionary<string, object?>
    {
        ["source_video"] = new[] { "https://example.com/source.mp4" },
        ["refine_foreground_edges"] = true,
        ["subject_is_person"] = true
    });

var result = await client.Apps.Generations.WaitAsync(
    "video-background-remover",
    task!.Data!.Id!);

PHP

$app = $client->apps()->retrieve('video-background-remover');
var_dump($app['data']['input_parameters']);

$task = $client->apps()->generations()->create('video-background-remover', [
    'source_video' => ['https://example.com/source.mp4'],
    'refine_foreground_edges' => true,
    'subject_is_person' => true,
]);

$result = $client->apps()->generations()->wait(
    'video-background-remover',
    $task['data']['id']
);

Ruby

app = client.apps.retrieve("video-background-remover")
puts app.dig("data", "input_parameters")

task = client.apps.generations.create("video-background-remover", {
  "source_video" => ["https://example.com/source.mp4"],
  "refine_foreground_edges" => true,
  "subject_is_person" => true
})

result = client.apps.generations.wait("video-background-remover", task.dig("data", "id"))

App reference pages