Skip to content
Docs version r8
OpenAPIJSONYAML
Guides / Move to VizoAPI from another provider

Move to VizoAPI from another provider

Each tab below has a prompt for your coding agent (Claude Code, Codex, Cursor or similar). Paste it into the agent in your project. The prompt tells the agent how to map your current provider's authentication, task creation, status checks or webhooks, and result fields onto VizoAPI.

Three differences matter in every migration. VizoAPI is asynchronous: creating a task returns at once and you collect the result later. A repeated create call is a second task and a second charge, so a timeout must not trigger a blind retry. Prices are in Credits, and outputs are kept for 7 days.

The prompts describe the other provider only in general terms, and tell the agent to read that provider's current documentation. Check the diff and run one small task before you move traffic.

Replicate

Replicate creates a prediction from a model and an input object, then returns the result later: you poll the prediction or receive a webhook. The result is a URL or a list of URLs.

You are migrating this codebase from Replicate to VizoAPI. Change only the code that calls Replicate. Leave the rest of the application as it is.

Step 1. Find every place the code uses Replicate: client set-up, model calls, status checks, webhook handlers, and the code that reads the result. List them for me before you edit anything.

Step 2. Authentication. Replicate sends its API token as a bearer token in the Authorization header. Replace it with a header Authorization: Bearer <key>. Read the key from the environment variable VIZO_API_KEY. Keep the key on the server; never put it in browser or app code.
The base URL of every call below is:
https://api.vizoapi.com


Step 3. Models. Call `GET /v1/models` and choose the VizoAPI model that matches the Replicate model used today. Each entry lists the `inputSchema` its input must follow, its `features` and the price of each of its `tiers`. `GET /v1/models/{id}` returns one model. After choosing a model, read its guide, https://vizoapi.com/docs/models/<model id>.md: its modes, runnable example bodies, input limits, billing and errors for that model. Also read the Rate limits, Billing and Errors pages (https://vizoapi.com/docs/rate-limits, https://vizoapi.com/docs/billing, https://vizoapi.com/docs/errors). To validate a body without creating anything, send it to `POST /v1/estimates`: it is free, creates no task and refuses invalid input with the same errors as a create. It needs the generations:create scope and counts against the rate limits. If no match is clear, stop and ask me. Do not guess.

Step 4. Create the task. Replace the create call with `POST /v1/generations`. The body has `model` and `input`, nothing else beside `metadata` and `webhook_endpoint_id`; the input alone selects the price tier. Build `input` from the `inputSchema` of step 3, in the model's own field names: for Kling and Wan the prompt goes in `input.prompt`, for Seedance and MiniMax in a text part of the input's content list. Send only the fields the schema lists; any other field is refused with HTTP 422. Add `metadata` with a `client_reference` of your own, such as your order id. The call returns HTTP 202 and the new task in the response body; keep its `id`. There is no synchronous result, so the code must wait for the task as in step 5. Do not retry a create call after a timeout: a second call creates a second task and a second charge. First look for the task with `GET /v1/generations` and the same `client_reference`. By default an organization runs 3 video tasks at once (10 image, 10 audio); a create above that gets HTTP 429 concurrency_limited, so queue tasks on your side and submit the next one when one finishes.

Step 5. Wait for the result. Replicate code usually creates a prediction and then polls it until it reaches a final state, or waits with a helper that does this for you. Find that loop. If the code uses a helper that blocks until the output is ready, replace it with your own submit-and-poll function. Replace it with `GET /v1/generations/{id}`, called every 5 seconds and slowing to every 10 seconds. The task is finished when `closed_at` is not null. A task still unfinished at its deadline closes as "unresolved": it is not charged, so treat it as failed; if its result arrives later, `late_result_available` becomes true and `result` is filled at no charge. If `status` is "succeeded", take every `asset_id` in `result.outputs`, in order; a task with one output lists one. `result.asset_id` repeats the first output, so do not download it twice. Call `GET /v1/assets/{id}/download` with each asset id and fetch the returned `url` at once, because it expires at `url_expires_at`. Fetch the `url` without the API key. Copy the file to your own storage, because outputs are kept for 7 days only. If the task finished without success, nothing can be downloaded: read `error.code` and handle it.

Step 6. Input files. A media field of the schema takes a public HTTPS URL or the `asset_id` of a file uploaded to the same project. To upload, call `POST /v1/assets/uploads` with `mime` and `max_bytes`, PUT the bytes to the returned `upload_url`, then call `POST /v1/assets/{id}/complete` and put the `asset_id` where the schema expects the media. Private VizoAPI download links, local file paths and Base64 data are refused.

Step 7. Webhooks. If the code receives Replicate webhooks, replace that handler (the verification and the payload parsing) with the VizoAPI handler described below. With VizoAPI you pass `webhook_endpoint_id` when you create the task; create the endpoint in the console first. A delivery is a POST signed per the Standard Webhooks specification, with the headers webhook-id, webhook-timestamp and webhook-signature. Verify it with the official Standard Webhooks library for the language (standardwebhooks on npm and PyPI) and the endpoint's whsec_ signing secret, passing the raw request body; the library checks the signature and the 5-minute timestamp window. Ignore a webhook-id you have seen. The body has `task_id`, `type` and `event_id`. The `type` is one of `generation.succeeded`, `generation.failed`, `generation.canceled`, `generation.unresolved`, `generation.refunded` or `generation.late_result_available`. After verifying, call `GET /v1/generations/{id}` with the `task_id` and act on that read. If you do not use webhooks, delete nothing and add nothing here.

Step 8. Cost. VizoAPI prices are in Credits. Read the charge from `price.charged` on the task and the balance from `GET /v1/wallet`. A task that cannot be funded fails with an `error.code` such as insufficient_balance. The charge follows actual usage and can be above the estimate; Credits the balance cannot cover are owed, and new creates get HTTP 402 balance_negative until a top-up. `GET /v1/wallet` needs a project key with the balance:read scope. Inputs and outputs are always moderated, with no switch; a refused task usually fails with input_moderated or output_moderated, but on some models (Kling) with generation_failed, and either way it is not charged. Do not copy Replicate prices into the code.

Step 9. Do not guess names. This prompt describes only the general Replicate pattern. Read the current Replicate documentation for its exact endpoint and field names before you change code that depends on them. Tell me every Replicate feature that has no VizoAPI equivalent instead of inventing one.

Step 10. Test. Run one small task end to end with the new code, and show me the diff and the result. Do not switch production traffic.

fal.ai

fal.ai runs a model on a queue: you submit a request, receive a request id, check its status and then fetch the result. Results are file URLs.

You are migrating this codebase from fal.ai to VizoAPI. Change only the code that calls fal.ai. Leave the rest of the application as it is.

Step 1. Find every place the code uses fal.ai: client set-up, model calls, status checks, webhook handlers, and the code that reads the result. List them for me before you edit anything.

Step 2. Authentication. fal.ai sends its key with the Key scheme in the Authorization header, not Bearer. Replace it with a header Authorization: Bearer <key>. Read the key from the environment variable VIZO_API_KEY. Keep the key on the server; never put it in browser or app code.
The base URL of every call below is:
https://api.vizoapi.com


Step 3. Models. Call `GET /v1/models` and choose the VizoAPI model that matches the fal.ai model used today. Each entry lists the `inputSchema` its input must follow, its `features` and the price of each of its `tiers`. `GET /v1/models/{id}` returns one model. After choosing a model, read its guide, https://vizoapi.com/docs/models/<model id>.md: its modes, runnable example bodies, input limits, billing and errors for that model. Also read the Rate limits, Billing and Errors pages (https://vizoapi.com/docs/rate-limits, https://vizoapi.com/docs/billing, https://vizoapi.com/docs/errors). To validate a body without creating anything, send it to `POST /v1/estimates`: it is free, creates no task and refuses invalid input with the same errors as a create. It needs the generations:create scope and counts against the rate limits. If no match is clear, stop and ask me. Do not guess.

Step 4. Create the task. Replace the create call with `POST /v1/generations`. The body has `model` and `input`, nothing else beside `metadata` and `webhook_endpoint_id`; the input alone selects the price tier. Build `input` from the `inputSchema` of step 3, in the model's own field names: for Kling and Wan the prompt goes in `input.prompt`, for Seedance and MiniMax in a text part of the input's content list. Send only the fields the schema lists; any other field is refused with HTTP 422. Add `metadata` with a `client_reference` of your own, such as your order id. The call returns HTTP 202 and the new task in the response body; keep its `id`. There is no synchronous result, so the code must wait for the task as in step 5. Do not retry a create call after a timeout: a second call creates a second task and a second charge. First look for the task with `GET /v1/generations` and the same `client_reference`. By default an organization runs 3 video tasks at once (10 image, 10 audio); a create above that gets HTTP 429 concurrency_limited, so queue tasks on your side and submit the next one when one finishes.

Step 5. Wait for the result. fal.ai code usually submits to the queue and then waits, either with the client library helper that subscribes to the request or with its own status loop. Find that code. Replace the helper with your own submit-and-poll function. The VizoAPI call does not stream progress logs. Replace it with `GET /v1/generations/{id}`, called every 5 seconds and slowing to every 10 seconds. The task is finished when `closed_at` is not null. A task still unfinished at its deadline closes as "unresolved": it is not charged, so treat it as failed; if its result arrives later, `late_result_available` becomes true and `result` is filled at no charge. If `status` is "succeeded", take every `asset_id` in `result.outputs`, in order; a task with one output lists one. `result.asset_id` repeats the first output, so do not download it twice. Call `GET /v1/assets/{id}/download` with each asset id and fetch the returned `url` at once, because it expires at `url_expires_at`. Fetch the `url` without the API key. Copy the file to your own storage, because outputs are kept for 7 days only. If the task finished without success, nothing can be downloaded: read `error.code` and handle it.

Step 6. Input files. A media field of the schema takes a public HTTPS URL or the `asset_id` of a file uploaded to the same project. To upload, call `POST /v1/assets/uploads` with `mime` and `max_bytes`, PUT the bytes to the returned `upload_url`, then call `POST /v1/assets/{id}/complete` and put the `asset_id` where the schema expects the media. Private VizoAPI download links, local file paths and Base64 data are refused.

Step 7. Webhooks. If the code gives fal.ai a webhook URL, replace that handler (the verification and the payload parsing) with the VizoAPI handler described below. With VizoAPI you pass `webhook_endpoint_id` when you create the task; create the endpoint in the console first. A delivery is a POST signed per the Standard Webhooks specification, with the headers webhook-id, webhook-timestamp and webhook-signature. Verify it with the official Standard Webhooks library for the language (standardwebhooks on npm and PyPI) and the endpoint's whsec_ signing secret, passing the raw request body; the library checks the signature and the 5-minute timestamp window. Ignore a webhook-id you have seen. The body has `task_id`, `type` and `event_id`. The `type` is one of `generation.succeeded`, `generation.failed`, `generation.canceled`, `generation.unresolved`, `generation.refunded` or `generation.late_result_available`. After verifying, call `GET /v1/generations/{id}` with the `task_id` and act on that read. If you do not use webhooks, delete nothing and add nothing here.

Step 8. Cost. VizoAPI prices are in Credits. Read the charge from `price.charged` on the task and the balance from `GET /v1/wallet`. A task that cannot be funded fails with an `error.code` such as insufficient_balance. The charge follows actual usage and can be above the estimate; Credits the balance cannot cover are owed, and new creates get HTTP 402 balance_negative until a top-up. `GET /v1/wallet` needs a project key with the balance:read scope. Inputs and outputs are always moderated, with no switch; a refused task usually fails with input_moderated or output_moderated, but on some models (Kling) with generation_failed, and either way it is not charged. Do not copy fal.ai prices into the code.

Step 9. Do not guess names. This prompt describes only the general fal.ai pattern. Read the current fal.ai documentation for its exact endpoint and field names before you change code that depends on them. Tell me every fal.ai feature that has no VizoAPI equivalent instead of inventing one.

Step 10. Test. Run one small task end to end with the new code, and show me the diff and the result. Do not switch production traffic.

WaveSpeed

WaveSpeed creates a task for a model, returns a task id, and you fetch the result by polling or receive it by webhook. Results are file URLs.

You are migrating this codebase from WaveSpeed to VizoAPI. Change only the code that calls WaveSpeed. Leave the rest of the application as it is.

Step 1. Find every place the code uses WaveSpeed: client set-up, model calls, status checks, webhook handlers, and the code that reads the result. List them for me before you edit anything.

Step 2. Authentication. WaveSpeed sends its API key as a bearer token in the Authorization header. Replace it with a header Authorization: Bearer <key>. Read the key from the environment variable VIZO_API_KEY. Keep the key on the server; never put it in browser or app code.
The base URL of every call below is:
https://api.vizoapi.com


Step 3. Models. Call `GET /v1/models` and choose the VizoAPI model that matches the WaveSpeed model used today. Each entry lists the `inputSchema` its input must follow, its `features` and the price of each of its `tiers`. `GET /v1/models/{id}` returns one model. After choosing a model, read its guide, https://vizoapi.com/docs/models/<model id>.md: its modes, runnable example bodies, input limits, billing and errors for that model. Also read the Rate limits, Billing and Errors pages (https://vizoapi.com/docs/rate-limits, https://vizoapi.com/docs/billing, https://vizoapi.com/docs/errors). To validate a body without creating anything, send it to `POST /v1/estimates`: it is free, creates no task and refuses invalid input with the same errors as a create. It needs the generations:create scope and counts against the rate limits. If no match is clear, stop and ask me. Do not guess.

Step 4. Create the task. Replace the create call with `POST /v1/generations`. The body has `model` and `input`, nothing else beside `metadata` and `webhook_endpoint_id`; the input alone selects the price tier. Build `input` from the `inputSchema` of step 3, in the model's own field names: for Kling and Wan the prompt goes in `input.prompt`, for Seedance and MiniMax in a text part of the input's content list. Send only the fields the schema lists; any other field is refused with HTTP 422. Add `metadata` with a `client_reference` of your own, such as your order id. The call returns HTTP 202 and the new task in the response body; keep its `id`. There is no synchronous result, so the code must wait for the task as in step 5. Do not retry a create call after a timeout: a second call creates a second task and a second charge. First look for the task with `GET /v1/generations` and the same `client_reference`. By default an organization runs 3 video tasks at once (10 image, 10 audio); a create above that gets HTTP 429 concurrency_limited, so queue tasks on your side and submit the next one when one finishes.

Step 5. Wait for the result. WaveSpeed code submits a task for a model and then polls the result of that task until it finishes, or uses its webhook option. Find that loop, including any synchronous mode that waits for the output. Replace it with `GET /v1/generations/{id}`, called every 5 seconds and slowing to every 10 seconds. The task is finished when `closed_at` is not null. A task still unfinished at its deadline closes as "unresolved": it is not charged, so treat it as failed; if its result arrives later, `late_result_available` becomes true and `result` is filled at no charge. If `status` is "succeeded", take every `asset_id` in `result.outputs`, in order; a task with one output lists one. `result.asset_id` repeats the first output, so do not download it twice. Call `GET /v1/assets/{id}/download` with each asset id and fetch the returned `url` at once, because it expires at `url_expires_at`. Fetch the `url` without the API key. Copy the file to your own storage, because outputs are kept for 7 days only. If the task finished without success, nothing can be downloaded: read `error.code` and handle it.

Step 6. Input files. A media field of the schema takes a public HTTPS URL or the `asset_id` of a file uploaded to the same project. To upload, call `POST /v1/assets/uploads` with `mime` and `max_bytes`, PUT the bytes to the returned `upload_url`, then call `POST /v1/assets/{id}/complete` and put the `asset_id` where the schema expects the media. Private VizoAPI download links, local file paths and Base64 data are refused.

Step 7. Webhooks. If the code gives WaveSpeed a webhook URL, replace that handler (the verification and the payload parsing) with the VizoAPI handler described below. With VizoAPI you pass `webhook_endpoint_id` when you create the task; create the endpoint in the console first. A delivery is a POST signed per the Standard Webhooks specification, with the headers webhook-id, webhook-timestamp and webhook-signature. Verify it with the official Standard Webhooks library for the language (standardwebhooks on npm and PyPI) and the endpoint's whsec_ signing secret, passing the raw request body; the library checks the signature and the 5-minute timestamp window. Ignore a webhook-id you have seen. The body has `task_id`, `type` and `event_id`. The `type` is one of `generation.succeeded`, `generation.failed`, `generation.canceled`, `generation.unresolved`, `generation.refunded` or `generation.late_result_available`. After verifying, call `GET /v1/generations/{id}` with the `task_id` and act on that read. If you do not use webhooks, delete nothing and add nothing here.

Step 8. Cost. VizoAPI prices are in Credits. Read the charge from `price.charged` on the task and the balance from `GET /v1/wallet`. A task that cannot be funded fails with an `error.code` such as insufficient_balance. The charge follows actual usage and can be above the estimate; Credits the balance cannot cover are owed, and new creates get HTTP 402 balance_negative until a top-up. `GET /v1/wallet` needs a project key with the balance:read scope. Inputs and outputs are always moderated, with no switch; a refused task usually fails with input_moderated or output_moderated, but on some models (Kling) with generation_failed, and either way it is not charged. Do not copy WaveSpeed prices into the code.

Step 9. Do not guess names. This prompt describes only the general WaveSpeed pattern. Read the current WaveSpeed documentation for its exact endpoint and field names before you change code that depends on them. Tell me every WaveSpeed feature that has no VizoAPI equivalent instead of inventing one.

Step 10. Test. Run one small task end to end with the new code, and show me the diff and the result. Do not switch production traffic.

kie.ai

kie.ai creates a task for a model, returns a task id, and you fetch the result by polling the task or receive it on a callback URL. Results are file URLs.

You are migrating this codebase from kie.ai to VizoAPI. Change only the code that calls kie.ai. Leave the rest of the application as it is.

Step 1. Find every place the code uses kie.ai: client set-up, model calls, status checks, webhook handlers, and the code that reads the result. List them for me before you edit anything.

Step 2. Authentication. kie.ai sends its API key as a bearer token in the Authorization header. Replace it with a header Authorization: Bearer <key>. Read the key from the environment variable VIZO_API_KEY. Keep the key on the server; never put it in browser or app code.
The base URL of every call below is:
https://api.vizoapi.com


Step 3. Models. Call `GET /v1/models` and choose the VizoAPI model that matches the kie.ai model used today. Each entry lists the `inputSchema` its input must follow, its `features` and the price of each of its `tiers`. `GET /v1/models/{id}` returns one model. After choosing a model, read its guide, https://vizoapi.com/docs/models/<model id>.md: its modes, runnable example bodies, input limits, billing and errors for that model. Also read the Rate limits, Billing and Errors pages (https://vizoapi.com/docs/rate-limits, https://vizoapi.com/docs/billing, https://vizoapi.com/docs/errors). To validate a body without creating anything, send it to `POST /v1/estimates`: it is free, creates no task and refuses invalid input with the same errors as a create. It needs the generations:create scope and counts against the rate limits. If no match is clear, stop and ask me. Do not guess.

Step 4. Create the task. Replace the create call with `POST /v1/generations`. The body has `model` and `input`, nothing else beside `metadata` and `webhook_endpoint_id`; the input alone selects the price tier. Build `input` from the `inputSchema` of step 3, in the model's own field names: for Kling and Wan the prompt goes in `input.prompt`, for Seedance and MiniMax in a text part of the input's content list. Send only the fields the schema lists; any other field is refused with HTTP 422. Add `metadata` with a `client_reference` of your own, such as your order id. The call returns HTTP 202 and the new task in the response body; keep its `id`. There is no synchronous result, so the code must wait for the task as in step 5. Do not retry a create call after a timeout: a second call creates a second task and a second charge. First look for the task with `GET /v1/generations` and the same `client_reference`. By default an organization runs 3 video tasks at once (10 image, 10 audio); a create above that gets HTTP 429 concurrency_limited, so queue tasks on your side and submit the next one when one finishes.

Step 5. Wait for the result. kie.ai code creates a task and then polls the task details until it finishes, or provides a callback URL. Find that loop and the callback handler. Replace it with `GET /v1/generations/{id}`, called every 5 seconds and slowing to every 10 seconds. The task is finished when `closed_at` is not null. A task still unfinished at its deadline closes as "unresolved": it is not charged, so treat it as failed; if its result arrives later, `late_result_available` becomes true and `result` is filled at no charge. If `status` is "succeeded", take every `asset_id` in `result.outputs`, in order; a task with one output lists one. `result.asset_id` repeats the first output, so do not download it twice. Call `GET /v1/assets/{id}/download` with each asset id and fetch the returned `url` at once, because it expires at `url_expires_at`. Fetch the `url` without the API key. Copy the file to your own storage, because outputs are kept for 7 days only. If the task finished without success, nothing can be downloaded: read `error.code` and handle it.

Step 6. Input files. A media field of the schema takes a public HTTPS URL or the `asset_id` of a file uploaded to the same project. To upload, call `POST /v1/assets/uploads` with `mime` and `max_bytes`, PUT the bytes to the returned `upload_url`, then call `POST /v1/assets/{id}/complete` and put the `asset_id` where the schema expects the media. Private VizoAPI download links, local file paths and Base64 data are refused.

Step 7. Webhooks. If the code gives kie.ai a callback URL, replace that handler (the verification, if any, and the payload parsing) with the VizoAPI handler described below. With VizoAPI you pass `webhook_endpoint_id` when you create the task; create the endpoint in the console first. A delivery is a POST signed per the Standard Webhooks specification, with the headers webhook-id, webhook-timestamp and webhook-signature. Verify it with the official Standard Webhooks library for the language (standardwebhooks on npm and PyPI) and the endpoint's whsec_ signing secret, passing the raw request body; the library checks the signature and the 5-minute timestamp window. Ignore a webhook-id you have seen. The body has `task_id`, `type` and `event_id`. The `type` is one of `generation.succeeded`, `generation.failed`, `generation.canceled`, `generation.unresolved`, `generation.refunded` or `generation.late_result_available`. After verifying, call `GET /v1/generations/{id}` with the `task_id` and act on that read. If you do not use webhooks, delete nothing and add nothing here.

Step 8. Cost. VizoAPI prices are in Credits. Read the charge from `price.charged` on the task (kie.ai returned it as creditsConsumed) and the balance from `GET /v1/wallet`. A task that cannot be funded fails with an `error.code` such as insufficient_balance. The charge follows actual usage and can be above the estimate; Credits the balance cannot cover are owed, and new creates get HTTP 402 balance_negative until a top-up. `GET /v1/wallet` needs a project key with the balance:read scope. Inputs and outputs are always moderated, with no switch; a refused task usually fails with input_moderated or output_moderated, but on some models (Kling) with generation_failed, and either way it is not charged. Do not copy kie.ai prices into the code.

Step 9. Do not guess names. This prompt describes only the general kie.ai pattern. Read the current kie.ai documentation for its exact endpoint and field names before you change code that depends on them. Tell me every kie.ai feature that has no VizoAPI equivalent instead of inventing one.

Step 10. Test. Run one small task end to end with the new code, and show me the diff and the result. Do not switch production traffic.