Skip to main content

Production guide πŸš€

Best practices for running Mappa SDK in production. Follow these patterns to build reliable, scalable integrations.

Architecture patterns​

Use webhooks, not polling​

❌ Don't:

// Blocks for minutes, wastes resources
const report = await mappa.reports.generateFromUrl({
url: "https://example.com/call.mp3",
output: { template: "general_report" },
target: { strategy: "dominant" },
});

βœ… Do:

// Returns immediately, scales infinitely
const receipt = await mappa.reports.createJobFromUrl({
url: "https://example.com/call.mp3",
output: { template: "sales_playbook" },
webhook: { url: "https://myapp.com/webhooks/mappa" },
idempotencyKey: `report:${userId}:${mediaHash}`,
target: { strategy: "dominant" },
});

await db.jobs.create({ jobId: receipt.jobId, userId, status: receipt.status });

Set up webhooks β†’


Idempotency​

Prevent duplicate jobs​

Always use idempotency keys:

await mappa.reports.createJobFromUrl({
url: "https://example.com/call.mp3",
output: { template: "sales_playbook" },
// Stable key prevents duplicates on retry
idempotencyKey: `report:user_${userId}:${mediaHash}`,
target: { strategy: "dominant" },
});

Key strategies:

StrategyExampleUse Case
User + Mediareport:user_123:media_abcOne report per user per file
External IDreport:customer_456:order_789Link to your system
UUIDreport:${uuidv4()}Unique every time

Handle duplicate webhooks​

Webhooks may be delivered multiple times:

async function processWebhook(event: WebhookEvent) {
// Check if already processed
const existing = await db.webhookEvents.findOne({ id: event.id });
if (existing) {
return; // Idempotent: safe to skip
}

// Process event
await handleEvent(event);

// Mark as processed
await db.webhookEvents.create({
id: event.id,
type: event.type,
processedAt: new Date(),
});
}

Learn more about idempotency β†’


Request tracing​

Use correlation IDs​

Track requests across your system:

const requestId = `req_user_${userId}_${Date.now()}`;

const receipt = await mappa.reports.createJobFromUrl({
url: "https://example.com/call.mp3",
output: { template: "sales_playbook" },
requestId,
target: { strategy: "dominant" },
});

logger.info({ requestId, jobId: receipt.jobId }, "Job created");

Benefits:

  • Trace requests end-to-end
  • Correlate logs with Mappa support
  • Debug faster

Monitor with telemetry​

const mappa = new Mappa({
apiKey: process.env.MAPPA_API_KEY!,
telemetry: {
onRequest: ({ method, url, requestId }) => {
metrics.increment("mappa.request", { method });
logger.debug({ method, url, requestId }, "Request");
},
onResponse: ({ status, durationMs, requestId }) => {
metrics.timing("mappa.latency", durationMs);
metrics.increment("mappa.response", { status });
},
onError: ({ error, requestId }) => {
metrics.increment("mappa.error");
logger.error({ error, requestId }, "Error");
},
},
});

Error handling​

Retry with exponential backoff​

The SDK retries automatically, but you may need custom logic:

async function createJobWithRetry(params: any, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await mappa.reports.createJob(params);
} catch (err) {
if (i === maxRetries - 1) throw err;
if (err instanceof RateLimitError) {
await sleep(Math.pow(2, i) * 1000);
} else {
throw err; // Don't retry non-retryable errors
}
}
}
}

Graceful degradation​

Handle failures without breaking the user experience:

async function generateReportWithFallback(url: string) {
try {
return await mappa.reports.generateFromUrl({
url,
output: { template: "sales_playbook" },
target: { strategy: "dominant" },
});
} catch (err) {
if (err instanceof InsufficientCreditsError) {
// Notify admin, use cached report
await notifyLowCredits();
return getCachedReport(url);
}
if (err instanceof ValidationError) {
// Fallback to general template
return await mappa.reports.generateFromUrl({
url,
output: { template: "general_report" },
target: { strategy: "dominant" },
});
}
throw err;
}
}

Error handling guide β†’


Timeout configuration​

Adjust for long files​

// Default client
const mappa = new Mappa({
apiKey: process.env.MAPPA_API_KEY!,
timeoutMs: 30000, // 30 seconds
});

// Override for specific request
await mappa.reports.createJobFromUrl({
url: "https://example.com/long-video.mp4",
output: { template: "general_report" },
}, {
timeoutMs: 120000, // 2 minutes for this request
target: { strategy: "dominant" },
});
OperationTimeout
File upload60-120 seconds
Job creation30 seconds
Status check10 seconds
Webhook delivery5 seconds

Credit management​

Check balance before jobs​

async function canCreateJob(estimatedCredits: number): Promise<boolean> {
const { available } = await mappa.credits.getBalance();
return available >= estimatedCredits;
}

// Use it
if (await canCreateJob(50)) {
await mappa.reports.createJob({
media: { mediaId: "media_123" },
output: { template: "general_report" },
target: { strategy: "dominant" },
});
} else {
await notifyLowCredits();
}

Track usage​

async function trackCreditUsage(jobId: string) {
const usage = await mappa.credits.getJobUsage(jobId);

await analytics.track("credit_usage", {
jobId,
creditsUsed: usage.creditsCharged,
creditsReserved: usage.creditsReserved,
creditsRefunded: usage.creditsRefunded,
});
}

Credit optimization β†’


Security​

Environment variables​

.env
MAPPA_API_KEY=your_production_key_here
MAPPA_WEBHOOK_SECRET=your_webhook_secret_here
const mappa = new Mappa({
apiKey: process.env.MAPPA_API_KEY!,
});
Never Expose Keys
  • ❌ Don't commit keys to version control
  • ❌ Don't use keys in client-side code
  • ❌ Don't log keys in error messages
  • βœ… Use separate keys for dev/staging/prod

Webhook verification​

Always verify webhook signatures:

await mappa.webhooks.verifySignature({
payload: req.body,
headers: req.headers,
secret: process.env.MAPPA_WEBHOOK_SECRET!,
});

Performance​

Reuse client instances​

// βœ… Good: One client for entire app
const mappa = new Mappa({ apiKey: process.env.MAPPA_API_KEY! });

// ❌ Bad: Creating new client every request
app.post("/analyze", async (req, res) => {
const mappa = new Mappa({ apiKey: process.env.MAPPA_API_KEY! }); // Don't do this!
});

Batch operations​

// Process multiple files concurrently
async function batchAnalyze(urls: string[]) {
const jobs = await Promise.all(
urls.map(url =>
mappa.reports.createJobFromUrl({
url,
output: { template: "general_report" },
target: { strategy: "dominant" },
webhook: { url: "https://myapp.com/webhooks/mappa" },
})
)
);

return jobs.map(j => j.jobId);
}

Monitoring​

Key metrics to track​

// Request volume
metrics.increment("mappa.jobs.created");

// Latency
metrics.timing("mappa.job.duration", durationMs);

// Success rate
metrics.increment("mappa.jobs.succeeded");
metrics.increment("mappa.jobs.failed");

// Credit usage
metrics.gauge("mappa.credits.available", available);

Health checks​

async function checkMappaHealth() {
try {
await mappa.health.ping({ timeoutMs: 5000 });
return { status: "healthy" };
} catch (err) {
return { status: "unhealthy", error: err.message };
}
}

// Health endpoint
app.get("/health", async (req, res) => {
const mappa = await checkMappaHealth();
res.json({ services: { mappa } });
});

Testing​

Mock the client​

// __mocks__/@mappa-ai/mappa-node.ts
export const Mappa = jest.fn().mockImplementation(() => ({
reports: {
createJobFromUrl: jest.fn().mockResolvedValue({
jobId: "job_test123",
status: "queued",
}),
get: jest.fn().mockResolvedValue({
id: "report_test123",
markdown: "# Test Report",
}),
},
}));

Integration tests​

describe("Report generation", () => {
it("creates job and handles webhook", async () => {
const receipt = await mappa.reports.createJobFromUrl({
url: "https://example.com/test.mp3",
output: { template: "general_report" },
target: { strategy: "dominant" },
});

expect(receipt.jobId).toMatch(/^job_/);
expect(receipt.status).toBe("queued");
});
});

Deployment checklist​

Before going live:

Configuration​

  • Set MAPPA_API_KEY in production environment
  • Set MAPPA_WEBHOOK_SECRET for webhook verification
  • Configure appropriate timeoutMs values
  • Set up separate keys for staging and production

Monitoring​

  • Set up telemetry hooks
  • Track key metrics (jobs created, success rate, credits)
  • Configure alerts for errors and low credits
  • Add health checks

Error handling​

  • Implement retry logic with exponential backoff
  • Add circuit breakers for cascading failures
  • Set up error logging and alerting
  • Test graceful degradation

Webhooks​

  • Set up webhook endpoint
  • Verify signature on all webhooks
  • Handle idempotent webhook delivery
  • Test with ngrok or webhook.site

Testing​

  • Write unit tests with mocked client
  • Run integration tests against sandbox
  • Load test with expected production volume
  • Test failure scenarios

What's next? πŸŽ―β€‹

Deep dives:

Resources: