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 コミュニティが作成したAIスキルを発見・探索
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
直接コマンドでは確認用 Prompt が省略されます。実行前にソースを確認してください。
npx skills add https://github.com/jeremylongshore/claude-code-plugins-plus-skills --skill deepgram-webhooks-eventsコマンドは1行のまま表示されます。コピー前に横へスクロールして全体を確認してください。
ローカルで確認しますか?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