Request a transcript
Run the call from a trusted server. Browser and mobile bundles must not contain a production API key.
const baseUrl = 'https://capslane.com'
const apiKey = process.env.CAPSLANE_API_KEY
const query = new URLSearchParams({
url: 'dQw4w9WgXcQ',
mode: 'auto',
})
const response = await fetch(`${baseUrl}/v1/transcript?${query}`, {
headers: { 'x-api-key': apiKey },
signal: AbortSignal.timeout(20_000),
})
const result = await response.json()
if (!response.ok) {
throw new Error(`${result.error}: ${result.message}`)
}Inspect both the status code and the response body. HTTP 202 is an accepted asynchronous job, not an error.
Poll with a deadline
Generated transcripts can take longer than native extraction. Use a modest interval, an application deadline and the same API key.
async function waitForTranscript(jobId) {
const deadline = Date.now() + 20 * 60_000
while (Date.now() < deadline) {
await new Promise((resolve) => setTimeout(resolve, 2_000))
const response = await fetch(`${baseUrl}/v1/transcript/${jobId}`, {
headers: { 'x-api-key': apiKey },
signal: AbortSignal.timeout(20_000),
})
const job = await response.json()
if (job.status === 'completed') return job
if (job.status === 'failed' || job.status === 'cancelled') throw new Error(job.error)
}
throw new Error('Transcript job deadline exceeded')
}Model both response shapes
A successful immediate response contains content, lang, availableLangs, source, cached and requestId. An accepted response contains jobId, status and requestId.
Keep the integration bounded
Set timeouts on every network call, cap polling, retain the request ID and apply retries only to transient failures. Use native mode when generation must never start.