TapVid

Create your motion videos from anything

Turn prompts, ideas, or source materials into structured, motion videos with visuals, voice, and clear explanations.

Log in
    TapVid
    HomeAPI & MCPPricingBlogAbout
    Blog›Text to Video API Tutorial: Build It in 10 Minutes
    Back to Blog

    Text to Video API Tutorial: Build It in 10 Minutes

    Build a source-to-video REST integration in about 10 minutes, then handle the real asynchronous render with persisted job state, safe polling, and retries.

    How-to
    Kenneth ChenKenneth ChenGTM Manager, TapVid

    Invites you to meet fellow video creators.

    Join our Discord
    August 7, 202615 min readUpdated August 12, 2026
    A source webpage flowing through API requests and asynchronous status nodes into a finished motion-graphics video
    Summarize with6 assistants
    ChatGPTPerplexityTapVidvideoClaudeGeminiGrok
    Create videos from your AI agentConnect TapVid API & MCP→

    In this article

    1. 01What a text to video API means in this tutorial
    2. 02Know the contract before writing code
    3. 03Step 1: upload a public URL or file
    4. 04Step 2: create the asynchronous video job
    5. 05Step 3: persist, poll, and request the download
    6. 06What the live REST test revealed
    7. 07Handle API errors without duplicating spend
    8. 08Production checklist for a reliable integration
    9. 09Use the API for finished explainers, not random clips
    Summarize withAPI & MCP →
    ChatGPTPerplexityTapVidClaudeGeminiGrok
    1. What a text to video API means in this tutorial2. Know the contract before writing code3. Step 1: upload a public URL or file4. Step 2: create the asynchronous video job5. Step 3: persist, poll, and request the download6. What the live REST test revealed7. Handle API errors without duplicating spend8. Production checklist for a reliable integration9. Use the API for finished explainers, not random clips

    The short version

    Build a source-to-video REST integration in about 10 minutes, then handle the real asynchronous render with persisted job state, safe polling, and retries.

    This text-to-video API tutorial turns one public source URL into a 30-second, 16:9 English motion-graphics job with TapVid. The integration itself is short: upload material, create a job, poll status, and request a signed download URL. The render is asynchronous and is not guaranteed to finish in 10 minutes. The controlled test took much longer, which is exactly why the production code below persists the job ID and survives transient network failures.

    Review TapVid API and MCP access

    01

    What a text to video API means in this tutorial

    “Text to video” covers several different products. Some APIs turn a short prompt into a five-second cinematic clip. Others animate an image, place a digital presenter over a script, or assemble stock footage. TapVid handles a different job: transform creator-owned source material into a structured, multi-scene information video. In this tutorial the input is not a vague visual prompt. It is the public TapVid API and MCP page plus a brief that defines audience, duration, aspect ratio, message, and prohibited claims. The output target is a complete 30-second information video rather than one isolated shot. For agencies and small businesses, prompt-based scene editing also means one scene can be regenerated while the rest stays intact.

    The phrase “build it in 10 minutes” refers to integrating the four REST operations, not promising a 10-minute render. Video generation is asynchronous. The create endpoint returns `202 Accepted` immediately, status may remain unchanged for long periods, and export preparation can continue after generation reports completed. A truthful client separates request latency from generation latency. It shows that the job was accepted, stores the ID, reports current status, and resumes later. It never replaces an active job with a duplicate just because a browser tab or network connection disappeared.

    The embedded video below is a finished TapVid example from a separate verified workflow. It demonstrates the kind of multi-scene output the API can deliver, but it is not presented as the terminal result of this REST test because that poller lost its connection before the job reached an observed terminal state.

    02

    Know the contract before writing code

    The current official gateway is `https://api.tapvid.ai/api/public/v1`, and every request uses `Authorization: Bearer YOUR_KEY` over HTTPS. Create the key at TapVid API Keys and expose it to local code as `process.env.TAPVID_API_KEY`. Do not hard-code it into the script shown in a blog, repository, frontend bundle, screenshot, or client-side application. The create flow accepts one to 30 material IDs, a required prompt, optional title, `16:9` or `9:16`, durations from `30s` through `5m`, and an optional language. These are wire values, so spelling and punctuation matter.

    • Use the public REST base `https://api.tapvid.ai/api/public/v1` over HTTPS.
    • Load the key from `process.env.TAPVID_API_KEY` on the server, never from frontend code.
    • Upload exactly one HTTPS URL or one multipart file per material request.
    • Persist `materialId`, then persist `videoId` immediately after the HTTP 202 create response.
    • Poll with the returned `pollAfterSeconds` and keep an overall resumable timeout.
    Field or resourceCurrent documented constraintImplementation note
    File100 MB per fileUse multipart form data
    URLHTTPS, up to 4,096 charactersNo internal hosts
    MaterialsUp to 30 per videoPersist every returned material ID
    PromptUp to 12,000 charactersKeep it specific and source-grounded
    Aspect ratio`16:9` or `9:16`Omit only when automatic choice is acceptable
    Duration`30s`, `60s`, `2m`, `3m`, `4m`, or `5m`Choose a wire enum exactly

    03

    Step 1: upload a public URL or file

    Start by uploading exactly one source form. For a URL, send JSON with an HTTPS `url`. For a file, send multipart form data with one file no larger than 100 MB. URL strings can be up to 4,096 characters and cannot target internal hosts. The example uses `https://tapvid.ai/api-mcp` because it is public, stable enough for this test, and describes the service being explained. The upload response returns `materialId`. Treat it as private application state. It is not a human-readable slug and does not belong in analytics labels or public logs.

    export TAPVID_API_KEY="replace-with-your-local-secret"
    
    curl -X POST https://api.tapvid.ai/api/public/v1/materials \
      -H "Authorization: Bearer ${TAPVID_API_KEY}" \
      -H "Content-Type: application/json" \
      -d '{ "url": "https://tapvid.ai/api-mcp" }'

    The cURL example sets an environment variable only to make the request easy to follow. In a shared machine or CI system, use the platform secret store instead of exporting a long-lived value into a shell history. The JSON response should contain `materialId` and `type`. Save both with the job record you are about to create. If upload fails with `payload_too_large`, changing the create prompt will not help. Fix the material. If the URL is rejected, verify HTTPS, length, reachability, redirects, and whether the source is allowed to be fetched.

    04

    Step 2: create the asynchronous video job

    Create the video only after the source upload succeeds. The required `userPrompt` can contain up to 12,000 characters, but length is not a substitute for a testable brief. State the audience, source boundary, intended duration, aspect ratio, language, mandatory sequence, and forbidden claims. The example requests 30 seconds and 16:9 explicitly instead of relying on automatic choices. The response arrives as HTTP 202 with `videoId`, `status`, and `createdAt`. The official HTTP Semantics specification defines 202 as accepted for processing, not completed. It does not mean the video is downloadable or approved.

    curl -X POST https://api.tapvid.ai/api/public/v1/video/create \
      -H "Authorization: Bearer ${TAPVID_API_KEY}" \
      -H "Content-Type: application/json" \
      -d '{
        "materialIds": ["MATERIAL_ID_FROM_UPLOAD"],
        "userPrompt": "Create a concise 30-second English explainer for developers. Stay faithful to the supplied source and do not invent claims.",
        "title": "TapVid API developer explainer",
        "aspectRatio": "16:9",
        "duration": "30s",
        "language": "en"
      }'
    Redacted REST API timeline showing HTTP 200 upload, HTTP 202 create, running status, and a TLS reset during polling
    Redacted REST API timeline showing HTTP 200 upload, HTTP 202 create, running status, and a TLS reset during polling
    TapVid REST flow from HTTPS source and HTTP 202 job through status polling to a signed download URL
    TapVid REST flow from HTTPS source and HTTP 202 job through status polling to a signed download URL

    Persist `videoId` before the next network call. This one line is the most important production change identified by the controlled test. A process can crash after create and before its first status response. If the ID exists only in memory, the application cannot resume and may create a second paid job. Store the ID beside your own request ID, material IDs, prompt revision, requested settings, and user. The status endpoint expects the query parameter `video_id`, while the create response uses camel-case `videoId`. Copy the current official wire names exactly instead of normalizing them from memory.

    05

    Step 3: persist, poll, and request the download

    Poll `GET /video/status` using the accepted ID and respect `pollAfterSeconds`. The documented terminal states are `completed` and `failed`; intermediate states include `queued` and `running`. Progress is a fraction from 0 to 1, not an estimated time remaining. Once completed, poll once more if `creditsUsed` is still null because settlement can follow the terminal update. Then request `GET /video/download` with resolution, watermark, and subtitle options. The signed `downloadUrl` expires in about one hour. Store the durable video ID, not the signed URL, and refresh the URL when a user needs it again.

    import { writeFile } from 'node:fs/promises'
    
    const apiKey = process.env.TAPVID_API_KEY
    if (!apiKey) throw new Error('TAPVID_API_KEY is required')
    
    const base = 'https://api.tapvid.ai/api/public/v1'
    const headers = { Authorization: `Bearer ${apiKey}` }
    
    async function request(path, init = {}, { attempts = 1 } = {}) {
      let lastError
      for (let attempt = 1; attempt <= attempts; attempt += 1) {
        try {
          const response = await fetch(`${base}${path}`, {
            ...init,
            headers: { ...headers, ...init.headers },
          })
          const data = await response.json()
          if (response.ok) return { response, data }
          if (response.status !== 429 && response.status < 500) {
            const error = new Error(`HTTP ${response.status}: ${data.code ?? 'unknown'}`)
            error.retryable = false
            throw error
          }
          lastError = new Error(`retryable HTTP ${response.status}`)
        } catch (error) {
          if (error?.retryable === false) throw error
          lastError = error
        }
        if (attempt === attempts) break
        await new Promise((resolve) => setTimeout(resolve, attempt * 1000))
      }
      throw lastError
    }
    
    const { data: material } = await request('/materials', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ url: 'https://tapvid.ai/api-mcp' }),
    })
    
    const { response: createResponse, data: video } = await request('/video/create', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        materialIds: [material.materialId],
        userPrompt: 'Create a concise 30-second English explainer for developers. Stay faithful to the source.',
        title: 'TapVid API developer explainer',
        aspectRatio: '16:9',
        duration: '30s',
        language: 'en',
      }),
    })
    
    if (createResponse.status !== 202) throw new Error('Expected 202 Accepted')
    
    // Persist before the next network call. A lost poll must not cause a duplicate create.
    await writeFile('.tapvid-job.json', JSON.stringify({ videoId: video.videoId }))
    
    let status
    for (let poll = 0; poll < 180; poll += 1) {
      const result = await request(
        `/video/status?video_id=${encodeURIComponent(video.videoId)}`,
        {},
        { attempts: 4 },
      )
      status = result.data
      if (status.status === 'completed' || status.status === 'failed') break
      await new Promise((resolve) =>
        setTimeout(resolve, Math.max(status.pollAfterSeconds ?? 5, 5) * 1000),
      )
    }
    
    if (!status) throw new Error('No status received')
    if (status.status === 'failed') throw new Error(status.error?.code ?? 'generation_failed')
    if (status.status !== 'completed') throw new Error('Polling timeout; resume with the saved videoId')
    
    const query = new URLSearchParams({
      video_id: video.videoId,
      resolution: '1080P',
      watermark: 'true',
      subtitle: 'false',
    })
    const { data: download } = await request(`/video/download?${query}`, {}, { attempts: 4 })
    console.log({ status: download.status, expiresAt: download.expiresAt })

    The Node.js example wraps reads in bounded retries and writes the accepted video ID to disk before polling. In a real service, replace the local JSON file with a database row and use a queue worker. The helper retries network errors, HTTP 429, and server errors. It does not retry a normal 400 or 401 as if time will repair bad arguments or credentials. The 180-poll ceiling creates a clear terminal condition for the worker. If that ceiling is reached, the code keeps the ID and reports a resumable timeout instead of submitting another create request.

    06

    What the live REST test revealed

    The August 7, 2026 REST test used the same source, prompt, 30-second duration, 16:9 ratio, and English language as the MCP test. Material upload returned HTTP 200 in about 1.4 seconds. Create returned HTTP 202 and queued in about 0.3 seconds. The first running state appeared at about 81 seconds. At about 331 seconds the job still reported running at 50 percent. The local Node process then received `ECONNRESET` before a TLS connection was established. That was a polling-client failure, not a documented video-job failure.

    Redacted REST API timeline showing HTTP 200 upload, HTTP 202 create, running status, and a TLS reset during polling
    Redacted REST API timeline showing HTTP 200 upload, HTTP 202 create, running status, and a TLS reset during polling
    Redacted REST API timeline showing HTTP 200 upload, HTTP 202 create, running status, and a TLS reset during polling
    Redacted REST API timeline showing HTTP 200 upload, HTTP 202 create, running status, and a TLS reset during polling

    The first test script kept the private video ID only in process memory, so after the process exited it could not resume the accepted job. No duplicate job was created. The account usage counter had already increased from 90 to 180 credits across the MCP and REST runs, matching 90 credits per create and the approved total ceiling. This is why the final sample persists the ID before polling and gives GET requests bounded retry. It is also why this article does not claim that the REST run produced a downloadable file in 10 minutes. The evidence supports fast request acceptance, not a fixed render-time promise.

    07

    Handle API errors without duplicating spend

    Handle errors according to what they mean. `unauthorized` calls for checking or revoking the key. `invalid_request` calls for correcting fields. `payload_too_large` calls for reducing materials. `insufficient_credits` calls for stopping and getting authorization before changing a limit. `rate_limited` calls for honoring `Retry-After`. `internal_error` and transport failures can receive bounded retry. `invalid_state` on download usually means generation or export is not ready. A duplicate create within five seconds may be rejected, but that is not a complete idempotency strategy for crashes that occur later.

    Code or conditionRetry?Correct response
    `unauthorized`NoFix or revoke the key
    `invalid_request`NoCorrect the request body or enum
    `insufficient_credits`NoStop and request spending authority
    `rate_limited`YesHonor `Retry-After` and back off
    `internal_error` or network resetBoundedRetry the safe read and preserve job state
    Lost response after createDo not recreateResume status with the persisted video ID

    08

    Production checklist for a reliable integration

    A reliable integration needs more than a working happy-path snippet. Store secrets server-side. Persist accepted IDs atomically. Record status transitions, request latency, generation latency, credits, and safe error codes. Add a maximum poll window and a resumable state. Separate source upload permission, generation-spend permission, export permission, and publication permission. Refresh signed URLs rather than storing them as permanent assets. Test both 429 and network resets. Show users the last confirmed state. Finally, review the generated explainer for source fidelity, actual duration, scene order, caption readability, audio, rights, and brand before external release.

    • API key stays in a server-side secret store and never enters client bundles or logs.
    • Material and video IDs are written atomically before the next network request.
    • Create, status, and download requests have separate latency and error metrics.
    • Polling honors `pollAfterSeconds`, has jittered backoff for failures, and has a resumable timeout.
    • The worker distinguishes retryable reads from credit-spending duplicate writes.
    • Signed download URLs are refreshed on demand and not treated as permanent storage.
    • Credits and terminal status are recorded without secrets or private URLs.
    • A person reviews factual fidelity, duration, rights, brand, and final publication.

    09

    Use the API for finished explainers, not random clips

    Use this text to video API when the job is to turn approved content into a coherent explainer with multiple scenes, narration, motion, and a downloadable output. Do not describe it as a raw model benchmark or promise the visual behavior of a cinematic prompt-to-clip engine. If you want to explore the prompt conversationally, the companion Claude and TapVid MCP tutorial shows the same source and brief through MCP. If you want durable application control, keep the REST flow here and review the current TapVid API and MCP overview before shipping.

    10

    Frequently asked questions

    Will the finished video always be ready in 10 minutes?

    No. The four-operation integration can be built quickly, but generation and export are asynchronous. The controlled MCP run took about 28 minutes to reach completed, and the REST poller lost its connection before terminal status.

    What does HTTP 202 mean?

    It means the create request was accepted for asynchronous processing. Persist the returned videoId and poll status; it does not mean the video is complete.

    How often should I poll?

    Use the pollAfterSeconds value returned by status. Add bounded retry for transient failures and an overall timeout that can resume from the stored video ID.

    How long does the download URL last?

    The current documentation says approximately one hour. Request a fresh signed URL when needed instead of treating it as permanent storage.

    Can I remove the watermark?

    The export option defaults to watermark on. Removing it requires an active subscription according to the current documentation.

    Kenneth Chen

    Written and edited by

    Kenneth Chen

    GTM Manager, TapVid | SEO · GEO · Growth Engineering

    Kenneth Chen invites you to join the conversation with fellow video creators on Discord.

    Join Kenneth on Discord →
    Build with TapVid API

    Use the materials you already have

    Turn them into a clear, publishable video

    Keep reading

    Related stories

    Claude planning cards connected through secure MCP tools to a TapVid motion-graphics video canvas
    How-to·13 min read

    Claude Video Generation: How to Make Motion Graphics with TapVid MCP

    A hands-on Claude and TapVid MCP tutorial with a verified Claude Code connection, a real AI-client tool call, a 30-second motion-graphics brief, and an honest production test.

    Aug 7, 2026

    Claude Video Generation: How to Pair Claude with Seedance 2.5 or TapVid
    Workflow·12 min read

    Claude Video Generation: Seedance 2.5 or TapVid?

    Claude video generation needs a rendering tool. Learn when to pair Claude with Seedance 2.5 or TapVid, with prompts and a practical workflow.

    Aug 8, 2026

    Build faster motion without visual noise
    Motion Graphics·10 min read

    Text Animator Techniques: Build Faster Motion Without Visual Noise

    A practical text animator framework for teams that need readable, high-impact video messaging.

    Apr 16, 2026

    In this article

    1. 01What a text to video API means in this tutorial
    2. 02Know the contract before writing code
    3. 03Step 1: upload a public URL or file
    4. 04Step 2: create the asynchronous video job
    5. 05Step 3: persist, poll, and request the download
    6. 06What the live REST test revealed
    7. 07Handle API errors without duplicating spend
    8. 08Production checklist for a reliable integration
    9. 09Use the API for finished explainers, not random clips
    Summarize withAPI & MCP →
    ChatGPTPerplexityTapVidClaudeGeminiGrok
    1. What a text to video API means in this tutorial2. Know the contract before writing code3. Step 1: upload a public URL or file4. Step 2: create the asynchronous video job5. Step 3: persist, poll, and request the download6. What the live REST test revealed7. Handle API errors without duplicating spend8. Production checklist for a reliable integration9. Use the API for finished explainers, not random clips

    Ready to create your first video?

    Join thousands of product teams using AI to create professional videos in minutes.

    Your first video in under 5 minutes →Book a demo →
    Tapvid

    TapVid turns prompts, docs, and scripts into production-ready videos with AI. No editor, no crew, no timeline.

    TikTokInstagramXDiscordYouTube

    TapVid

    Features

    AI Explainer Video GeneratorAI Motion Graphics GeneratorAI Product Demo Video GeneratorAI Product Video GeneratorTalking Head Video EnhancerText to Video AIText to Motion GraphicsAnimated Video MakerAnimated Explainer Video MakerKinetic Typography GeneratorAnimated Chart MakerAnimated Collage MakerFree AI Video Generator

    Convert to Video

    Image to VideoPDF to VideoPPT to VideoArticle to VideoBlog to VideoURL to VideoScript to VideoGoogle Slides to VideoWord to Video

    Use Cases

    SaaS Explainer VideoProduct Launch Video MakerAI Ad Video GeneratorDocumentary Video MakerAnimated Social Media Video MakerInfographic Video MakerWhiteboard Animation MakerEducational VideoTutorial VideoCustomer OnboardingHelp Center VideoAPI Docs Video

    Solutions

    Explainer VideoProduct Demo VideoMeeting Recap VideoWebinar ClipsMarketing VideoFeature AnnouncementCompetitive ComparisonNewsletter VideoLanding Page VideoInvestor Pitch Video

    Featured Guides

    Best Faceless YouTube NichesCollage Animation Guide

    Company

    All FeaturesAboutBlogPricing

    © 2026 TapVid. All rights reserved.

    Privacy
    Terms of Service