Webhook providers deliver at least once. If your endpoint is slow or doesn't return 2xx in time, they retry, so duplicates are normal and your handler must be idempotent.
- Make the database enforce it. Store the provider's order/event id with a unique constraint:
alter table orders add column ls_order_id text unique;then insert with on conflict (ls_order_id) do nothing. Only issue the license key if the insert actually inserted a row.
- Return 200 quickly. Verify the signature, write the row, respond. Do slow work (emails, license generation) after.
Your "select then insert" check has a race: two requests can both select nothing at the same moment. The unique constraint can't race.