Skip to content

Latest commit

 

History

6 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Vancine Seedance API Starter Kit

A standalone, production-quality starter kit for overseas developers who want to build on supported Seedance text-to-video and image-to-video workflows through the Vancine API.

This repository contains only developer-facing integration assets: copyable examples, importable collections, and an automation workflow. It is intentionally small, language-agnostic at the protocol level, and designed to be verified offline.

Vancine provides access to supported Seedance workflows through its documented asynchronous API. Create an account, generate an API key, and check the live pricing page for current model prices.

Try it in Postman

View Postman documentation

To run the requests, import the collection file from this repository: postman/Vancine-Seedance.postman_collection.json. See Postman below for the import steps.

The imported collection ships with an empty api_key on purpose. Fill it in through your own private or local variable after importing. Never save a real key into a public or shared Collection.

Why this starter kit

A general product landing page tells you that an API exists. This repository is meant to help you make a working request as quickly as possible:

  1. Submit a Seedance video task and get a task_id.
  2. Poll the task status with bounded retries.
  3. Handle success, failure, and timeout explicitly.
  4. Retrieve the result URL.

If you can run one of the examples end to end, the integration path works.

Quick links

How the Vancine Seedance workflow works

Seedance requests use an asynchronous submit-and-poll workflow. Each request requires an API key sent as a bearer token.

POST /v1/video/generations
  -> { "id": "...", "task_id": "...", "status": "queued",
       "model": "...", "created_at": 1781863047 }

GET /v1/video/generations/{task_id}
  -> { "code": "success", "message": "",
       "data": { "task_id": "...", "status": "...",
                 "result_url": "...", "progress": "100%" } }

  data.status: QUEUED -> IN_PROGRESS -> SUCCESS | FAILURE
  success result: data.result_url    failure reason: data.fail_reason

The submit call returns the task id at the top level. You then poll the status endpoint on a fixed interval until data.status reaches a terminal state (SUCCESS or FAILURE). Under normal conditions a video task completes within seconds to a few minutes depending on the model and payload, but your code must treat polling as bounded: a configurable interval, a maximum number of attempts or maximum wait time, and a clear exit for failure and timeout.

Requests are authenticated with an API key generated from the Vancine console:

Authorization: Bearer $VANCINE_API_KEY

Repository structure

README.md                              Product + integration guide
.env.example                           Environment variable template
.gitignore                             Default ignores
LICENSE                                 MIT License (examples)
SECURITY.md                            Reporting and handling guidance
examples/
  curl/
    generate.sh                        Submit + poll from the shell
  node/
    package.json                       Node example (ESM, native fetch)
    generate.mjs                       Submit + poll, importable functions
    generate.test.mjs                  Offline unit tests (node:test)
  python/
    requirements.txt                   Runtime dependency (requests)
    generate.py                        Submit + poll, importable functions
    test_generate.py                   Offline unit tests (unittest)
postman/
  Vancine-Seedance.postman_collection.json   Importable Seedance requests
n8n/
  vancine-seedance-workflow.json     Importable async workflow
scripts/
  validate-assets.mjs                Structure + link + secret checks

Quick start

Every example reads the API key from the environment. Copy the template first:

cp .env.example .env
# then edit .env and set VANCINE_API_KEY

To run the examples with the values from .env, load the file with set -a (so every assignment is auto-exported to the environment) before running any example, all from the repository root:

set -a
source .env
set +a

Environment variable

Variable Required Description
VANCINE_API_KEY yes API key from the Vancine console
VANCINE_BASE_URL no Override base URL (defaults to https://vancine.com)
SEEDANCE_MODEL no Model id (defaults to Doubao-Seedance-2.5)
POLL_INTERVAL_SECONDS no Seconds between polls (default 5)
POLL_MAX_ATTEMPTS no Maximum poll attempts (default 120)

cURL

chmod +x examples/curl/generate.sh
./examples/curl/generate.sh

Prerequisites: curl, jq. The script is written for bash, checks both dependencies, exits cleanly on any non-2xx response, and never prints the full API key.

Node.js

cd examples/node
npm install
node cli.mjs

Requirements: Node.js 18+. The example uses native fetch and has no runtime dependencies beyond the Node standard library.

The code is split into two files on purpose:

  • examples/node/generate.mjs holds all param-driven, unit-testable logic (parsing, polling, network calls that take apiKey as a parameter). It never reads the environment, so it can be imported in tests without side effects.
  • examples/node/cli.mjs is the runnable entrypoint: it reads VANCINE_API_KEY from the environment and calls into generate.mjs.

Functions are written to be imported and tested without network access:

import {
  submitTask,
  extractTaskId,
  extractStatus,
  extractResultUrl,
  generateVideo,
} from "./generate.mjs";

Run the offline unit tests (these exercise generate.mjs only):

node --test

Python

cd examples/python
pip install -r requirements.txt
python generate.py

Requirements: Python 3.10+, requests. Parsing and polling logic is split into importable functions that can be tested without network access:

from generate import submit_task, fetch_task, extract_task_id, extract_status, extract_result_url

Run the offline unit tests:

python -m unittest test_generate.py -v

Postman

The collection is in postman/Vancine-Seedance.postman_collection.json and uses the v2.1 format.

It defines collection variables so you do not have to repeat shared values:

Variable Default Purpose
base_url https://vancine.com API host
api_key (empty — set this first) API credential
model Doubao-Seedance-2.5 Example model
task_id (empty) Set automatically

The collection contains two requests:

  1. Submit Seedance VideoPOST {{base_url}}/v1/video/generations
  2. Get Video Task StatusGET {{base_url}}/v1/video/generations/{{task_id}}

Import steps

  1. Open Postman.
  2. Choose Import in the top left.
  3. Select the Vancine-Seedance.postman_collection.json file.
  4. Open the collection, open the Variables tab, and set api_key to your key.
  5. Send Submit Seedance Video first.

After a successful submit, the test script on the submit request saves the task id into the task_id collection variable. The saved value comes from the first present field in this order: task_id, id, data.task_id, data.id. You can then send Get Video Task Status to poll the result. Its test script reads data.status first (the current contract) and falls back to a top-level status. The saved poll examples show the current SUCCESS and FAILURE envelopes. Set a bounded polling loop in your own test runner rather than relying on a single manual send.

The collection ships with an empty api_key and contains no credential.

n8n

The workflow is in n8n/vancine-seedance-workflow.json and uses standard n8n nodes: Manual Trigger, Set/Edit Fields, two HTTP Request nodes, Wait, IF, Merge, and a Code node (for state merging only — no network).

It expresses the same submit-and-poll lifecycle:

setFields
  -> submitTask (HTTP Request + Header Auth)
  -> saveTaskId (Set: extract task_id, carry config)
  -> waitInterval
  -> pollTask (HTTP Request + same Header Auth)
  -> mergeState (Code: merge response + carried state, increment poll_index;
                 reads data.status / data.result_url / data.fail_reason first)
  -> SUCCESS -> output task_id + result URL
  -> FAILURE -> stop with error (shows saved task_id + data.fail_reason)
  -> timeout -> stop (poll_index >= maxPolls)
  -> otherwise -> continue polling (bounded loop back to waitInterval)

Both submitTask and pollTask are real HTTP Request nodes that use generic Header Auth. You must assign the same Header Auth credential to both nodes after import — the Code node never makes network requests.

Loop state (task_id, poll_index, maxPolls, base_url) is carried on execution-scoped items via a Merge node (append mode) that combines the HTTP poll response with a parallel state-carrying Set node. This avoids n8n's stale $('NodeName') cross-node references inside loops and does not rely on global workflow staticData, so concurrent executions never overwrite each other's state.

A base_url field (default https://vancine.com) in the Set node is used by both HTTP Request nodes. No change is needed for production use.

Like the other examples, maxPolls defaults to 120 at a 5-second interval — about 10 minutes maximum — and stays user-configurable while the polling loop remains strictly bounded (poll_index >= maxPolls stops it; there is no infinite loop).

Verification status.

The workflow file currently in this repository was executed in real n8n 2.30.4 (pinned image n8nio/n8n:2.30.4, version confirmed by the n8n CLI inside the running container) through tests/n8n-integration-test.py. Every workflow request went to a local mock that accepts only the fictitious credential Authorization: Bearer dummy_local_key; no production Vancine endpoint was called, and no real API key exists anywhere in the setup. These are the results of this revision, not carried over from an earlier one.

Current shape — the {code, message, data} envelope with data.status, data.result_url and data.fail_reason:

  • SUCCESS: 1 POST + 2 GET, execution success, output carries the matching task_id and the exact result_url.
  • FAILURE: 1 POST + 1 GET, execution error, the Stop-And-Error node fires and its message names the task_id and data.fail_reason; no further GET is issued.
  • timeout at maxPolls=3: 1 POST + exactly 3 GET, the timeout Stop-And-Error node terminates the run, and there is no 4th GET.

Compatibility shape — the older top-level completed / failed form with metadata.url and error.message:

  • completed: 1 POST + 2 GET, execution success, result URL extracted from metadata.url.
  • failed: 1 POST + 1 GET, execution error, message carries the task_id and the compatibility error text, with no extra GET afterwards.

Concurrency — two overlapping executions issued 2 POST and exactly 6 GET in total, produced two distinct task_id values, polled only their own task three times each, and both reached their expected terminal state, so loop state, result URLs and poll_index never cross-contaminate.

Every workflow API request — to /v1/video/generations and to its task-status endpoint — carried Authorization: Bearer dummy_local_key, a fictitious local test value and not a real key. The harness also sends one reachability probe to the mock on a non-API path without that header; it is not a product workflow request and is excluded from every per-scenario request count. Each scenario's terminal state was read back from n8n's own execution records rather than inferred from the mock log alone.

Import was additionally verified with the n8n CLI into a fresh, empty user directory (Successfully imported 1 workflow).

Scope of these claims: n8n 2.30.4 only — no other n8n version has been exercised. Nothing here claims certification, approval, or endorsement by n8n.

The same expressions are also covered offline by tests/n8n-workflow-logic.test.mjs, and tests/mock-server.mjs defaults to the current envelope so the cURL, Node.js and Python examples run end to end against it locally.

Import steps

  1. In n8n, open Workflows -> Import from File.
  2. Select vancine-seedance-workflow.json.
  3. Create one HTTP Header Auth credential:
    • Name: Authorization
    • Value: Bearer <YOUR_VANCINE_API_KEY>
  4. Assign that same credential to both HTTP Request nodes (submitTask and pollTask).
  5. The base_url field defaults to https://vancine.com — no change needed.
  6. Update model, prompt, and size on the Set node as needed, then run.

Compatibility

The current Vancine response contract is the generic task envelope: the poll call answers { code, message, data } and the task fields live inside data. Some deployments and upstream providers instead expose the same facts top level (status, metadata.url, error.message). These examples read the current data.* fields first and fall back to the older shapes, so they keep working while the response format is normalized. The older shapes are compatibility input only — never treat them as the current contract.

Task id

The submit receipt carries the id at the top level; the poll response carries it as data.task_id. One shared extractor serves both, and it resolves the first present value in this order:

  1. top-level task_id — current submit receipt (and older poll responses)
  2. top-level id — current submit receipt (and older poll responses)
  3. data.task_id — current poll envelope
  4. data.id — compatibility

The n8n mergeState node handles the poll response only, so there it prefers data.task_id first.

Task status

The values below are treated as terminal. data.status is the current field.

Current (data.status) Compatibility (top-level status) Meaning
QUEUED queued Waiting
IN_PROGRESS in_progress, IN_PROGRESS Running
SUCCESS completed Done
FAILURE failed Failed

Examples treat SUCCESS (and the compatibility completed) as success, and FAILURE (and the compatibility failed) as a failure.

Result URL

Resolved from the first present value in this order:

  1. data.result_urlcurrent contract
  2. metadata.url — compatibility
  3. data.data.content.video_url — compatibility

Failure reason

Resolved from the first present value in this order:

  1. data.fail_reasoncurrent contract
  2. data.error.message — compatibility
  3. error.message — compatibility

Errors you should handle

Situation HTTP Typical body What to do
Authentication failed 401 error.message about the key or endpoint Verify the key and that you POST to /v1/video/generations, not a chat or TTS path
Insufficient balance 402 / 400 error.message about balance or quota Check the live pricing page and your account balance in the console
Invalid model or payload 400 error.message about model, prompt, size, etc. Check the model id and required parameters
Task failure 200 data.status: "FAILURE" with data.fail_reason (older shapes use error.message) Read the reason and adjust the prompt or inputs
Polling timeout no terminal state within the bounded window Stop polling; report the task_id for debugging
Non-2xx poll response 4xx/5xx transport-level error Stop; do not keep looping

Rules the examples follow:

  • A bounded polling loop with a configurable interval and a maximum attempt count. No infinite loop.
  • Clear, distinct handling for submission error, authentication error, insufficient balance, task failure, and timeout.
  • The full API key is never printed to logs or output.

Security

  • Always pass the API key through an environment variable. Never hard-code it.
  • This repository ships with example prompts only; no real credential is committed. See SECURITY.md for how to report a vulnerability or a committed secret.
  • Rotate the key from the Vancine console if you believe it is exposed.

Product limits

This starter kit documents access to supported Seedance workflows. It does not guarantee:

  • cheapest pricing
  • unlimited or unrestricted usage
  • guaranteed uptime
  • guaranteed output for every prompt
  • any safety-filter bypass

Vancine does not bypass model safety requirements. Model capabilities, input requirements, availability, and safety behavior follow their documented requirements. Model pricing and limits can change; the live pricing page and API documentation remain authoritative.

License

The example code in this repository is released under the MIT License.

The Seedance name and its underlying models are trademarks of their respective owners. This starter kit is an independent integration example and is not an official product of, or partnership with, those providers.