Skip to main content
deepgram-webhooks-events Implement Deepgram callback and webhook handling for async transcription.
Use when implementing callback URLs, processing async transcription results,
or handling Deepgram event notifications.
Trigger: "deepgram callback", "deepgram webhook", "async transcription",
"deepgram events", "deepgram notifications", "deepgram async".
跳到安装 Skills Marketplace 发现并探索由社区构建的 Agent Skills
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/jeremylongshore/claude-code-plugins-plus-skills --skill deepgram-webhooks-events命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
下载 Zip 下载中... 同仓库更多 Skills Implement user sign-up and sign-in flows with Clerk.
Use when building authentication UI, customizing sign-in experience,
or implementing OAuth social login.
Trigger with phrases like "clerk sign-in", "clerk sign-up",
"clerk login flow", "clerk OAuth", "clerk social login".
Implement session management and middleware with Clerk.
Use when managing user sessions, configuring route protection,
or implementing token refresh and custom JWT templates.
Trigger with phrases like "clerk session", "clerk middleware",
"clerk route protection", "clerk token", "clerk JWT".
Configure enterprise SSO, role-based access control, and organization management.
Use when implementing SSO integration, configuring role-based permissions,
or setting up organization-level controls.
Trigger with phrases like "clerk SSO", "clerk RBAC",
"clerk enterprise", "clerk roles", "clerk permissions", "clerk organizations".
jeremylongshore
jeremylongshore/claude-code-plugins-plus-skills
打开 GitHub 仓库 name deepgram-webhooks-events description Implement Deepgram callback and webhook handling for async transcription.
Use when implementing callback URLs, processing async transcription results,
or handling Deepgram event notifications.
Trigger: "deepgram callback", "deepgram webhook", "async transcription",
"deepgram events", "deepgram notifications", "deepgram async".
allowed-tools Read, Write, Edit, Bash(curl:*) version 1.13.0 license MIT author Jeremy Longshore <jeremy@intentsolutions.io> tags ["saas","deepgram","webhooks","transcription","async"] compatibility Designed for Claude Code, also compatible with Codex and OpenClaw
Deepgram Webhooks & Callbacks
Overview
Implement async transcription with Deepgram's callback feature. When you pass a callback URL, Deepgram returns a request_id immediately, processes audio in the background, and POSTs results to your endpoint. Supports HTTP and WebSocket callbacks with automatic retry (10 attempts, 30s intervals).
Deepgram Callback Flow
1. Client -> POST /v1/listen?callback=https://you.com/webhook (with audio)
2. Deepgram -> 200 { request_id: "..." } (immediate)
3. Deepgram processes audio asynchronously
4. Deepgram -> POST https://you.com/webhook (results)
Retries up to 10 times (30s delay) on non-2xx response
Instructions
Step 1: Submit Async Transcription
import { createClient } from '@deepgram/sdk' ;
const deepgram = createClient (process.env .DEEPGRAM_API_KEY !);
async function submitAsync (audioUrl : string , callbackUrl : string ) {
const { result, error } = await deepgram.listen .prerecorded .transcribeUrl (
{ url : audioUrl },
{
model : 'nova-3' ,
smart_format : true ,
diarize : true ,
utterances : true ,
callback : callbackUrl,
}
);
(error) ( );
requestId = result. . ;
. ( );
. ( );
requestId;
}
if
throw
new
Error
`Submit failed: ${error.message} `
const
metadata
request_id
console
log
`Submitted. Request ID: ${requestId} `
console
log
`Results will be POSTed to: ${callbackUrl} `
return
Step 2: Callback Server import express from 'express' ;
import crypto from 'crypto' ;
const app = express ();
app.use ('/webhooks/deepgram' , express.raw ({ type : 'application/json' , limit : '50mb' }));
app.post ('/webhooks/deepgram' , async (req, res) => {
try {
const signature = req.headers ['x-deepgram-signature' ] as string ;
if (process.env .DEEPGRAM_WEBHOOK_SECRET && signature) {
const expected = crypto
.createHmac ('sha256' , process.env .DEEPGRAM_WEBHOOK_SECRET )
.update (req.body )
.digest ('hex' );
if (!crypto.timingSafeEqual (Buffer .from (signature), Buffer .from (expected))) {
console .error ('Invalid webhook signature' );
return res.status (401 ).json ({ error : 'Invalid signature' });
}
}
const result = JSON .parse (req.body .toString ());
const requestId = result.metadata ?.request_id ;
const transcript = result.results ?.channels ?.[0 ]?.alternatives ?.[0 ]?.transcript ;
const duration = result.metadata ?.duration ;
console .log (`Callback received: ${requestId} ` );
console .log (`Duration: ${duration} s` );
console .log (`Transcript: ${transcript?.substring(0 , 200 )} ...` );
await processTranscriptionResult (requestId, result);
res.status (200 ).json ({ received : true , request_id : requestId });
} catch (err : any ) {
console .error ('Callback processing error:' , err.message );
res.status (500 ).json ({ error : 'Processing failed' });
}
});
async function processTranscriptionResult (requestId : string , result : any ) {
const transcript = result.results .channels [0 ].alternatives [0 ];
const record = {
requestId,
transcript : transcript.transcript ,
confidence : transcript.confidence ,
duration : result.metadata .duration ,
words : transcript.words ?.length ?? 0 ,
utterances : result.results .utterances ?.map ((u : any ) => ({
speaker : u.speaker ,
text : u.transcript ,
start : u.start ,
end : u.end ,
})),
processedAt : new Date ().toISOString (),
};
console .log ('Processed:' , JSON .stringify (record, null , 2 ));
return record;
}
Step 3: Job Tracking with Redis import Redis from 'ioredis' ;
const redis = new Redis (process.env .REDIS_URL ?? 'redis://localhost:6379' );
class TranscriptionJobTracker {
async submit (requestId : string , metadata : Record <string , any > ) {
await redis.hset (`job:${requestId} ` , {
status : 'processing' ,
submittedAt : new Date ().toISOString (),
...metadata,
});
await redis.expire (`job:${requestId} ` , 86400 );
}
async complete (requestId : string , result : any ) {
await redis.hset (`job:${requestId} ` , {
status : 'completed' ,
completedAt : new Date ().toISOString (),
transcript : result.results .channels [0 ].alternatives [0 ].transcript ,
duration : result.metadata .duration ,
});
await redis.publish ('transcription:complete' , JSON .stringify ({
requestId,
duration : result.metadata .duration ,
}));
}
async getStatus (requestId : string ) {
return redis.hgetall (`job:${requestId} ` );
}
}
app.get ('/api/transcription/:requestId' , async (req, res) => {
const tracker = new TranscriptionJobTracker ();
const status = await tracker.getStatus (req.params .requestId );
if (!status || Object .keys (status).length === 0 ) {
return res.status (404 ).json ({ error : 'Job not found' });
}
res.json (status);
});
Step 4: Client SDK with Submit/Poll/Wait class AsyncTranscriptionClient {
private deepgram : ReturnType <typeof createClient>;
private baseUrl : string ;
constructor (apiKey : string , serverBaseUrl : string ) {
this .deepgram = createClient (apiKey);
this .baseUrl = serverBaseUrl;
}
async submit (audioUrl : string ): Promise <string > {
const callbackUrl = `${this .baseUrl} /webhooks/deepgram` ;
const { result, error } = await this .deepgram .listen .prerecorded .transcribeUrl (
{ url : audioUrl },
{ model : 'nova-3' , smart_format : true , diarize : true , callback : callbackUrl }
);
if (error) throw error;
return result.metadata .request_id ;
}
async poll (requestId : string ): Promise <any > {
const res = await fetch (`${this .baseUrl} /api/transcription/${requestId} ` );
if (res.status === 404 ) return null ;
return res.json ();
}
async waitForResult (requestId : string , timeoutMs = 300000 ): Promise <any > {
const start = Date .now ();
while (Date .now () - start < timeoutMs) {
const status = await this .poll (requestId);
if (status?.status === 'completed' ) return status;
if (status?.status === 'failed' ) throw new Error ('Transcription failed' );
await new Promise (r => setTimeout (r, 2000 ));
}
throw new Error ('Timeout waiting for transcription' );
}
}
const client = new AsyncTranscriptionClient (
process.env .DEEPGRAM_API_KEY !,
'https://your-server.com'
);
const requestId = await client.submit ('https://example.com/long-recording.wav' );
const result = await client.waitForResult (requestId);
Step 5: Local Testing with ngrok
ngrok http 3000
curl -X POST 'https://api.deepgram.com/v1/listen?model=nova-3&callback=https://abc123.ngrok.io/webhooks/deepgram' \
-H "Authorization: Token $DEEPGRAM_API_KEY " \
-H "Content-Type: application/json" \
-d '{"url":"https://static.deepgram.com/examples/nasa-podcast.wav"}'
Step 6: Idempotent Processing
const processedRequests = new Set <string >();
app.post ('/webhooks/deepgram' , async (req, res) => {
const result = JSON .parse (req.body .toString ());
const requestId = result.metadata ?.request_id ;
if (processedRequests.has (requestId)) {
console .log (`Duplicate callback for ${requestId} — skipping` );
return res.status (200 ).json ({ received : true , duplicate : true });
}
processedRequests.add (requestId);
await processTranscriptionResult (requestId, result);
res.status (200 ).json ({ received : true });
});
Output
Async transcription submission with callback URL
Callback server with signature verification
Redis-backed job tracking with pub/sub notifications
Client SDK with submit/poll/wait pattern
Idempotent callback processing
Local testing setup with ngrok
Error Handling Issue Cause Solution Callback not received Endpoint unreachable Check HTTPS, firewall, use ngrok for local Duplicate callbacks Deepgram retry after slow response Implement idempotency with request_id Invalid signature Wrong webhook secret Verify DEEPGRAM_WEBHOOK_SECRET matches Console Processing timeout Slow downstream Return 200 immediately, process async Large payload Long audio transcript Increase express.raw limit
Resources