| 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 with phrases like "deepgram callback", "deepgram webhook",
"async transcription deepgram", "deepgram events", "deepgram notifications".
|
| allowed-tools | Read, Write, Edit, Bash(curl:*) |
| version | 1.0.0 |
| license | MIT |
| author | Jeremy Longshore <jeremy@intentsolutions.io> |
Deepgram Webhooks Events
Overview
Implement callback URL handling for asynchronous Deepgram transcription workflows.
Prerequisites
- Publicly accessible HTTPS endpoint
- Deepgram API key with transcription permissions
- Request validation capabilities
- Secure storage for transcription results
Deepgram Callback Flow
- Client sends transcription request with callback URL
- Deepgram processes audio asynchronously
- Deepgram POSTs results to callback URL
- Your server processes and stores results
Instructions
Step 1: Create Callback Endpoint
Set up an HTTPS endpoint to receive results.
Step 2: Implement Request Validation
Verify callbacks are from Deepgram.
Step 3: Process Results
Handle the transcription response.
Step 4: Store and Notify
Save results and notify clients.
Examples
TypeScript Callback Server (Express)
import express from 'express';
import crypto from 'crypto';
import { logger } from './logger';
import { storeTranscription, notifyClient } from './services';
const app = express();
app.use('/webhooks/deepgram', express.raw({ type: 'application/json' }));
app.use(express.json());
interface DeepgramCallback {
request_id: string;
metadata: {
request_id: string;
transaction_key: string;
sha256: string;
created: string;
duration: number;
channels: number;
models: string[];
};
results: {
channels: Array<{
alternatives: Array<{
transcript: string;
confidence: number;
: <{
: ;
: ;
: ;
: ;
}>;
}>;
}>;
};
}
(): {
(!signature) ;
expectedSignature = crypto
.(, secret)
.(payload)
.();
crypto.(
.(signature),
.(expectedSignature)
);
}
app.(, (req, res) => {
requestId = req.[] ;
logger.(, { requestId });
{
signature = req.[] ;
webhookSecret = process..;
(webhookSecret && !(req., signature, webhookSecret)) {
logger.(, { requestId });
res.().({ : });
}
: = .(req..());
transcript = callback..[]?.[]?.;
confidence = callback..[]?.[]?.;
logger.(, {
: callback.,
: callback..,
confidence,
});
({
: callback.,
transcript,
confidence,
: callback.,
: callback..[]?.[]?.,
});
(callback., {
: ,
transcript,
});
res.().({ : });
} (error) {
logger.(, {
requestId,
: error ? error. : ,
});
res.().({ : });
}
});
app.(, {
res.({ : });
});
app;
Async Transcription Request
import { createClient } from '@deepgram/sdk';
import { v4 as uuidv4 } from 'uuid';
import { redis } from './redis';
interface AsyncTranscriptionOptions {
language?: string;
model?: string;
diarize?: boolean;
punctuate?: boolean;
}
export class AsyncTranscriptionService {
private client;
private callbackBaseUrl: string;
constructor(apiKey: string, callbackBaseUrl: string) {
this.client = createClient(apiKey);
this.callbackBaseUrl = callbackBaseUrl;
}
async submitTranscription(
audioUrl: string,
options: AsyncTranscriptionOptions = {}
): Promise<{ jobId: string; requestId: string }> {
const jobId = ();
callbackUrl = ;
{ result, error } = ....(
{ : audioUrl },
{
: options. || ,
: options. || ,
: options. ?? ,
: options. ?? ,
: ,
: callbackUrl,
}
);
(error) {
();
}
redis.(, {
: ,
: result.,
: ().(),
audioUrl,
});
redis.(, );
{
jobId,
: result.,
};
}
(: ): <{
: ;
?: ;
}> {
data = redis.();
(!data || .(data). === ) {
();
}
{
: data.,
: data. ? .(data.) : ,
};
}
}
Store and Notify Services
import { redis } from './redis';
import { db } from './database';
interface TranscriptionResult {
requestId: string;
transcript: string;
confidence: number;
metadata: Record<string, unknown>;
words?: Array<{
word: string;
start: number;
end: number;
confidence: number;
}>;
}
export async function storeTranscription(result: TranscriptionResult): Promise<void> {
await db.transcriptions.insert({
request_id: result.requestId,
transcript: result.transcript,
confidence: result.confidence,
metadata: result.metadata,
words: result.words,
created_at: (),
});
jobId = redis.();
(jobId) {
redis.(, {
: ,
: .(result),
: ().(),
});
}
}
{ } ;
{ emailService } ;
(): <> {
clientId = redis.();
(clientId) {
.(clientId, {
: ,
requestId,
...data,
});
}
email = redis.();
(email) {
emailService.({
: email,
: ,
: ,
});
}
}
Retry Mechanism for Callbacks
import { logger } from './logger';
interface RetryConfig {
maxRetries: number;
baseDelay: number;
maxDelay: number;
}
export class CallbackRetryHandler {
private config: RetryConfig;
private pendingRetries: Map<string, NodeJS.Timeout> = new Map();
constructor(config: Partial<RetryConfig> = {}) {
this.config = {
maxRetries: config.maxRetries ?? 3,
baseDelay: config.baseDelay ?? 5000,
maxDelay: config.maxDelay ?? 60000,
};
}
async processWithRetry(
requestId: string,
processor: () => Promise<void>
): Promise<void> {
attempt = ;
(attempt < ..) {
{
();
;
} (error) {
attempt++;
logger.(, {
requestId,
attempt,
: error ? error. : ,
});
(attempt >= ..) {
error;
}
delay = .(
.. * .(, attempt - ),
..
);
( (resolve, delay));
}
}
}
(: , : <>, : ): {
delay = .(
.. * .(, attempt),
..
);
timeout = ( () => {
{
();
..(requestId);
} (error) {
(attempt < ..) {
.(requestId, callback, attempt + );
} {
logger.(, { requestId });
}
}
}, delay);
..(requestId, timeout);
}
(: ): {
timeout = ..(requestId);
(timeout) {
(timeout);
..(requestId);
}
}
}
Testing Callbacks Locally
ngrok http 3000
curl -X POST https://your-ngrok-url.ngrok.io/webhooks/deepgram \
-H "Content-Type: application/json" \
-d '{
"request_id": "test-123",
"metadata": {
"request_id": "test-123",
"duration": 10.5
},
"results": {
"channels": [{
"alternatives": [{
"transcript": "This is a test transcript.",
"confidence": 0.95
}]
}]
}
}'
Client SDK for Async Transcription
export class AsyncTranscriptionClient {
private baseUrl: string;
private pollInterval: number;
constructor(baseUrl: string, pollInterval = 2000) {
this.baseUrl = baseUrl;
this.pollInterval = pollInterval;
}
async submit(audioUrl: string): Promise<string> {
const response = await fetch(`${this.baseUrl}/transcribe/async`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ audioUrl }),
});
const { jobId } = await response.json();
return jobId;
}
async waitForResult(jobId: string, timeout = 300000): Promise<{
transcript: string;
: ;
}> {
startTime = .();
(.() - startTime < timeout) {
response = ();
data = response.();
(data. === ) {
data.;
}
(data. === ) {
();
}
( (r, .));
}
();
}
(: ): <{
: ;
: ;
}> {
jobId = .(audioUrl);
.(jobId);
}
}
Resources
Next Steps
Proceed to deepgram-performance-tuning for optimization.