# TikTok Transcript API Official documentation: https://tiktoktranscriptapi.com/docs # Getting started Build your first TikTok transcript integration with an account, an API key, and one public video URL. The API creates a background job and returns an ID. You use that ID to retrieve the transcript when processing finishes. ## Get your API key [Create an account](/sign-in) using your email address and the one-time code sent to your inbox. New verified accounts receive 100 free credits. You do not need to enter a card to try the API. Open **API Keys** in your dashboard, enter a recognizable name, and create a key. Copy the complete value immediately; it is shown once. Store it in a server environment variable named `TIKTOK_API_KEY`. Keep it out of browser code, public repositories, and screenshots. ## Request a transcript Use a TikTok video you own or have permission to process. Replace the example URL below with a real, publicly playable video. The request reserves one credit and transcribes up to 20 minutes. ```bash curl https://tiktoktranscriptapi.com/api/v1/transcriptions \ -H "Authorization: Bearer $TIKTOK_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: my-first-tiktok-request" \ -d '{"url":"https://www.tiktok.com/@creator/video/VIDEO_ID"}' ``` The response contains `data.id` and `data.status_url`. Save the ID before doing anything else. A successful submission usually returns HTTP 202; this means processing has started, not that the transcript is complete. ## Retrieve the result Wait a few seconds, then replace JOB_ID with your returned ID: ```bash curl https://tiktoktranscriptapi.com/api/v1/transcriptions/JOB_ID \ -H "Authorization: Bearer $TIKTOK_API_KEY" ``` Read `data.status`. While it is `processing`, wait before checking again. A `completed` result includes text and timestamped segments. A `failed` result includes an error and releases the reserved credit. Status checks do not consume credits. ## Continue building The [API reference](/docs/api) explains every endpoint, response field, limit, and error. Use the [integration guides](/docs/guides) for practical workflow patterns. To connect an AI tool, read [MCP integration](/docs/mcp). Your requests appear in the [dashboard](/dashboard), where you can review account activity and remaining credits. Use the API response to retrieve the completed transcript text and timestamps. --- # TikTok Transcript API reference Use the TikTok Transcript API to turn the speech in a public TikTok video into text your application can work with. Submit one video URL, keep the returned job identifier, and retrieve the transcript after background processing finishes. Completed results include readable text and timestamped segments. This reference covers the authenticated developer API. The free website tool also has a guest flow, documented separately below. Both process public TikTok videos, but they use different authentication and allowances. Choose the developer API for application code, repeatable workflows, account activity, and paid usage. ## Base URL All developer requests use HTTPS: ```text https://tiktoktranscriptapi.com/api/v1 ``` Requests and responses use UTF-8 JSON. Set `Content-Type: application/json` when sending a body and include an `Authorization` header on every authenticated request. Call the API from your server, command-line tool, or a trusted integration service. Keep your API key away from browser bundles and public forms. The examples use environment variables for secrets. A name such as JOB_ID or VIDEO_ID is a placeholder, not a working resource. Replace it with the identifier returned by your own request or the ID of a real video you are authorized to process. ## Endpoints | Method | Path | Purpose | Credit cost | | --- | --- | --- | --- | | POST | `/transcriptions` | Submit a public TikTok video | One credit reserved per new job | | GET | `/transcriptions/{id}` | Retrieve a job and its result | No credit charge | | GET | `/transcriptions?limit=20` | List recent jobs in your account | No credit charge | | GET | `/credits` | Retrieve your available balance and plan | No credit charge | | GET | `/openapi` | Download the machine-readable API specification | No authentication or credit charge | The API operates on individual public videos. It does not discover videos, search hashtags, crawl profiles, retrieve comments, or bypass account permissions. If your workflow begins with a collection of URLs, select each video in your own application and submit it as an individual job. ## Authentication Create an API key in [your dashboard](/dashboard/keys). Give it a name that identifies the application or environment using it. The secret begins with `tt_live_` and is displayed once. The dashboard retains a short prefix so you can recognize the key later, but it cannot show you the original secret again. Include the key in a bearer authorization header: ```bash export TIKTOK_API_KEY='YOUR_API_KEY' curl https://tiktoktranscriptapi.com/api/v1/credits \ -H "Authorization: Bearer $TIKTOK_API_KEY" ``` Every active key belongs to one account. Keys for the same account share the credit balance, request rate, job concurrency, and transcript history. Creating a new key does not create an additional allowance. A key can submit requests and read the account's transcripts, so treat it as an application secret. Accounts can keep up to ten active keys. Use separate keys for independent integrations so one can be revoked without interrupting the others. If a key is exposed, revoke it, create a replacement, update your server secret, and verify a request using the new value. Requests with a revoked key return HTTP 401 immediately after revocation is recorded. The account dashboard uses a secure sign-in session established through an email code. That browser session is not the developer API credential. Use bearer keys for API clients, even if the same browser is already signed in to the website. ## Quick start The following request submits a video and assigns a caller-generated idempotency key. Reuse that key if a network failure leaves you unsure whether the request was accepted. Use a new key for a genuinely new transcription request. ```bash curl --fail-with-body \ https://tiktoktranscriptapi.com/api/v1/transcriptions \ -H "Authorization: Bearer $TIKTOK_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: campaign-brief-video-001" \ -d '{"url":"https://www.tiktok.com/@creator/video/VIDEO_ID"}' ``` A newly accepted request returns HTTP 202: ```json { "data": { "id": "aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee", "status": "processing", "status_url": "/api/v1/transcriptions/aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee", "credits_reserved": 1, "reused": false } } ``` Wait at least a few seconds, then request the returned status URL with the same account's API key. The example identifier above is illustrative. A real identifier comes from your own create response. Processing speed depends on the source video, access conditions, audio length, and current queue. ## Create a transcript Send `POST /transcriptions` with a JSON object containing `url`. This call validates the source, reserves a credit, creates a job, and queues the video for processing. The HTTP response does not wait for the full transcript. | Field | Type | Required | Meaning | | --- | --- | --- | --- | | `url` | string | Yes | One public TikTok video URL; maximum 2,048 characters | ```json { "url": "https://www.tiktok.com/@creator/video/VIDEO_ID" } ``` The request body must be no larger than 16 KiB. A JSON object is required; a bare string, array, malformed JSON, or an empty body is rejected. Extra request properties do not enable additional processing options. The currently supported input is the video URL. A successful create response includes the job ID, its current status, a relative status URL, whether the request reused an earlier job, and the number of credits newly reserved by this call. The HTTP `Location` header also points to the status URL. Store the job ID together with your own source record so you can reconnect the result to the correct task. Each new job covers up to the first 20 minutes of one video's audio. This limit applies to the trial, monthly plan, and annual plan. It is a per-video processing limit, not a guarantee that every accepted URL will produce 20 minutes of speech. Shorter videos return only their available content. The service can process a maximum of five jobs at once per account. If that limit is reached, wait for a current job to finish. Listing recent jobs shows the last synchronized status; retrieving an individual job refreshes its status from processing. The dashboard and background reconciliation also refresh completed and failed work. ## Supported TikTok links Use a canonical public video URL whenever it is available: ```text https://www.tiktok.com/@creator/video/1234567890123456789 ``` Active public share links on `vm.tiktok.com` and `vt.tiktok.com` are also accepted. They must resolve to a video that the processing service can access. A short link can become invalid after it is shared, so retain the original full video URL in your source system when possible. The server checks the hostname and video path before creating a job. A profile page, hashtag page, search result, collection, image-only post, or a URL on another platform is not an individual supported video input. A lookalike hostname such as `tiktok.com.example.org` does not qualify as a TikTok domain. A syntactically valid URL can still fail during processing. The video may have been removed, made private, restricted to signed-in viewers, or blocked from access in the processing environment. The source must be available without sharing a personal TikTok login. The API does not accept your TikTok password, cookies, or account tokens. Submit media you own or are authorized to process. If you are developing a customer-facing application, explain this requirement in your upload or URL submission flow. The transcript output should remain associated with the video and the permissions under which you obtained it. ## Idempotent requests The optional `Idempotency-Key` header makes retries safe. The key identifies one logical create operation within your account. Use 8–128 characters consisting of letters, numbers, underscores, hyphens, periods, or colons. A UUID is a convenient choice. ```bash curl https://tiktoktranscriptapi.com/api/v1/transcriptions \ -H "Authorization: Bearer $TIKTOK_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: 7d1729c9-659a-4610-920a-12b4ce0d9829" \ -d '{"url":"https://www.tiktok.com/@creator/video/VIDEO_ID"}' ``` Repeating the same key with the same URL returns the original job and does not reserve another credit. The reused response returns HTTP 200 and sets `reused` to true and `credits_reserved` to zero. A repeated key with a different URL returns HTTP 409, because changing the input would make the operation ambiguous. Without an idempotency key, every accepted POST is a separate job. Submitting the same URL twice can therefore consume two credits. URL equality alone is not a deduplication rule. If your workflow retries requests, generate the key before making the first network call and save it with the pending operation. Use the original key only to recover the original request. To intentionally run a video again—for example, after the source becomes publicly available—start a new logical operation with a new key. A failed job remains the result of its original operation; retrying its idempotency key does not create a replacement job. ## Retrieve a transcript Send `GET /transcriptions/{id}` using a key from the account that created the job. This endpoint returns the current state and, on success, the full result. ```bash curl https://tiktoktranscriptapi.com/api/v1/transcriptions/JOB_ID \ -H "Authorization: Bearer $TIKTOK_API_KEY" ``` A completed response has this shape: ```json { "data": { "id": "aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee", "status": "completed", "filename": "TikTok video", "created_at": "2026-09-07T09:00:00.000Z", "duration_seconds": 8, "text": "Start with a clear question. Show the process, then share what you learned.", "segments": [ { "start": 0, "end": 2.4, "text": "Start with a clear question." }, { "start": 2.4, "end": 8.2, "text": "Show the process, then share what you learned." } ] } } ``` | Field | Type | Meaning | | --- | --- | --- | | `id` | string | Stable transcript job identifier | | `status` | string | `processing`, `completed`, or `failed` | | `filename` | string | Display name assigned to the imported video | | `created_at` | string | Job creation timestamp in ISO 8601 format | | `duration_seconds` | number or null | Duration reported by the processor when available | | `text` | string or null | Full transcript when completed; null before completion or after failure | | `segments` | array or null | Timed transcript segments when completed and available | | `error` | object | Present when processing fails; contains a code and message | Segment start and end values are seconds relative to the source audio. They can include fractional seconds. Do not interpret them as Unix timestamps or milliseconds. Use the segment end field directly when constructing subtitles; do not assume every segment has the same length or ends when the next one begins. The filename is a display field, not an authentication or ownership signal. Use the job ID for lookups. Result text can contain punctuation, line breaks, non-English characters, or words you did not expect. Render it as text in your application, never as trusted HTML. A completed result may contain little text if the video has little recognizable speech. Background music, overlapping voices, rapid cuts, and noise can affect transcription quality. Review quotes and captions before publishing them or using them as a source of record. ## Job lifecycle A new job begins in `processing`. Your application should show a pending state and retain the ID even if the user navigates away. Continue reading the same job rather than creating another request to check progress. The terminal states are `completed` and `failed`. A completed job has finished processing and its output can be saved. A failed job has stopped processing; the result describes the failure in the `error` object and the reservation is released. Stop polling when either terminal state appears. ```json { "data": { "id": "aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee", "status": "failed", "filename": "TikTok video", "created_at": "2026-09-07T09:00:00.000Z", "duration_seconds": null, "text": null, "segments": null, "error": { "code": "transcription_failed", "message": "This video could not be processed. Check that it is public and playable. The reserved credit has been released." } } } ``` A failed transcription is different from an unsuccessful HTTP status request. For example, an HTTP 503 while checking a job says the status could not be retrieved at that moment. It does not establish that the underlying video failed. Keep the ID and retry the read after a delay. The API does not currently expose job cancellation, webhooks for transcript completion, or a percentage-complete field. Disconnecting your client or closing the dashboard does not cancel work already queued. Build your interface around a pending state and the two terminal states rather than inventing a progress percentage. ## List recent transcripts Use the list endpoint to recover recent IDs or display account history: ```bash curl 'https://tiktoktranscriptapi.com/api/v1/transcriptions?limit=20' \ -H "Authorization: Bearer $TIKTOK_API_KEY" ``` The optional `limit` parameter defaults to 20 and accepts integers from 1 to 100. Results are ordered newest first. The response contains a `data` array with `id`, `status`, `source_url`, and `created_at` for each job. ```json { "data": [ { "id": "aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee", "status": "completed", "source_url": "https://www.tiktok.com/@creator/video/VIDEO_ID", "created_at": "2026-09-07T09:00:00.000Z" } ] } ``` An empty array is a valid result for an account with no jobs. The list does not include transcript text or segment arrays. Retrieve a specific job to obtain its output and refresh its processing status. Because list statuses reflect the latest synchronization, a recently finished job may still appear as processing until it is refreshed. This endpoint is a recent-history view, not a paginated archival export. It does not currently accept a cursor, offset, or date filter. Keep the job IDs and completed output your application needs in your own storage instead of treating the latest 100 records as a complete long-term history. ## Credits and plans New verified accounts start with 100 free API credits. A new transcript reserves one credit at submission. Successful processing uses that credit. If the job fails, reconciliation releases the reserved credit to the balance it came from, subject to the expiration of monthly allowance. The monthly plan costs $5 per month and grants 1,000 credits each month. The annual plan costs $54 per year, equivalent to $4.50 per month, and also grants 1,000 credits each month. Annual billing does not grant all twelve months of credits at once. Monthly allowances refresh on the subscription's monthly anniversary while paid access remains active. Unused monthly credits do not roll over. Trial credits and purchased top-up credits are tracked separately. The service uses active monthly allowance first, then top-up credits, then trial credits. A failed job returns its reservation to the same bucket. If that monthly grant has already expired, releasing a reservation does not increase the new month's allowance. Subscribers can buy 1,000 additional credits for $2.50 on the monthly plan or $1.50 on the annual plan. An active subscription is required to purchase a top-up. Top-up credits remain available after cancellation. Account rate limits follow the currently active plan, so an account without an active subscription uses the trial rate even if top-up credits remain. Retrieve your available credits programmatically: ```bash curl https://tiktoktranscriptapi.com/api/v1/credits \ -H "Authorization: Bearer $TIKTOK_API_KEY" ``` The balance endpoint returns `available`, `trial`, `monthly`, `topup`, `plan`, and `monthly_refresh_at` inside `data`. Availability is the current sum of the applicable balances. A processing job has already reserved its credit, so that credit is not included in the available total. Purchases occur through Stripe Checkout linked from your authenticated dashboard. Credit activation depends on verified payment status; returning to a success page alone does not establish payment. Subscription status and top-up grants are reconciled from Stripe, with duplicate event handling to avoid awarding the same purchase twice. ## Rate and concurrency limits | Account | API requests per minute | Concurrent processing jobs | | --- | --- | --- | | Free trial or no active subscription | 20 | 5 | | Monthly subscription | 200 | 5 | | Annual subscription | 300 | 5 | Create calls and authenticated result, list, and balance reads count toward the request rate. Reading status does not consume a transcript credit, but it still uses request capacity. The allowance is shared across your account's keys and supported interfaces; adding more keys does not increase it. The rate window follows UTC calendar minutes. When you reach a limit, the API responds with HTTP 429 and a `Retry-After` header. Wait for that many seconds before retrying. Avoid immediately retrying failed requests from several workers at once, since this can create another burst at the next window boundary. Concurrency limits protect processing capacity independently of the request rate. A plan can allow 200 requests per minute while still limiting the account to five processing jobs. Use a queue in your application, refresh the oldest pending jobs, and release local queue slots only when jobs reach a terminal state. For polling, a delay of three to five seconds is a reasonable starting point for one job. Increase it when you have several jobs pending, and use a maximum waiting time appropriate to your interface. Store the job ID so the user can return later if your interactive wait ends. ## Error handling Transport and validation errors use an HTTP status and a JSON error object: ```json { "error": { "code": "invalid_source", "message": "Provide one public TikTok video URL in the url field." } } ``` | HTTP status | Common code | Recommended response | | --- | --- | --- | | 400 | `invalid_json` | Send a valid JSON object | | 400 | `invalid_source` | Check that the URL identifies a supported public video | | 400 | `invalid_limit` | Use an integer between 1 and 100 | | 400 | `invalid_idempotency_key` | Correct the idempotency-key format | | 401 | `invalid_api_key` | Check the bearer header and whether the key was revoked | | 402 | `credits_exhausted` | Add credits or choose a paid plan | | 404 | `not_found` | Check the job ID and the account that created it | | 409 | `idempotency_conflict` | Reuse the original input or start a new logical operation | | 413 | `body_too_large` | Send a JSON body smaller than 16 KiB | | 415 | `unsupported_media_type` | Set Content-Type to application/json | | 429 | `rate_limited` | Wait according to Retry-After | | 429 | `concurrency_limit` | Wait for current processing jobs to finish | | 503 | `service_unavailable` | Keep your operation ID and retry after a delay | Your application should branch on the HTTP status and stable code rather than matching the exact English message. Messages explain the current issue and may become more specific over time. Never display a raw exception or secret-bearing request header to the person using your application. A 404 also protects account boundaries: a key cannot retrieve another account's transcript by guessing its ID. If a known job appears missing, check the account associated with the key and compare the ID with your saved create response. Avoid creating another transcript until you have ruled out a simple account or identifier mismatch. ## Retry strategy Retry read requests after temporary network failures or HTTP 503 responses using a bounded delay. Start with a few seconds, increase the wait after repeated failures, and stop after your chosen deadline. Keep the job ID so a later request can resume the workflow without starting a new transcript. For HTTP 429, use the server's `Retry-After` value. For validation, authentication, and credit errors, fix the underlying issue before making another request. Repeatedly sending the same invalid URL or revoked key will not resolve the problem. For create requests, use an idempotency key before enabling automatic retries. A timeout can occur after the job is committed but before your client receives the response. Repeating the same logical operation with its original key returns the existing job instead of reserving another credit. Do not automatically create a new job after a transcription reaches `failed`. The source may still be inaccessible, and repeating it can waste processing attempts. Ask the caller to check the video's public availability or choose a different source. If they intentionally retry, create a new operation ID. ## JavaScript example This Node.js example reads the API key and video URL from environment variables, submits a job, and polls for a terminal state. It keeps the create idempotency key stable for retry attempts. Use Node.js with built-in fetch support. ```javascript import { randomUUID } from 'node:crypto'; import { setTimeout as delay } from 'node:timers/promises'; const base = 'https://tiktoktranscriptapi.com/api/v1'; const key = process.env.TIKTOK_API_KEY; const video = process.env.TIKTOK_VIDEO_URL; if (!key || !video) throw new Error('Set TIKTOK_API_KEY and TIKTOK_VIDEO_URL'); async function api(path, options = {}) { for (let attempt = 0; attempt < 4; attempt++) { let response; try { response = await fetch(base + path, { ...options, headers: { Authorization: `Bearer ${key}`, 'Content-Type': 'application/json', ...options.headers, }, signal: AbortSignal.timeout(30000), }); } catch (error) { if (attempt === 3) throw error; await delay(2000 * (attempt + 1)); continue; } if ((response.status === 429 || response.status >= 500) && attempt < 3) { const retry = Number(response.headers.get('retry-after')); await delay((Number.isFinite(retry) && retry > 0 ? retry : 3 * (attempt + 1)) * 1000); continue; } const body = await response.json(); if (!response.ok) throw new Error(`${response.status}: ${body.error?.message}`); return body.data; } throw new Error('Request retries exhausted'); } const operationId = randomUUID(); const created = await api('/transcriptions', { method: 'POST', headers: { 'Idempotency-Key': operationId }, body: JSON.stringify({ url: video }), }); console.log('Save this job ID:', created.id); const deadline = Date.now() + 10 * 60 * 1000; while (Date.now() < deadline) { await delay(5000); const job = await api(`/transcriptions/${created.id}`); if (job.status === 'completed') { console.log(job.text); break; } if (job.status === 'failed') throw new Error(job.error.message); } ``` The interactive polling deadline does not cancel the job. If the loop ends while processing continues, show the stored job ID and let your application retrieve it later. In a production worker, persist the operation and job IDs in durable storage instead of relying only on process memory. ## Python example This example uses `requests` for HTTP calls. It handles temporary response errors and uses the same operation key across create retries. Set your API key and source URL in the environment before running the script. ```python import os import time import uuid import requests base = 'https://tiktoktranscriptapi.com/api/v1' key = os.environ['TIKTOK_API_KEY'] video = os.environ['TIKTOK_VIDEO_URL'] client = requests.Session() client.headers.update({'Authorization': f'Bearer {key}'}) def api(method, path, **kwargs): for attempt in range(4): try: response = client.request(method, base + path, timeout=30, **kwargs) except requests.RequestException: if attempt == 3: raise time.sleep(2 * (attempt + 1)) continue if (response.status_code == 429 or response.status_code >= 500) and attempt < 3: retry_after = response.headers.get('Retry-After', '') wait = int(retry_after) if retry_after.isdigit() else 3 * (attempt + 1) time.sleep(max(1, wait)) continue body = response.json() if not response.ok: message = body.get('error', {}).get('message', 'Request failed') raise RuntimeError(f'{response.status_code}: {message}') return body['data'] raise RuntimeError('Request retries exhausted') operation_id = str(uuid.uuid4()) created = api('POST', '/transcriptions', headers={'Idempotency-Key': operation_id}, json={'url': video}) print('Save this job ID:', created['id']) deadline = time.monotonic() + 600 while time.monotonic() < deadline: time.sleep(5) job = api('GET', '/transcriptions/' + created['id']) if job['status'] == 'completed': print(job['text']) break if job['status'] == 'failed': raise RuntimeError(job['error']['message']) else: print('Still processing. Retrieve the saved job ID later.') ``` Treat the response as structured data. Save `text` when you need a readable transcript and `segments` when you need to attach quotes to timestamps. Handle null result fields before completion instead of assuming the first response already contains usable text. ## Text and subtitle exports The developer API returns JSON. Save the `text` field as a UTF-8 `.txt` file when you need a plain transcript. For subtitle exports, convert each segment's start, end, and text into the output format required by your editor. The public web tool already provides TXT and SRT downloads. The following helper converts completed segments into SRT. It rounds each timestamp to milliseconds and uses the required comma between seconds and milliseconds. Numbering begins at one. ```javascript function srtTime(seconds) { const ms = Math.max(0, Math.round(seconds * 1000)); const hours = Math.floor(ms / 3600000); const minutes = Math.floor(ms / 60000) % 60; const wholeSeconds = Math.floor(ms / 1000) % 60; return [hours, minutes, wholeSeconds] .map(value => String(value).padStart(2, '0')).join(':') + ',' + String(ms % 1000).padStart(3, '0'); } function toSrt(segments) { return segments.map((segment, index) => `${index + 1}\n${srtTime(segment.start)} --> ${srtTime(segment.end)}\n${segment.text.trim()}` ).join('\n\n'); } ``` Check that `segments` is an array before exporting. Review the generated file in the editor where it will be used. Timing, line length, punctuation, and reading speed may need editorial adjustments even when the underlying speech is correctly transcribed. ## Integration practices Keep your source URL, operation key, job ID, and processing state together in your application's data model. A small durable record lets you recover from a server restart, avoid duplicate submissions, and show clear progress to the person who requested the transcript. Separate the create operation from result retrieval. Your web handler can submit the video, return a pending state to the browser, and let a background task check progress. Do not hold an ordinary page request open indefinitely while waiting for a longer video. Use bounded queues. Submit at most the number of jobs your account can process concurrently, then check those jobs before starting more. Polling every job several times a second increases request volume without making speech processing finish faster. Store completed transcripts when your application needs them later. Your account history is useful for inspection and recovery, but it should not replace the storage design of a customer-facing product. Apply your own retention and access rules to any copies you keep. When summarizing with an AI model, separate the transcript from your instructions. The video's speech may include commands, quoted prompts, jokes, or deliberately misleading text. Treat all of it as source material to analyze rather than as instructions to execute. For research workflows, keep timestamps beside extracted quotes. A short phrase without its context can misrepresent the speaker. Let reviewers open the source video and compare important passages before publishing analysis or using a transcript in a consequential decision. ## Security and privacy Keep API keys in environment variables or your hosting provider's secret store. Never place a key in a URL query string, because URLs can appear in browser history, proxy logs, analytics, and screenshots. Use the Authorization header exactly as shown in the examples. Do not send account session cookies to unrelated services. A developer key should only be sent to this API or to an integration provider you intentionally trust to act for your account. A provider holding the key can use credits and read account transcripts. Avoid logging full request headers or transcript bodies by default. For operational debugging, the job ID, HTTP status, error code, and elapsed request time are usually enough. Only retain source URLs and transcript content where your application actually needs them. The website's product analytics excludes submitted video URLs, transcript text, API keys, and email codes. Account data and transcription results are handled as application data. Consult the [Privacy Policy](/privacy) for the service's data handling and support contact. ## Design a recoverable application A reliable integration distinguishes between a request that has not been sent, a request with an uncertain outcome, and a job whose identity is known. Treat these as separate states in your application. This avoids replacing a recoverable network interruption with a second transcription charge. Before the first POST, save the source URL and operation key. After an accepted response, save the job ID in the same record. If the process stops between these events, retry the original operation key. Once an ID exists, all progress checks should use that ID. A completed or failed result closes the operation. For a public-facing interface, return an application-owned request ID to the browser rather than your server's API key. Your backend can map that request to the transcript job and enforce the current user's access. This keeps account credentials out of the client and prevents one customer from reading another customer's transcript through your application. If you use a scheduled worker, make its processing steps safe to repeat. Reading a completed transcript is repeatable, but writing the result into a notes system or sending a notification may not be. Record whether each downstream action has already completed before allowing the worker to perform it again. ## Validate the output you use Treat each response according to its job state. A pending result with null text is normal; it should not be rendered as an empty finished transcript. Only run summarization or export code once status is completed. For a failed state, show the error and the source link rather than presenting an empty document as a success. Check types at your application's boundary. Segment arrays may be unavailable, and duration can be null. Preserve fractional seconds for timing calculations. When presenting a whole-number duration to a person, format a display value without changing the original segment times stored for later export. Do not depend on a particular number of segments or a fixed relationship between word count and duration. Different speech, silence, edits, and audio quality produce different segmentation. Your layout should handle one short segment, a longer transcript with many segments, and a completed result with very little speech. Transcripts can contain the same sensitive information that was spoken in the source video. If your application forwards text to another service, make that destination and purpose clear to your users. Apply the same access controls to generated summaries and exported files as you apply to the original transcript. ## Diagnose a stalled workflow Begin with the last confirmed step. If you have a job ID, retrieve it with the same account's key. If you only have an operation key, repeat the create request with the original source. If you have neither, check your application's request logs and the account's recent activity before submitting again. A job shown as processing in the recent list may simply need an individual status refresh. The list is optimized for recent account activity; it does not force every underlying job to refresh on every read. The individual result endpoint and the dashboard perform that synchronization. If the service returns rate-limited responses, reduce polling volume across the entire account. Several integrations using separate keys still share one rate window. A single worker with a small queue and a sensible delay is often easier to operate than many clients independently polling the same jobs. When contacting support about a stall, describe the sequence: whether create returned an ID, whether a status read succeeded, the most recent job state, and any HTTP error. This gives enough context to investigate without exposing your key or copying the entire transcript into an email. ## Guest website endpoints The public form uses `POST /api/transcribe-link` and `GET /api/transcriptions`. These are outside the `/api/v1` namespace and use a guest-session cookie. They are intended for the no-account website experience, which currently allows one free transcript daily, up to 20 minutes. A terminal client can preserve that session with a cookie jar: ```bash curl --cookie cookies.txt --cookie-jar cookies.txt \ https://tiktoktranscriptapi.com/api/transcribe-link \ -H 'Content-Type: application/json' \ -d '{"url":"https://www.tiktok.com/@creator/video/VIDEO_ID"}' curl --cookie cookies.txt \ https://tiktoktranscriptapi.com/api/transcriptions ``` The create response uses `transcriptionId` rather than `data.id`. The list response is an array of records containing `id`, `filename`, `status`, `text`, `durationSeconds`, and `segments`. Match the returned ID to your own job. Without the session cookie, the guest list is empty. Guest cookies do not authenticate the paid developer API. Developer keys do not replace guest cookies. Keep the two flows separate in your integration: use `/api/v1` when you need account credits, idempotency, and a stable application credential. ## Support If a request is not behaving as expected, include the endpoint, HTTP status, error code, approximate time, and job ID in your support message. Describe what you expected and what you received. Do not include API keys, session cookies, sign-in codes, or payment card details. Open [support](/contact), review the [billing guide](/docs/billing), or return to the [quickstart](/docs/getting-started). For agent integrations, the [MCP guide](/docs/mcp) explains how the same jobs and credits are exposed as tools. --- # MCP integration Give an AI application access to your TikTok transcript workflow through Model Context Protocol. The remote MCP endpoint exposes tools to create a transcript, retrieve a result, and list recent jobs. It connects to the same account, processing queue, and credit balance as the REST API. The integration is designed for clients that can connect to a remote Streamable HTTP server and attach an Authorization header. Use a dedicated API key for each client so you can revoke one connection without disrupting your other applications. The server does not require a local transcription process or a separate model installation. ## Connection details | Setting | Value | | --- | --- | | Server URL | `https://tiktoktranscriptapi.com/mcp` | | Transport | Streamable HTTP with JSON responses | | Authentication | Bearer API key | | Authorization header | `Authorization: Bearer YOUR_API_KEY` | | Protocol versions | `2025-06-18` and `2025-03-26` | | Server name | `tiktok-transcript-api` | The connection is stateless. The server returns each tool response as JSON and does not require an MCP session identifier. Transcript jobs themselves are durable and continue processing independently of the client connection. Closing an agent conversation does not cancel a job already submitted. The endpoint does not provide a standalone server-sent event stream. A GET request returns HTTP 405; normal tool requests use POST. This is different from the older HTTP+SSE transport. If a client asks for an SSE URL, choose its Streamable HTTP option instead. ## Create a dedicated key Sign in to [TikTok Transcript API](/sign-in), open [API Keys](/dashboard/keys), and create a key named for the client you are connecting. Copy it when it is first shown and save it in your client's protected credential settings. Keys are account credentials. The client holding a key can create transcripts and access the account's transcript results. Keep personal and shared team integrations separate when they should not have access to the same material. Do not embed a real key in a configuration file that will be committed publicly or distributed to other people. A new verified account includes 100 free credits, so you can test a connection before subscribing. Checking tool availability, reading a job, and listing recent jobs do not use transcript credits. Creating a new transcript reserves one credit, which is used on success and released on failure. ## Configure your client Many developer tools accept a configuration similar to the following. The exact file and property names depend on the client. Use its remote HTTP server settings and verify that it supports custom authentication headers. ```json { "mcpServers": { "tiktok-transcript": { "url": "https://tiktoktranscriptapi.com/mcp", "headers": { "Authorization": "Bearer YOUR_API_KEY" } } } } ``` Replace YOUR_API_KEY in the client's secret field or supported environment-variable interpolation. The literal placeholder will return HTTP 401. Avoid placing the key in the server URL: query strings may be retained in logs and browser history. After saving the connection, ask the client to refresh or discover its tools. The server should offer `create_transcript`, `get_transcript`, and `list_transcripts`. If no tools appear, check the transport, exact endpoint, header name, and key validity before testing with a video. This server currently uses static bearer keys and does not expose an OAuth authorization flow. A host that only accepts OAuth-based remote connectors cannot connect directly with these settings. Use a key-capable MCP host or call the REST API from your own application. Do not assume that a generic configuration example guarantees compatibility with every version of a named AI client. ## Available tools ### create_transcript Submit one public TikTok video. The response contains a job ID and the status URL. The tool reserves one account credit for a new job and covers up to 20 minutes of audio. | Argument | Required | Description | | --- | --- | --- | | `url` | Yes | A publicly playable TikTok video URL | | `idempotency_key` | No | A stable identifier for safe retries of this logical operation | ```json { "url": "https://www.tiktok.com/@creator/video/VIDEO_ID", "idempotency_key": "research-project-video-001" } ``` The same idempotency key and URL return the existing job instead of starting another one. A reused key with a different URL is rejected. Generate the key before the tool call when you need retry safety, and retain it along with the resulting job ID. The source must be an individual public video. The tool does not search TikTok, inspect account feeds, retrieve comments, or discover related videos. Give the agent an exact video URL selected by the user or by an authorized source in your own application. ### get_transcript Retrieve the current state and result of a job belonging to this account. Pass the identifier returned by `create_transcript`. ```json { "id": "aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee" } ``` A job can be processing, completed, or failed. A completed result includes readable text and segment timestamps. A failed result explains that processing could not finish and releases the reservation. The status read itself does not consume a transcript credit. Wait at least three seconds between checks. Keep polling bounded so an agent does not loop indefinitely. If the job is still processing at the end of an interactive session, save its ID and check again later. Do not create another transcript just to check progress. ### list_transcripts Retrieve recent jobs, newest first. The optional limit defaults to 20 and accepts integers from 1 through 100. ```json { "limit": 10 } ``` The list contains job IDs, source URLs, creation timestamps, and the latest synchronized statuses. It does not return full transcript text. Use `get_transcript` for a current status and completed result. An empty list means the account does not yet have matching recent work; it is not a connection failure. This tool gives the agent visibility into recent account activity. When connecting a shared AI workspace, consider whether every person using that connection should be able to access the account's transcripts. A separate account is appropriate when data ownership needs to be separate. ## A useful agent workflow A transcript-based research task starts with the user's authorized source URL and a clear output request. For example: > Transcribe this public TikTok video that I created. When it is ready, identify the opening hook, summarize the main explanation, and include timestamps for the strongest quotes. The agent submits the video through `create_transcript` and retains the returned ID. While processing continues, it should communicate a pending state. Once `get_transcript` returns a completed result, the agent can analyze the text and refer to segment times. The transcript service returns speech text; the AI host performs the summary, comparison, or analysis. A summary is not an additional API output field. If you need repeatable formatting, specify the structure in your application and validate the agent's output before displaying or storing it. For caption drafting, ask the host to preserve the speaker's meaning and distinguish verbatim text from rewritten captions. For research, ask it to keep quotes separate from its own interpretation. The underlying transcript and source timestamps provide a way to check the result. ## Example prompts **Review your own video.** Ask the agent to transcribe a supplied TikTok link, identify repeated phrases, and suggest a clearer opening. Have it quote the original wording before offering edits so you can compare the recommendation with what was actually said. **Prepare searchable notes.** Ask for a title, a brief outline, and a small set of tags grounded in the transcript. Include the job ID and source URL in your own notes system. This preserves the connection between the saved note and the video that produced it. **Draft subtitles.** Ask the host to use the returned segment times and produce a subtitle draft. Review line breaks, reading speed, and timing in your editing software. Automatic speech timing is useful as a starting point, but the final publishing pass remains an editorial task. **Compare authorized clips.** Supply specific video links and explain the comparison you want. Keep the queue within the account's concurrency limit and wait for each result. Ask the host to separate differences in spoken content from its own inference about the creators' intentions. These prompts are examples of work your host can perform after transcription. They do not expand the API's access to private content or add video search, account crawling, or comment retrieval. ## Test the protocol directly A direct HTTP request can help distinguish a client configuration issue from an invalid key. Start with an initialize request using a real API key in your environment. ```bash curl https://tiktoktranscriptapi.com/mcp \ -H "Authorization: Bearer $TIKTOK_API_KEY" \ -H 'Content-Type: application/json' \ -H 'Accept: application/json, text/event-stream' \ -d '{ "jsonrpc":"2.0", "id":1, "method":"initialize", "params":{ "protocolVersion":"2025-06-18", "capabilities":{}, "clientInfo":{"name":"my-client","version":"1.0.0"} } }' ``` The response includes the negotiated protocol version, server information, and tool capability. The client then sends an initialized notification and can discover tools. Notifications receive an empty HTTP 202 response. ```bash curl https://tiktoktranscriptapi.com/mcp \ -H "Authorization: Bearer $TIKTOK_API_KEY" \ -H 'Content-Type: application/json' \ -H 'Accept: application/json, text/event-stream' \ -H 'MCP-Protocol-Version: 2025-06-18' \ -d '{"jsonrpc":"2.0","method":"notifications/initialized"}' curl https://tiktoktranscriptapi.com/mcp \ -H "Authorization: Bearer $TIKTOK_API_KEY" \ -H 'Content-Type: application/json' \ -H 'Accept: application/json, text/event-stream' \ -H 'MCP-Protocol-Version: 2025-06-18' \ -d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}' ``` To request a transcript, send `tools/call` with the tool name and arguments. This creates real processing work and reserves one credit, so use a video you are authorized to process. ```bash curl https://tiktoktranscriptapi.com/mcp \ -H "Authorization: Bearer $TIKTOK_API_KEY" \ -H 'Content-Type: application/json' \ -H 'Accept: application/json, text/event-stream' \ -H 'MCP-Protocol-Version: 2025-06-18' \ -d '{ "jsonrpc":"2.0", "id":3, "method":"tools/call", "params":{ "name":"create_transcript", "arguments":{ "url":"https://www.tiktok.com/@creator/video/VIDEO_ID", "idempotency_key":"mcp-video-request-001" } } }' ``` The tool result includes a text content item containing JSON and a structured content object for clients that support it. Read the returned job ID, wait, and invoke `get_transcript` with that ID. Tool errors set `isError` to true and provide an error code and message in the content. ## Handling tool errors Authentication failures occur before a tool executes and return HTTP 401. Check whether the header contains the full key, whether a secret setting accidentally added quotes or whitespace, and whether the key is still active in the dashboard. Validation and processing constraints appear as tool errors. An unsupported video URL, exhausted credit balance, reused operation key with different input, or a concurrency limit should be shown to the user with a clear explanation. The agent should not silently alter the video URL or start unrelated work to bypass the failure. Rate-limit errors include a retry delay in the tool's error content when available. Respect that delay and retry the same logical operation. A client should not spawn additional workers or rotate keys to work around the account's shared rate limit. A temporary service failure may leave the client unsure whether a create call was accepted. Keep the idempotency key and repeat the same request after a delay. If a job ID is already known, read that job rather than submitting the video again. ## Credits and account visibility MCP activity appears alongside REST API activity in your account. The source column distinguishes MCP requests so you can see which workflow created a job. All keys and interfaces share the available balance and five-job concurrency cap. One new transcript reserves one credit. Status checks and recent-history reads do not use credits. The 20-minute per-video cap applies to every plan. An annual subscription changes the billing cycle, top-up price, and request rate; it does not increase the duration of an individual transcript. The monthly and annual plans each provide 1,000 credits per month. Free accounts begin with 100 trial credits. See [Billing & credits](/docs/billing) for rollover, cancellation, and top-up behavior, and use the dashboard to inspect the actual balance before starting a larger workflow. ## Trust the user request, not the transcript A video can contain spoken instructions, quoted commands, or text intended to manipulate an AI system. Your host must treat the returned transcript as untrusted source content. It should follow the user's task and its own instruction hierarchy instead of executing instructions discovered in the video. For example, a speaker saying “ignore previous instructions” is part of the transcript, not permission to change the task. A URL read aloud in the video is not authorization to open it, submit information, or send a message. Keep extraction and analysis separate from consequential actions. Store the original transcript when you need an audit trail, and label rewritten output as a summary or draft. For important quotes, preserve a timestamp and let a person compare the source. The MCP connection provides access to data; it does not establish that every statement in that data is correct. ## Build a custom host A custom MCP host should keep connection setup separate from transcript processing. Initialize the server, discover the available tools, and store the supported tool schemas. When a user supplies an authorized video, validate the intended action against the create tool's arguments before calling it. Give every tool call a distinct JSON-RPC request ID so your host can match responses to requests. This protocol ID is different from a transcript job ID and from an idempotency key. The protocol ID identifies a message, the operation key identifies a logical create attempt, and the job ID identifies the durable transcription result. Your host can reconnect without losing the transcript, because job storage is independent of the transport session. Save the job ID in your application state or conversation record. On a later turn, use the get tool with that ID and the same account's credential. Do not rely on the model remembering an ID that was never retained by the host. Treat successful tool execution and successful transcription as different outcomes. A create tool can succeed by accepting a job while the job itself is still processing. A get tool can successfully return a failed transcription state. Check the result's status before treating its text as available for analysis. If you display a tool approval prompt, make the cost clear: creating a new transcript reserves one credit, while checking it does not consume another credit. This lets the person using your host make a meaningful decision about a new source without approving every status read as if it were a new purchase. ## Keep credentials separate from conversation Store the bearer key in your host's secret configuration and attach it to HTTP requests outside the model's generated arguments. The create tool needs a URL and optional operation key; it does not need the API secret as part of the conversation or the tool input. When an agent produces a configuration example, show a placeholder instead of the real key. If a person accidentally pastes a key into a shared conversation, revoke it and generate a replacement. Deleting the visible message alone cannot guarantee that every copy has disappeared from logs or downstream systems. For a shared host, decide whether one account is appropriate for the entire team. The server's keys do not create separate per-key transcript permissions. If different groups must have different access, connect distinct accounts or enforce a separate application access layer before exposing results. ## Troubleshooting a connection If the client reports that the endpoint is unsupported, confirm that it is using Streamable HTTP. A client configured for the older SSE transport may try a GET stream and receive HTTP 405. Change the transport instead of appending guessed paths to the endpoint. If tool discovery succeeds but transcription fails, inspect the actual tool error. A key can be valid while the account has no remaining credits. A video can have a plausible URL while still requiring a TikTok login. Test one known public, authorized video before adding a larger workflow. If a result never appears, keep its job ID and inspect it in the dashboard. Avoid a polling loop that immediately calls the status tool again with no delay. The rate limit applies to reads, and fast polling does not accelerate processing. For help, include your MCP client's name, the transport setting, the tool name, the approximate request time, and the job ID. Do not send your API key or a screenshot that exposes its complete value. [Contact support](/contact) for integration assistance. --- # Integration guides Build around the API's asynchronous workflow: create a job, retain its identity, and retrieve the result. These patterns help turn a working example into a reliable application without adding unnecessary API calls. ## Keep one record per operation Store a record containing your source URL, a unique operation key, the transcript ID, and the latest processing state. The operation key is generated before submission and sent as `Idempotency-Key`. The transcript ID is filled in after the API accepts the request. If your worker loses the response, retry with the same operation key and source URL. If it already has a transcript ID, request that job. This distinction prevents a temporary connection problem from becoming duplicate processing. Keep the original source URL even after the transcript is saved. It helps your interface display a source link and gives reviewers context for quotes. Do not use a video title as the database key, because titles are display information and may not be unique. ## Build a bounded queue An account can process up to five jobs concurrently. Keep pending source records in your own queue, submit a small number, and check the accepted jobs until they finish. When one reaches completed or failed, release that local queue slot. The request rate also applies to status reads. Use delays between polls and consider the whole account's traffic when several services share it. Separate API keys help identify integrations, but they do not create separate rate allowances. If your interactive page stops waiting, retain the job ID and show a return path. A browser timeout does not mean the transcription was canceled. Your server can continue checking the result and make it available when the person returns. ## Turn a transcript into notes Use the completed text as source material for a notes or summarization step. Ask your model for a clear output format, such as a short summary, key claims, and timestamped quotes. Keep the transcript separate from the instruction describing what to produce. Validate that extracted quotes appear in the source text. A model can paraphrase while presenting the result as a quote, so preserve a distinction between direct quotation and interpretation. Where the wording matters, compare it with the original video. Store the summary and transcript separately. This lets you revise a generated summary later without losing the original result or creating another transcription request. It also makes it easier to explain which parts of the output came from the source and which came from your application. ## Build a searchable collection Index completed transcript text in your application's search system and retain segment timestamps alongside the source record. Text search can locate useful passages without requiring a person to replay every clip. Keep access control tied to the owner of the source collection. An API account is not automatically a multi-tenant permission system for your application. If your service has several customers, enforce customer boundaries before returning any stored text or source link. The transcript API accepts individual links; it does not enumerate a creator's account or discover videos for you. Only submit URLs gathered through a workflow you are authorized to operate. ## Prepare subtitle drafts Convert segment start and end times into the timestamp format required by your editor. The [API reference](/docs/api#text-and-subtitle-exports) includes an SRT helper. Preserve Unicode text and use UTF-8 when saving files. Review subtitle length, timing, and punctuation before publishing. A segment boundary reflects speech processing rather than an editorial decision about the ideal line break. Adjust the subtitle draft to match the pace and layout of the final video. If your application does not need its own export logic, the public web tool provides a ready-made transcript view with copy, TXT download, and SRT download controls. The developer endpoint remains JSON so your application can choose its own storage and presentation. ## Monitor the right signals Track accepted jobs, terminal outcomes, HTTP errors, queue depth, and the time from submission to completion. A fast create response only means the job was prepared; it is not the duration of the transcription itself. Use job IDs in operational logs rather than copying entire transcripts into logging services. Record stable error codes so you can distinguish invalid inputs, exhausted credits, rate limits, and temporary service failures. Review failures before enabling automated resubmission. A private or removed video will not become available because the same request is repeated more often. Show the source-access problem to the caller and let them choose the next action. --- # Billing and credits TikTok Transcript API uses credits for transcription and request limits for API traffic. These are separate measures. Creating a new transcript reserves a credit; checking an existing job does not consume a credit but still counts toward your account's request rate. ## Start with free credits A new verified account receives 100 free API credits. No payment card is required. The trial allows 20 API requests per minute and up to five jobs processing at once. Each transcript covers up to 20 minutes of one public TikTok video. The no-account web tool has a separate guest allowance: one free transcript daily, also up to 20 minutes. Guest transcripts are tied to the browser's guest session rather than your signed-in account. Use the developer API or MCP tools when you want work to appear in your account history. ## Choose a subscription | Plan | Price | Included credits | Top-up price | API rate | | --- | --- | --- | --- | --- | | Monthly | $5 each month | 1,000 each month | $2.50 per 1,000 | 200 requests/minute | | Annual | $54 each year | 1,000 each month | $1.50 per 1,000 | 300 requests/minute | Annual billing is equivalent to $4.50 per month. Both plans include the REST API, MCP connection, account dashboard, and support. Neither changes the 20-minute duration limit or the five-job concurrency cap. Open [Billing](/dashboard/billing) in your account to choose a plan. Stripe Checkout shows the subscription and payment details before you pay. The site activates paid access after verifying the payment and subscription status with Stripe. ## Monthly allowance Your 1,000 subscription credits refresh each month while the subscription is active. Unused monthly credits do not roll over. Annual subscribers receive the same monthly allowance rather than an immediate block of 12,000 credits. The dashboard shows the next allowance refresh and the end of the current paid period. For an annual plan, these dates are different: credits refresh monthly while billing happens yearly. Month-end anniversaries use the applicable last day of shorter months. The service spends active monthly credits first, then purchased top-up credits, then any remaining trial credits. These balances are shown separately so you can understand where your available total comes from. ## Reserved and released credits A new job reserves one credit before processing begins. That reserved credit is removed from the available balance while the video is pending. If processing succeeds, it remains used. If processing fails, reconciliation releases the reservation. Reading a result, opening the dashboard, and background reconciliation can refresh a failed job and release its credit. If the reservation came from a monthly grant that has already expired, the release does not increase the next month's grant. Trial and top-up reservations return to their original balances. An invalid request rejected before a job is created does not reserve a credit. Retrying an accepted create request with the same idempotency key and URL returns the original job without another reservation. Repeating the URL without an idempotency key creates a separate request. ## Top-ups An active subscriber can purchase additional blocks of 1,000 credits from Billing. The price depends on the active plan: $2.50 for monthly subscribers or $1.50 for annual subscribers. Top-ups are one-time purchases, not a second recurring subscription. Purchased top-up credits remain available after cancellation. You need an active subscription to buy more, and your account uses the free request rate when no paid plan is active. Top-ups do not increase concurrency or the maximum duration of a video. ## Manage or cancel Use **Manage subscription & invoices** in Billing to open your Stripe billing portal. You can update the payment method, view invoices, or cancel renewal there. Cancellation is scheduled for the end of the current paid period. Subscriptions renew automatically until canceled. If a payment is incomplete or fails, the dashboard may show a non-active subscription state. Resolve the payment issue in the billing portal before expecting the next paid allowance to become available. If a payment completed but the balance has not updated, return to Billing and refresh. Keep the checkout confirmation or invoice identifier for support. Do not submit another purchase solely because a page took a moment to update. ## Billing support For duplicate charges, refund questions, or account matching problems, [contact support](/contact). Include the account email and invoice or checkout identifier. Do not include full card numbers, API keys, or sign-in codes.