TikTok Shop & BigCommerce Flash Sales: Managing High-Velocity Social Commerce Webhooks
TikTok Shop & BigCommerce Flash Sales: Managing High-Velocity Social Commerce Webhooks Traditional e-commerce webhook traffic follows a predictable diurnal curve.

TikTok Shop & BigCommerce Flash Sales: Managing High-Velocity Social Commerce Webhooks
Traditional e-commerce webhook traffic follows a predictable diurnal curve. Traffic builds through the morning, peaks in the early evening, and fades overnight — the kind of load a standard auto-scaling group absorbs without drama.
Social commerce live-streams break that model completely.
When a creator on TikTok Shop flashes a limited-stock item to a live audience and says "link in bio, go," checkout demand stops being a curve and becomes a vertical line. In the space of a second or two, a backend that normally sees a few requests a minute can be hit with thousands of concurrent order, payment, and inventory webhooks.
Industry trackers disagree on the exact share of TikTok Shop's revenue that comes from live shopping — estimates for 2026 range from roughly 10% up toward the mid-20s percent of platform GMV depending on the source and methodology, and the figure is meaningfully higher in Southeast Asia than in the US. What every tracker agrees on is the shape of the traffic: individual livestream sessions are reported to swing from a few hundred dollars in sales to tens of thousands of dollars within a single hour, and that revenue lands as a burst, not a trickle. If your integration bridges TikTok Shop and BigCommerce, that burst is an architectural problem, not just a marketing one. Handled poorly, it produces dropped orders, oversold inventory, API rate-limit lockouts, and — in BigCommerce's case — webhooks that get automatically disabled mid-sale.
This piece lays out an architecture for surviving that burst: how to decouple ingestion from processing, how to verify and de-duplicate events correctly for both platforms, how to batch inventory writes against BigCommerce's real rate limits, and how to recover cleanly when something still breaks.
A note on scope: TikTok Shop's Partner API and BigCommerce's REST API both change fairly often. The specifics below (header names, rate-limit numbers, retry windows) were checked against current platform documentation as of September 2026 and are sourced at the end of this article — but always verify against the live docs before shipping, especially anything involving signature verification.
1. Why Social Commerce Traffic Breaks Synchronous Architectures
| Metric | Traditional BigCommerce Storefront | TikTok Shop Live Flash Sale |
|---|---|---|
| Traffic onset | Gradual ramp over 15–45 minutes | Near-instant burst, effectively 0 to peak in under a second |
| Concurrency | Spread across browsing, carts, checkout | Concentrated on one-tap checkouts during a narrow window |
| Event velocity | Tens of webhooks per minute at peak | Can spike into the thousands per second during a drop |
| Inventory risk | Standard per-order sync | Multi-channel race condition between TikTok Shop and BigCommerce |
When a burst like this hits a naive, synchronous integration, the failure sequence is predictable:
- The synchronous trap. The receiver accepts a TikTok Shop webhook, looks up the order, calls the BigCommerce Catalog or Inventory API to adjust stock, and only then returns a response to TikTok. Every one of those steps holds the HTTP connection open.
- Thread starvation. As concurrent webhooks pile up, response times climb from tens of milliseconds to multiple seconds. TikTok Shop's delivery layer treats a slow or missing response as a failed delivery.
- Retry amplification. TikTok Shop retries failed deliveries, adding to the load your already-struggling receiver is trying to handle — compounding the spike instead of relieving it.
- BigCommerce throttling. Meanwhile, your workers are hammering BigCommerce with one inventory update per order. BigCommerce's default API plan allows 150 requests per 30 seconds per store, per API client — a limit that a few hundred concurrent orders blows through in seconds, returning
429 Too Many Requests. - Webhook disablement. If your own downstream BigCommerce webhook consumer (for events like
store/order/statusUpdated) can't keep up and starts timing out, BigCommerce logs delivery exceptions and, after roughly 48 hours of continued failure across 11 retry attempts, disables the webhook by flipping itsis_activeflag tofalse— severing sync until someone notices and re-enables it.
The fix, as with most high-throughput webhook problems, is to stop doing any of that work inside the HTTP request/response cycle at all.
2. Architecture: Buffer-First Ingestion
The core rule: your public webhook endpoint does no business logic. It verifies the signature, drops the raw payload on a queue, and returns a fast acknowledgment — nothing else.
HIGH-VELOCITY INGESTION PIPELINE
┌────────────────┐ ┌─────────────────────────┐ ┌──────────────────┐
│ TikTok Shop │─────►│ Light Receiver Edge API │─────►│ Ingestion Bus │
│ Webhook Engine │ │ (Fastify / API Gateway) │ │ (AWS SQS / Kafka)│
└────────────────┘ └─────────────────────────┘ └────────┬─────────┘
│
┌─────────┴─────────┐
│ Async Worker Pool │
└─────────┬─────────┘
│
┌─────────────────────────────────────────────────────────────┴──────────────────────────────────────────────────┐
▼ ▼ ▼
┌───────────┐ ┌──────────────────┐ ┌──────────────────┐
│ Idempotent │ │ Inventory Delta │ │ BigCommerce │
│ Redis Lock │ │ Aggregator │ │ Inventory API │
└───────────┘ └──────────────────┘ └──────────────────┘
Ingress layer. A lightweight Fastify/Node service, Go service, or serverless function (API Gateway + Lambda, Cloudflare Workers) whose only jobs are HMAC verification and enqueueing. Budget under 20ms of execution time.
Message bus. Amazon SQS Standard queues are a good default here: AWS documents standard queues as supporting a very high, effectively unlimited number of API calls per second per action, with at-least-once delivery and best-effort ordering. That "best-effort ordering, at-least-once delivery" tradeoff is exactly why the idempotency layer in Section 4 isn't optional — it's what makes an unordered, duplicate-tolerant queue safe to use.
If you need strict per-order sequencing instead of timestamp-based reconciliation, SQS FIFO queues are the alternative, and AWS has been steadily raising FIFO throughput ceilings — high-throughput mode now supports up to 70,000 transactions per second per API action in several regions (lower in some others), which is generally enough headroom even for a very large flash sale. Standard queues remain the simpler default; reach for FIFO only if strict ordering genuinely matters more than raw throughput and code simplicity.
Worker pool. Node.js/TypeScript, Go, or Python consumers that pull from the queue, enforce idempotency, aggregate inventory deltas, and make rate-limit-aware calls to BigCommerce.
3. Verifying Webhook Authenticity — Correctly
This is the part most reference architectures get wrong, because TikTok Shop's signature scheme is easy to confuse with the general TikTok for Developers webhook scheme, which is a different product surface using a different format. Mixing them up means your signature check silently never passes (or worse, silently never fails).
TikTok Shop's actual scheme
For TikTok Shop specifically (Partner Center / Shop Open API webhooks — order, package, product, and message events), the signature travels in the Authorization header, with no Bearer prefix. It is a lowercase-hex HMAC-SHA256, computed as:
signature = HMAC_SHA256(key = app_secret, message = app_key + raw_request_body)
A few things to get right:
- Sign the exact raw bytes of the body — parsing the JSON and re-serializing it before signing will not match.
- There is no timestamp baked into the signature, so this scheme offers no built-in replay protection. Don't rely on the signature alone to dedupe; use the event's
tts_notification_idfor that (covered in Section 4). - Return
401 Unauthorizedfor a bad signature, not400. - This is unrelated to TikTok Shop's separate API request signing scheme (used when you call TikTok Shop's API, which signs the path, sorted query params, and body with a
signparameter). Don't reuse that logic for webhook verification, and vice versa.
import crypto from 'crypto';
/**
* Verifies a TikTok Shop webhook (Partner Center / Shop Open API).
* Signature arrives in the `Authorization` header — no Bearer prefix.
*/
export function verifyTikTokShopSignature(
rawBody: Buffer,
authorizationHeader: string | undefined,
appKey: string,
appSecret: string
): boolean {
if (!authorizationHeader) return false;
const message = Buffer.concat([Buffer.from(appKey, 'utf8'), rawBody]);
const expected = crypto
.createHmac('sha256', appSecret)
.update(message)
.digest('hex');
const expectedBuf = Buffer.from(expected, 'utf8');
const givenBuf = Buffer.from(authorizationHeader, 'utf8');
if (expectedBuf.length !== givenBuf.length) return false;
return crypto.timingSafeEqual(expectedBuf, givenBuf);
}
Common TikTok Shop webhook events worth planning your handler switch statement around: ORDER_STATUS_CHANGE, PACKAGE_UPDATE, RECIPIENT_ADDRESS_UPDATE, PRODUCT_STATUS_CHANGE, SELLER_DEAUTHORIZATION, and NEW_MESSAGE (customer-service events, internally event type 14). TikTok Shop's own guidance asks receivers to acknowledge quickly — documentation for the adjacent Customer Service webhooks specifies responding within 3 seconds, which is a reasonable target to hold your whole ingress layer to.
Verifying BigCommerce's webhooks too
If your pipeline is bidirectional — reacting to BigCommerce events like store/order/statusUpdated to push fulfillment or cancellation state back to TikTok Shop — verify those inbound webhooks as well. BigCommerce now documents webhook signing against the open Standard Webhooks specification: deliveries carry webhook-id, webhook-timestamp, and webhook-signature (formatted v1,<base64>) headers. The signing key is your app's client secret, base64-encoded before use.
import crypto from 'crypto';
export function verifyBigCommerceSignature(
rawBody: Buffer,
webhookId: string,
webhookTimestamp: string,
webhookSignatureHeader: string, // e.g. "v1,BASE64SIG v1,BASE64SIG2"
clientSecret: string,
toleranceSeconds = 300
): boolean {
// Reject stale deliveries — Standard Webhooks recommends a 5-minute tolerance.
const age = Math.abs(Date.now() / 1000 - parseInt(webhookTimestamp, 10));
if (age > toleranceSeconds) return false;
const signedContent = `${webhookId}.${webhookTimestamp}.${rawBody.toString('utf8')}`;
const key = Buffer.from(clientSecret, 'utf8').toString('base64');
const expected = crypto
.createHmac('sha256', Buffer.from(key, 'base64'))
.update(signedContent)
.digest('base64');
// webhook-signature can carry multiple space-separated "v1,<sig>" values
// during secret rotation — accept the request if any of them match.
return webhookSignatureHeader
.split(' ')
.some((entry) => {
const [, sig] = entry.split(',');
if (!sig) return false;
const a = Buffer.from(sig, 'base64');
const b = Buffer.from(expected, 'base64');
return a.length === b.length && crypto.timingSafeEqual(a, b);
});
}
Worth flagging: BigCommerce's own docs, as of this writing, describe the scheme by pointing developers to Standard Webhooks client libraries rather than naming the headers outright, and don't clearly state whether signing is fully GA across every webhook type. Log the incoming headers on your first real delivery to confirm what you're actually receiving before trusting this in production.
4. Idempotency & Out-of-Order Events
At-least-once delivery is the norm on both platforms, and under concurrent retries and parallel workers, events will arrive duplicated or out of order — a cancellation notification landing before the order-created notification, a paid event processed twice.
For TikTok Shop, key your idempotency lock on tts_notification_id, since — as noted above — the webhook signature carries no timestamp and gives you no replay signal on its own. For BigCommerce, the hash field on each delivery plus the resource id/scope pair works well as a dedup key.
import Redis from 'ioredis';
const redis = new Redis(process.env.REDIS_URL);
export async function processWebhookWithIdempotency(
notificationId: string,
eventType: string,
eventTimestamp: number,
processFn: () => Promise<void>
): Promise<boolean> {
const idempotencyKey = `idempotency:${eventType}:${notificationId}`;
const timestampKey = `entity_last_ts:${notificationId}`;
// Atomic lock: only the first delivery of this notification proceeds.
const isNewEvent = await redis.set(idempotencyKey, 'LOCKED', 'EX', 86400, 'NX');
if (!isNewEvent) {
return true; // Duplicate — acknowledge so the queue message clears.
}
// Out-of-order guard: skip if a newer update for this entity already landed.
const lastProcessedTime = await redis.get(timestampKey);
if (lastProcessedTime && parseInt(lastProcessedTime, 10) > eventTimestamp) {
return true;
}
await processFn();
await redis.set(timestampKey, eventTimestamp.toString(), 'EX', 604800);
return true;
}
5. Rate Limits & Batching — Against the Real Numbers
Both platforms will throttle you the moment a flash sale sends a burst of individual writes, but they throttle differently, and the fix on the BigCommerce side is more specific than "add a retry wrapper."
BigCommerce: use the Inventory API, not per-variant Catalog calls
BigCommerce's default API rate plan allows 150 requests per 30 seconds, per store, per API client — response headers X-Rate-Limit-Requests-Quota, X-Rate-Limit-Requests-Left, X-Rate-Limit-Time-Window-Ms, and X-Rate-Limit-Time-Reset-Ms tell you exactly where you stand on every call. Blow through it and you get 429 Too Many Requests; sustained abuse can also trigger a 509 Bandwidth Limit Exceeded. (Enterprise stores can be on an "Unlimited" plan, but that's still bounded by underlying infrastructure limits, so batching remains worthwhile regardless.)
The original approach of calling the Catalog API's variant-batch endpoint (PUT /v3/catalog/variants) doesn't scale well for this use case on its own — that endpoint currently caps out at around 50 variants per batch call, which is a small ceiling during a burst of thousands of orders. The better fit for order-driven, delta-style inventory changes is BigCommerce's dedicated Inventory API, specifically the relative-adjustment endpoint:
POST https://api.bigcommerce.com/stores/{store_hash}/v3/inventory/adjustments/relative
BigCommerce's own guidance is explicit that relative adjustments are the right tool "when you do not know absolute quantities" — their example is precisely order-driven changes coming from a third party, which is exactly this scenario. That endpoint accepts up to roughly 2,000 items per payload, a far larger batch ceiling than the Catalog API offers, and it's location-aware if you run multi-warehouse fulfillment.
/**
* Record an inventory reduction in Redis during a high-velocity flash sale.
*/
export async function queueInventoryDecrement(sku: string, quantity: number) {
await redis.hincrby('inventory_delta:bigcommerce', sku, -Math.abs(quantity));
}
/**
* Runs every ~2s. Flushes aggregated deltas to BigCommerce's Inventory API
* in a single relative-adjustment batch call instead of one call per order.
*/
export async function flushInventoryDeltasToBigCommerce() {
const cacheKey = 'inventory_delta:bigcommerce';
const pipeline = redis.pipeline();
pipeline.hgetall(cacheKey);
pipeline.del(cacheKey);
const [[, pendingDeltas]] = (await pipeline.exec()) as [[Error | null, Record<string, string>]];
if (!pendingDeltas || Object.keys(pendingDeltas).length === 0) return;
const items = Object.entries(pendingDeltas).map(([sku, deltaStr]) => ({
sku,
location_id: DEFAULT_LOCATION_ID,
quantity: parseInt(deltaStr, 10),
}));
try {
await bigCommerceClient.post('/v3/inventory/adjustments/relative', {
reason: 'TikTok Shop live-sale sync',
items,
});
} catch (error) {
console.error('Inventory batch flush failed, restoring deltas', error);
for (const [sku, deltaStr] of Object.entries(pendingDeltas)) {
await redis.hincrby(cacheKey, sku, parseInt(deltaStr, 10));
}
}
}
Also worth budgeting for: BigCommerce webhook payloads are intentionally thin — typically just a resource type and id, not the full object. If your pipeline reacts to BigCommerce's own webhooks (rather than only pushing outbound), every event requires a follow-up API call to fetch the actual resource, which roughly doubles the API calls that event stream costs you. Factor that into your 150-requests-per-30-seconds budget.
TikTok Shop: adapt to 429s, don't hard-code a ceiling
Unlike BigCommerce's published numeric quota, TikTok Shop's Partner API uses dynamic QPS allocation — your effective throughput is computed based on the number of shops your app is authorized for and the specific endpoint, and TikTok doesn't expose an API to query your current quota. In practice this means: don't hard-code a requests-per-second assumption for order or fulfillment calls. Build your client to react to 429 responses and back off, rather than trying to stay under a number you can't actually look up.
Exponential backoff with full jitter, for both platforms
export async function executeWithRetry<T>(
fn: () => Promise<T>,
maxRetries = 5,
baseDelayMs = 1000,
maxDelayMs = 30000
): Promise<T> {
let attempt = 0;
while (attempt < maxRetries) {
try {
return await fn();
} catch (error: any) {
attempt++;
const status = error.response?.status;
const isRateLimited = status === 429 || status === 509;
if (!isRateLimited && attempt >= maxRetries) throw error;
const retryAfterHeader = error.response?.headers?.['retry-after'];
let delayMs: number;
if (retryAfterHeader) {
delayMs = parseInt(retryAfterHeader, 10) * 1000;
} else {
const exponentialDelay = Math.min(maxDelayMs, baseDelayMs * 2 ** attempt);
delayMs = Math.floor(Math.random() * exponentialDelay); // full jitter
}
console.warn(`[RETRY ${attempt}] Rate limited. Waiting ${delayMs}ms...`);
await new Promise((resolve) => setTimeout(resolve, delayMs));
}
}
throw new Error(`Max retries (${maxRetries}) exhausted.`);
}
Randomized jitter matters here specifically because a burst of workers all backing off on the same fixed schedule will just re-synchronize their retries into a second spike.
6. Full Production Blueprint: Ingress & Worker
1. Ingress edge receiver
import Fastify from 'fastify';
import { SQSClient, SendMessageCommand } from '@aws-sdk/client-sqs';
import { verifyTikTokShopSignature } from './cryptoUtils';
const fastify = Fastify({ logger: true });
const sqs = new SQSClient({ region: process.env.AWS_REGION });
const SQS_QUEUE_URL = process.env.TIKTOK_WEBHOOK_QUEUE_URL!;
const TIKTOK_APP_KEY = process.env.TIKTOK_APP_KEY!;
const TIKTOK_APP_SECRET = process.env.TIKTOK_APP_SECRET!;
// Preserve raw bytes — required for signature verification.
fastify.addContentTypeParser(
'application/json',
{ parseAs: 'buffer' },
(req, body, done) => done(null, body)
);
fastify.post('/webhooks/tiktok-shop', async (request, reply) => {
const rawBody = request.body as Buffer;
const authHeader = request.headers['authorization'] as string | undefined;
if (!verifyTikTokShopSignature(rawBody, authHeader, TIKTOK_APP_KEY, TIKTOK_APP_SECRET)) {
return reply.status(401).send({ error: 'Invalid signature' });
}
try {
const parsed = JSON.parse(rawBody.toString('utf8'));
const eventType = parsed.type ?? 'UNKNOWN';
const notificationId = parsed.tts_notification_id;
await sqs.send(
new SendMessageCommand({
QueueUrl: SQS_QUEUE_URL,
MessageBody: rawBody.toString('utf8'),
MessageAttributes: {
EventType: { DataType: 'String', StringValue: eventType },
NotificationId: { DataType: 'String', StringValue: notificationId ?? '' },
},
})
);
return reply.status(200).send({ code: 0, message: 'ACCEPTED' });
} catch (error) {
fastify.log.error(error, 'Error enqueueing webhook payload');
return reply.status(500).send({ error: 'Internal Queue Error' });
}
});
fastify.listen({ port: 3000, host: '0.0.0.0' }, (err) => {
if (err) throw err;
console.log('Webhook ingress active on port 3000');
});
2. Async worker
import { SQSClient, ReceiveMessageCommand, DeleteMessageCommand } from '@aws-sdk/client-sqs';
import { processWebhookWithIdempotency } from './idempotency';
import { executeWithRetry } from './retryUtils';
import { queueInventoryDecrement } from './inventoryAggregator';
const sqs = new SQSClient({ region: process.env.AWS_REGION });
const SQS_QUEUE_URL = process.env.TIKTOK_WEBHOOK_QUEUE_URL!;
async function startWorker() {
console.log('SQS consumer worker started...');
while (true) {
const response = await sqs.send(
new ReceiveMessageCommand({
QueueUrl: SQS_QUEUE_URL,
MaxNumberOfMessages: 10,
WaitTimeSeconds: 20, // long polling
})
);
if (!response.Messages?.length) continue;
for (const message of response.Messages) {
if (!message.Body || !message.ReceiptHandle) continue;
const payload = JSON.parse(message.Body);
const notificationId = payload.tts_notification_id;
const eventType = payload.type;
const timestamp = payload.timestamp ?? Math.floor(Date.now() / 1000);
const handled = await processWebhookWithIdempotency(
notificationId,
eventType,
timestamp,
() => handleWebhookBusinessLogic(eventType, payload)
);
if (handled) {
await sqs.send(
new DeleteMessageCommand({ QueueUrl: SQS_QUEUE_URL, ReceiptHandle: message.ReceiptHandle })
);
}
}
}
}
async function handleWebhookBusinessLogic(eventType: string, payload: any) {
switch (eventType) {
case 'ORDER_STATUS_CHANGE':
if (payload.data?.order_status === 'AWAITING_SHIPMENT') {
for (const item of payload.data.item_list) {
await queueInventoryDecrement(item.seller_sku, item.quantity);
}
await executeWithRetry(async () => {
// Create/update the corresponding BigCommerce order.
});
}
break;
default:
console.log(`Unhandled event type: ${eventType}`);
}
}
startWorker();
7. Monitoring, Dead Letter Queues, and Recovery
Configure dashboards (CloudWatch, Datadog, Grafana — whatever you already run) around three metrics:
- Ingress latency (p99) — should stay comfortably under 50ms. Anything creeping toward 200ms means your edge receiver is blocking on I/O somewhere it shouldn't be.
- Queue backlog depth — expected to climb during a live drop, but should drain back to zero within a few minutes after the sale ends.
- Worker error rate (429/5xx) — your early signal of downstream pressure on BigCommerce or database contention.
Dead letter queues. Set SQS maxReceiveCount to a small number (5 is a common default) so a malformed "poison pill" payload can't loop indefinitely against your worker. Alert immediately when the DLQ depth rises above zero, and build a one-click replay path for once the underlying bug or outage is fixed.
BigCommerce-specific recovery signals. Subscribe to store/hook/deliveryException so you get told directly when your own webhook deliveries are struggling, rather than discovering it after the fact. BigCommerce's delivery-exception codes are worth knowing by number:
| Code | Meaning |
|---|---|
90001 | Delivery failed, will retry (BigCommerce rate-limits this notice to once per 10 minutes) |
90002 | All retries exhausted — the webhook has been disabled |
90003 | Your destination domain has been blocklisted |
Two behaviors here catch people off guard. First, retries and disablement are tracked per destination domain, not per individual webhook — if yourapp.com/webhook-orders and yourapp.com/webhook-inventory both point at the same domain, failures on one affect retry behavior for both. Second, if a domain's delivery success ratio drops below 90% within a rolling 2-minute window, BigCommerce blocklists that domain for 3 minutes — a short, automatic circuit-breaker that a struggling ingress layer can trigger on itself during exactly the kind of spike this article is about. Keeping ingress response time low isn't just about your own throughput; it's what keeps BigCommerce from cutting you off.
DEAD LETTER QUEUE (DLQ) RECOVERY
┌──────────────────┐ Fail 5x ┌──────────────────┐ ┌──────────────────┐
│ Primary Ingest │──────────────►│ Dead Letter Queue│───(Inspect)──►│ Fix Code/Outage │
│ Queue (SQS) │ │ (DLQ Buffer) │ └────────┬─────────┘
└──────────────────┘ └──────────────────┘ │
▲ │
└───────────────────────── (Replay Payload) ─────────────────────────┘
8. Deployment Readiness Checklist
[ ] Ingestion Decoupling
└─ Public webhook endpoint performs ONLY signature validation & queue publish.
└─ Measured p99 endpoint response time is < 20ms under load.
[ ] Signature Verification (both directions, if bidirectional)
└─ TikTok Shop: Authorization header, HMAC-SHA256(app_secret, app_key + raw_body), 401 on failure.
└─ BigCommerce: Standard Webhooks headers (webhook-id/-timestamp/-signature), 5-min timestamp tolerance.
[ ] Idempotency Safeguards
└─ Redis atomic lock (SET NX) keyed on tts_notification_id / BigCommerce hash+id, 24h+ TTL.
└─ Out-of-order resolution enforced via per-entity timestamp tracking.
[ ] Rate-Limiting & Batching
└─ BigCommerce inventory writes routed through Inventory API relative-adjustment batches
(up to ~2,000 items/request), not per-order Catalog calls.
└─ TikTok Shop calls back off on 429 rather than assuming a fixed QPS ceiling.
└─ Exponential backoff with full jitter on all outbound retries.
[ ] Resilience & Dead Letter Queues
└─ SQS DLQ active with a small maxReceiveCount (e.g. 5).
└─ Replay path tested in staging.
[ ] Platform Safety
└─ store/hook/deliveryException subscribed and alerting on 90001/90002/90003.
└─ Ingress latency kept well clear of BigCommerce's 90%-success/2-minute blocklist trigger.
Conclusion
Surviving a TikTok Shop flash sale on a BigCommerce backend comes down to refusing to do real work inside the webhook request/response cycle: verify the signature correctly (and per the right scheme — TikTok Shop's own, not the generic TikTok for Developers one), buffer everything through a queue built for bursty at-least-once delivery, de-duplicate on the right ID, and push inventory changes through BigCommerce's Inventory API in batches instead of one call per order. None of the individual pieces are exotic — the difference between an integration that survives a live-stream spike and one that doesn't is almost always which specific endpoint, header, and batch size you reached for.
Sources checked for this piece
- BigCommerce Developer Center — API rate limits, Webhooks overview, Inventory adjustments, Product Variants / batch update
- Hookdeck — Guide to BigCommerce Webhooks, TikTok Shop Webhooks skill and its signature verification reference
- TikTok for Developers — Rate limits, Shop Management APIs
- AWS — SQS queue types, High throughput for FIFO queues
- Standard Webhooks specification — standardwebhooks.com
- Industry GMV/live-shopping estimates: multiple third-party trackers (Dashboardly, Axis Intelligence, Momentum Works) — treated as directional estimates rather than official platform figures, given the range of numbers reported across sources.
Rate limits, header names, and retry windows are the kind of detail platforms change without much notice — re-verify against current docs before a launch you can't afford to get wrong.