Idempotency
You know when a retry is the same logical operation; we don't. Pass idempotencyKey on any mutation and we'll dedupe within 24 hours — second request with the same key gets the cached
first response, not a duplicate row.
How it wires up
Every create / update / sub-resource .create on the SDK
accepts an options bag with idempotencyKey. The client adds it to the Idempotency-Key header before sending.
await cstar.tickets.create(
{ title: 'Need help', priority: 'high' },
{ idempotencyKey: 'submission_form_42' }
);
// Same key inside 24h returns the cached first response — no duplicate ticket.
await cstar.tickets.create(
{ title: 'Need help', priority: 'high' },
{ idempotencyKey: 'submission_form_42' }
);Pick the key like a fingerprint
Make the key deterministic for the logical operation, not the network attempt. Some shapes that work:
- Form submissions:
submission_${formId}_${userId}— same form, same user, same ticket. - Webhook handlers:
stripe_${event.id}— Stripe sends the same event ID on every retry. - Queue jobs:
job_${jobId}— survives worker restarts and at-least-once delivery. - Bad shape:
crypto.randomUUID(). A fresh UUID per attempt is the same as no key.
Webhook handler that survives retries
The classic case. Stripe (or any webhook source) retries delivery on non-2xx responses; the idempotency key keeps you safe even when your handler runs twice.
import express from 'express';
import { CStarClient } from '@cstar.help/js';
const cstar = new CStarClient({
apiKey: process.env.CSTAR_KEY,
teamId: process.env.CSTAR_TEAM_ID
});
app.post('/stripe-webhook', async (req, res) => {
const event = req.body;
await cstar.tickets.create(
{
title: `Stripe issue: ${event.type}`,
priority: 'high',
tags: ['stripe', event.type]
},
{ idempotencyKey: `stripe_${event.id}` }
);
res.status(200).end();
});No key, no dedup
Skip idempotencyKey and you get exactly-once semantics on the network and at-least-once
on retries. That's fine for fire-and-forget endpoints (analytics events, log writes) but a footgun
for anything that creates a row your customer cares about.