StripeWebhookEvent
Overview
services/api/src/models/StripeWebhookEvent.js defines a Mongoose model that stores Stripe webhook events for deduplication. The file treats each received Stripe event as a ledger entry, so the application can detect retries and avoid applying the same payment mutation twice.
This model fits into the payments webhook flow. In services/api/src/modules/payments/payments.webhooks.js, the handler checks whether an event.id already exists before processing, and it writes a StripeWebhookEvent record after successful handling. That links this model directly to webhook idempotency.
[!NOTE] The schema disables automatic Mongoose timestamps. The stored fields are only
eventId,type, andreceivedAt.
How it works
sequenceDiagram
participant WH as payments webhooks
participant M as StripeWebhookEvent
participant DB as MongoDB
WH->>M: exists eventId
M->>DB: query by eventId
DB-->>M: found or not found
M-->>WH: duplicate state
WH->>M: create eventId type receivedAt
M->>DB: insert ledger record
DB-->>M: saved or duplicate key error
M-->>WH: create result
The model itself is small, but its role is important. The webhook handler uses it as an idempotency ledger, and the eventId field has a unique constraint. If the same Stripe event arrives again, the duplicate insert is rejected and the event can be skipped safely.
[!IMPORTANT]
eventIdis the deduplication key. It is markedrequired,unique, andtrim.
Key components
{
"title": "StripeWebhookEvent",
"content": "Mongoose model that stores Stripe webhook event identifiers, event types, and reception time for deduplication.",
"type": "class",
"filePath": "services/api/src/models/StripeWebhookEvent.js",
"badges": [
"public"
]
}
Data & fields
[
{
"name": "eventId",
"type": "string",
"required": true,
"description": "Unique Stripe event identifier. It is trimmed and indexed as unique."
},
{
"name": "type",
"type": "string",
"required": true,
"description": "Stripe event type, stored as a trimmed string."
},
{
"name": "receivedAt",
"type": "Date",
"description": "Timestamp assigned when the document is created. It defaults to the current date."
}
]
Schema options
[
{
"name": "timestamps",
"type": "boolean",
"description": "Disabled for this schema, so Mongoose does not add createdAt or updatedAt fields."
}
]
Behaviors
const { Schema } = mongoose— extracts the Mongoose schema constructor used to define the document structure.new Schema(...)— declares theStripeWebhookEventSchemawith three fields andtimestamps: false.eventId— enforces uniqueness, required presence, and trimming.type— stores the Stripe event type as a required trimmed string.receivedAt— defaults tonew Date()when the document is created.mongoose.model("StripeWebhookEvent", StripeWebhookEventSchema)— registers and exports the model asStripeWebhookEvent.
Workflows
1. Receive webhook event | `payments.webhooks.js` receives a Stripe event and identifies its `event.id`.
2. Check for prior processing | The handler queries `StripeWebhookEvent` to detect whether the event already exists.
3. Process the event | If it is new, the webhook flow continues with payment confirmation or subscription sync.
4. Persist the ledger entry | The handler creates a `StripeWebhookEvent` record with `eventId` and `type`.
5. Skip duplicates | A repeated `eventId` is rejected by the unique index and treated as already processed.
Gotchas & edge cases
[!WARNING] Duplicate Stripe deliveries are expected behavior. The model exists to prevent the same event from mutating state twice.
[!CAUTION] The unique constraint lives on
eventId. If the same event arrives again, Mongoose or MongoDB can reject the insert before any new state is written.
[!NOTE] The model does not store Mongoose-managed timestamps. Only
receivedAtrecords the reception time.
Related
services/api/src/modules/payments/payments.webhooks.js is the consumer that checks and stores Stripe webhook events. It uses StripeWebhookEvent.exists({ eventId: event.id }) for the duplicate check and StripeWebhookEvent.create({ eventId: event.id, type: event.type }) to persist the ledger entry.
services/api/src/modules/payments/providers/stripe.provider.js is the provider module that validates Stripe webhook signatures before the webhook handler reaches this model. That makes StripeWebhookEvent part of the broader Stripe payment and subscription flow.