> ## Documentation Index
> Fetch the complete documentation index at: https://docs.zapier.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Trigger Inbox onboarding

> Create your first inbox using a webhook trigger.

# Trigger Inbox onboarding

This article covers the core queue model of the [Trigger Inbox API](/white-label/trigger-inbox/what-is-trigger-inbox-api): create an inbox, send a message, lease it, and acknowledge it. It uses Webhooks by Zapier as the trigger so you can run the full lifecycle without connecting an external app.

Follow the steps individually to understand each part of the flow, or skip to the [complete script](#complete-script) at the bottom to run everything at once.

Once you understand this pattern, the [app tutorial](/white-label/trigger-inbox/create-trigger-inbox) covers connecting to apps like Slack or Gmail using the user's app connection.

## Before you begin

Node.js 18 or later, installed and available as `node`.

***

## Step 1: Get an access token

The Trigger Inbox API requires an access token to authenticate your requests. For local testing, use SDK client credentials. The webhook trigger used in this guide does not require an app connection, so SDK client credentials are all you need to follow along.

**1. Install the Zapier Platform CLI:**

If you already have the Zapier Platform CLI installed, skip to step 2.

```bash theme={null}
npm install -g zapier-platform-cli
```

**2. Log in and create credentials:**

```bash theme={null}
npx zapier-sdk login
npx zapier-sdk create-client-credentials
```

The response includes a `client_id` and `client_secret`. Copy both values.

**3. Exchange your credentials for an access token:**

```bash theme={null}
curl -s -X POST "https://zapier.com/oauth/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "client_secret=YOUR_CLIENT_SECRET" \
  -d "scope=external" | python3 -m json.tool
```

**4. Set the `access_token` value from the response:**

```bash theme={null}
export TOKEN="your-access-token-here"
```

<Note>
  SDK credentials are for testing only. For production applications that act on behalf of your users, use [JWT authentication](/white-label/implementation/token-exchange).
</Note>

***

## Step 2: Create the inbox

The webhook trigger requires two randomly generated values, a hook code and a seed, that form your unique webhook URL.

**1. Generate webhook codes and create the inbox:**

```bash theme={null}
HOOK_CODE=$(openssl rand -hex 6)
HOOK_SEED=$(openssl rand -hex 6)
INBOX_NAME="my-webhook-inbox-$(date +%s)"

curl -s -X POST "https://api.zapier.com/trigger-inbox/api/v1/inboxes" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "'"$INBOX_NAME"'",
    "subscription": {
      "app_key": "WebHookCLIAPI",
      "action_key": "hook_v2",
      "inputs": {
        "_zap_static_hook_code": "'"$HOOK_CODE"'",
        "_zap_static_hook_seed": "'"$HOOK_SEED"'"
      }
    }
  }' | python3 -m json.tool
```

**2. Set the inbox ID and webhook URL from the response:**

```bash theme={null}
INBOX_ID="<id from response>"
WEBHOOK_URL="https://hooks.zapier.com/hooks/catch/$HOOK_CODE/"
```

***

## Step 3: Wait for active

A new inbox starts in [`initializing`](/white-label/trigger-inbox/what-is-trigger-inbox-api#inbox-states) while Zapier sets up the trigger subscription. Do not send events or lease messages until the status is `active`.

**1. Poll until the inbox is active:**

```bash theme={null}
DELAY=5
while true; do
  STATUS=$(curl -s "https://api.zapier.com/trigger-inbox/api/v1/inboxes/$INBOX_ID" \
    -H "Authorization: Bearer $TOKEN" \
    | python3 -c "import sys,json; print(json.load(sys.stdin)['status'])")
  echo "Status: $STATUS"
  [ "$STATUS" = "active" ] && break
  if [ "$STATUS" = "initialization_failure" ]; then
    echo "Inbox setup failed. Check paused_reason, delete this inbox, and create a new one."
    exit 1
  fi
  sleep $DELAY
  DELAY=$(( DELAY < 60 ? DELAY * 2 : 60 ))
done
```

Go to [inbox states](/white-label/trigger-inbox/what-is-trigger-inbox-api#inbox-states) for a full description of each status.

***

## Step 4: Send a test event

**1. Send an HTTP POST to your webhook URL:**

```bash theme={null}
curl -s -X POST "$WEBHOOK_URL" \
  -H "Content-Type: application/json" \
  -d '{"event": "user.signup", "user_id": 42}'
```

The endpoint accepts the POST immediately. The message typically becomes available to lease within a few minutes.

***

## Step 5: Lease messages

Leasing claims a batch of messages and locks them for exclusive processing. No other consumer can claim them during the lease. If you do not acknowledge within the lease duration, the messages return to the queue automatically.

**1. Poll until messages are available:**

```bash theme={null}
DELAY=5
while true; do
  LEASE_RESPONSE=$(curl -s -X POST "https://api.zapier.com/trigger-inbox/api/v1/inboxes/$INBOX_ID/messages/lease" \
    -H "Authorization: Bearer $TOKEN" \
    -H "Content-Type: application/json" \
    -d '{"lease_seconds": 300, "lease_limit": 10}')

  LEASE_ID=$(echo "$LEASE_RESPONSE" \
    | python3 -c "import sys,json; print(json.load(sys.stdin).get('lease_id') or '')" 2>/dev/null)

  if [ -n "$LEASE_ID" ]; then
    echo "$LEASE_RESPONSE" | python3 -m json.tool
    break
  fi

  echo "No messages yet, retrying in ${DELAY}s..."
  sleep $DELAY
  DELAY=$(( DELAY < 60 ? DELAY * 2 : 60 ))
done
```

The response includes:

| Field                                                  | Description                                                                                                                                                     |
| ------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `lease_id`                                             | Required to acknowledge or release the batch.                                                                                                                   |
| `leased_until`                                         | When the lease expires. Messages return to the queue after this time if not acknowledged.                                                                       |
| `results[]`                                            | The leased messages.                                                                                                                                            |
| `results[].payload`                                    | The event data. Contains your POST body plus a `querystring` field that Zapier adds automatically. This field is empty (`{}`) if no query parameters were sent. |
| `results[].message_attributes.lease_count`             | How many times this message has been leased. Use this to identify repeatedly failing messages.                                                                  |
| `results[].message_attributes.possible_duplicate_data` | `true` if Zapier detected a possible duplicate delivery.                                                                                                        |
| `inbox_attributes`                                     | Current inbox status.                                                                                                                                           |

**2. Set the `lease_id` from the response:**

```bash theme={null}
LEASE_ID="<lease_id from response>"
```

Run your processing logic against the message payload before moving to the next step.

***

## Step 6: Acknowledge messages

Acknowledging permanently removes messages from the queue. Only acknowledge after processing succeeds.

**1. Acknowledge using the `lease_id` from Step 5:**

```bash theme={null}
curl -s -X POST "https://api.zapier.com/trigger-inbox/api/v1/inboxes/$INBOX_ID/messages/ack" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"lease_id": "'"$LEASE_ID"'"}' | python3 -m json.tool
```

A successful response returns each message with `"status": "acked"`.

<Note>
  If processing fails, do not acknowledge. Let the lease expire and the messages will return to the queue automatically. To return them immediately, use [release messages](/white-label/api-reference/messages/release-messages).

  The Trigger Inbox API uses [at-least-once delivery](/white-label/trigger-inbox/what-is-trigger-inbox-api#how-it-works). Build idempotent processing and check the message `id` before acting on a payload.
</Note>

To acknowledge specific messages within a lease rather than the full batch, add `"message_ids": ["id1", "id2"]` to the request body alongside `lease_id`.

***

## Step 7: Confirm the inbox is empty

After acknowledging, confirm there are no remaining messages.

**1. Attempt to lease with a limit of 1:**

```bash theme={null}
curl -s -X POST "https://api.zapier.com/trigger-inbox/api/v1/inboxes/$INBOX_ID/messages/lease" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"lease_limit": 1}' | python3 -m json.tool
```

An empty inbox returns `"lease_id": null` and `"results": []`.

***

## Step 8: Delete the test inbox

In production, inboxes are long-lived. Create them once and run the [lease-process-acknowledge cycle](/white-label/trigger-inbox/what-is-trigger-inbox-api#message-lifecycle) continuously. Delete an inbox only when decommissioning an integration entirely.

For this tutorial, delete the test inbox to cancel the trigger subscription.

**1. Delete the inbox:**

```bash theme={null}
curl -s -X DELETE "https://api.zapier.com/trigger-inbox/api/v1/inboxes/$INBOX_ID" \
  -H "Authorization: Bearer $TOKEN" | python3 -m json.tool
```

Deletion is partially asynchronous. If you named the inbox, the name is freed immediately, so you can reuse it as soon as your DELETE call returns. The inbox status changes to `deleting` until Zapier finishes removing the inbox and any remaining messages on the backend, but you can treat the inbox as effectively gone as soon as you get a 202 response.

***

## Complete script

Complete Step 1 first to get your access token, then set `TOKEN` and run the script:

```bash theme={null}
#!/usr/bin/env bash
# Trigger Inbox onboarding — complete script
# Prerequisites: TOKEN environment variable set
# Usage: export TOKEN="your-access-token" && bash onboarding.sh

set -euo pipefail

BASE_URL="https://api.zapier.com/trigger-inbox/api/v1"
HOOKS_URL="https://hooks.zapier.com"

# 1. Create the inbox
HOOK_CODE=$(openssl rand -hex 6)
HOOK_SEED=$(openssl rand -hex 6)
INBOX_NAME="quickstart-$(date +%s)"

echo "Creating inbox..."
INBOX_ID=$(curl -s -X POST "$BASE_URL/inboxes" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d "{
    \"name\": \"$INBOX_NAME\",
    \"subscription\": {
      \"app_key\": \"WebHookCLIAPI\",
      \"action_key\": \"hook_v2\",
      \"inputs\": {
        \"_zap_static_hook_code\": \"$HOOK_CODE\",
        \"_zap_static_hook_seed\": \"$HOOK_SEED\"
      }
    }
  }" | python3 -c "import sys,json; print(json.load(sys.stdin)['id'])")
echo "Inbox ID: $INBOX_ID"
echo "Webhook URL: $HOOKS_URL/hooks/catch/$HOOK_CODE/"

# 2. Wait for active (typically a few seconds)
echo "Waiting for inbox to become active..."
DELAY=5
while true; do
  STATUS=$(curl -s "$BASE_URL/inboxes/$INBOX_ID" \
    -H "Authorization: Bearer $TOKEN" \
    | python3 -c "import sys,json; print(json.load(sys.stdin)['status'])")
  echo "  Status: $STATUS"
  [ "$STATUS" = "active" ] && break
  if [ "$STATUS" = "initialization_failure" ]; then
    echo "Inbox setup failed. Check paused_reason, delete this inbox, and create a new one."
    exit 1
  fi
  sleep $DELAY
  DELAY=$(( DELAY < 60 ? DELAY * 2 : 60 ))
done

# 3. Send a test event
echo "Sending test event..."
curl -s -X POST "$HOOKS_URL/hooks/catch/$HOOK_CODE/" \
  -H "Content-Type: application/json" \
  -d '{"event": "user.signup", "user_id": 42}'
echo ""
echo "Event sent. Waiting for it to become available to lease..."

# 4. Lease messages
DELAY=5
while true; do
  LEASE_RESPONSE=$(curl -s -X POST "$BASE_URL/inboxes/$INBOX_ID/messages/lease" \
    -H "Authorization: Bearer $TOKEN" \
    -H "Content-Type: application/json" \
    -d '{"lease_seconds": 300, "lease_limit": 10}')

  LEASE_ID=$(echo "$LEASE_RESPONSE" \
    | python3 -c "import sys,json; print(json.load(sys.stdin).get('lease_id') or '')" 2>/dev/null)

  if [ -n "$LEASE_ID" ]; then
    echo "Messages leased:"
    echo "$LEASE_RESPONSE" | python3 -m json.tool
    break
  fi

  echo "  No messages yet, retrying in ${DELAY}s..."
  sleep $DELAY
  DELAY=$(( DELAY < 60 ? DELAY * 2 : 60 ))
done

# 5. Acknowledge
echo "Acknowledging messages..."
curl -s -X POST "$BASE_URL/inboxes/$INBOX_ID/messages/ack" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d "{\"lease_id\": \"$LEASE_ID\"}" | python3 -m json.tool

# 6. Confirm inbox is empty
echo "Confirming inbox is empty..."
curl -s -X POST "$BASE_URL/inboxes/$INBOX_ID/messages/lease" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"lease_limit": 1}' | python3 -m json.tool

# 7. Delete the test inbox
# In production, skip this step. Inboxes are long-lived infrastructure.
echo "Deleting test inbox..."
curl -s -X DELETE "$BASE_URL/inboxes/$INBOX_ID" \
  -H "Authorization: Bearer $TOKEN" | python3 -m json.tool

echo ""
echo "Quickstart complete."
```

***

## Next steps

* [Using triggers with Zapier SDK](/sdk/using-triggers).
* [Create a trigger inbox for an app](/white-label/trigger-inbox/create-trigger-inbox).
* [Consume messages](/white-label/trigger-inbox/consuming-messages).
* [Manage your inbox](/white-label/trigger-inbox/manage-your-inbox).
* [Trigger Inbox API reference](/white-label/api-reference/inboxes/list-inboxes).
