# TikTok Shop Webhooks

## When to Use This Skill

* How do I receive TikTok Shop webhooks?
* How do I verify TikTok Shop webhook signatures?
* How do I handle ORDER_STATUS_CHANGE or PACKAGE_UPDATE events?
* Why is my TikTok Shop webhook signature verification failing?
* Setting up TikTok Shop webhook handlers and event subscriptions

## Verification (core)

TikTok Shop puts the signature in the `Authorization` header (no `Bearer`
prefix) as a lowercase-hex HMAC-SHA256. The signed message is your
`app_key` concatenated with the raw request body, keyed by your `app_secret`.
Verify against the raw body exactly as received — don't `JSON.parse` first.

> This is not the Standard Webhooks spec and is distinct from TikTok Shop's
> API request signing. There is no timestamp in the signature, so it offers
> no replay protection — dedupe on `tts_notification_id` and reconcile by polling.

```javascript
const crypto = require('crypto');

// sign base = app_key + rawBody ; key = app_secret ; digest = lowercase hex
function verifyTikTokShop(rawBody, authHeader, appKey, appSecret) {
  const expected = crypto
    .createHmac('sha256', appSecret)
    .update(appKey + rawBody)          // rawBody: exact bytes received, as UTF-8
    .digest('hex');
  try {
    return crypto.timingSafeEqual(
      Buffer.from(authHeader || '', 'utf8'),
      Buffer.from(expected, 'utf8')
    );
  } catch {
    return false;                      // length mismatch = invalid
  }
}

```

Return HTTP 200 with an empty body within 3 seconds on success; return
401 to signal a rejected signature.

> For complete handlers with route wiring, event dispatch, and tests, see:
> 
> * [examples/express/](https://github.com/hookdeck/webhook-skills/tree/main/skills/tiktok-shop-webhooks/examples/express/)
> * [examples/nextjs/](https://github.com/hookdeck/webhook-skills/tree/main/skills/tiktok-shop-webhooks/examples/nextjs/)
> * [examples/fastapi/](https://github.com/hookdeck/webhook-skills/tree/main/skills/tiktok-shop-webhooks/examples/fastapi/)

## Common Event Types

Subscribe to event types per shop in Partner Center (or via the Events API).
Subscriptions are configured by `event_type` string (one callback URL per
topic). The delivered payload carries a numeric `type` — TikTok Shop's
docs state they do not publish a complete numeric mapping and warn: "Do
not branch only on the numeric type; use the subscribed event_type context and
the topic-specific payload schema." Only `type: 1` (ORDER_STATUS_CHANGE)
appears in the official sample payload. The most robust pattern is a distinct
callback path per subscribed topic, so the route identifies the event.

Core `event_type` values (from the official topic reference):

| `event_type` | Triggered when |
| --- | --- |
| `ORDER_STATUS_CHANGE` | An order is created or its status changes |
| `RECIPIENT_ADDRESS_UPDATE` | The recipient address of an order is updated |
| `PACKAGE_UPDATE` | A package is combined, split, or changed |
| `PRODUCT_STATUS_CHANGE` | Product audit results are updated |
| `SELLER_DEAUTHORIZATION` | A seller revokes or loses authorization for the app |
| `UPCOMING_AUTHORIZATION_EXPIRATION` | Sent 30 days before authorization expires, then daily |

Additional subscribable topics: `CANCELLATION_STATUS_CHANGE`,
`RETURN_STATUS_CHANGE`, `REVERSE_STATUS_UPDATE`, `NEW_CONVERSATION`,
`NEW_MESSAGE`, `NEW_MESSAGE_LISTENER`, `PRODUCT_INFORMATION_CHANGE`,
`PRODUCT_CREATION`, `PRODUCT_CATEGORY_CHANGE`, `PRODUCT_AUDIT_STATUS_CHANGE`,
`INVOICE_STATUS_CHANGE`. See [references/overview.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/tiktok-shop-webhooks/references/overview.md).

## Payload Structure

```json
{
  "type": 1,
  "tts_notification_id": "7012345678901234567",
  "shop_id": "7009876543210987654",
  "timestamp": 1633174587,
  "data": { "order_id": "5769...", "order_status": "AWAITING_SHIPMENT" }
}

```

## Environment Variables

```bash
TIKTOK_SHOP_APP_KEY=your_app_key        # From Partner Center → App details
TIKTOK_SHOP_APP_SECRET=your_app_secret  # From Partner Center → App details (keep secret)

```

## Local Development

```bash
# Start tunnel (no account needed) — endpoint must be public HTTPS
npx hookdeck-cli listen 3000 tiktok-shop --path /webhooks/tiktok-shop

```

TikTok Shop requires an HTTPS endpoint on a domain (no IP, no custom port),
TLS 1.2+. Configure the URL under App & Service → your app → Basic
Information → Developing → Webhook URL / Event subscriptions, or via the
Events API (`PUT/GET/DELETE https://open-api.tiktokglobalshop.com/event/202309/webhooks`).

## Reference Materials

* [references/overview.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/tiktok-shop-webhooks/references/overview.md) - TikTok Shop webhook concepts and events
* [references/setup.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/tiktok-shop-webhooks/references/setup.md) - Partner Center configuration and Events API
* [references/verification.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/tiktok-shop-webhooks/references/verification.md) - Signature verification details and gotchas