> For the complete documentation index, see [llms.txt](https://native-app-co.gitbook.io/stork-credit/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://native-app-co.gitbook.io/stork-credit/integrations/external-triggers.md).

# External triggers

Issue store credit from Klaviyo, Zapier, Make, or any tool that can send a webhook.

External triggers give your store a **private webhook endpoint**. Send it a POST request and it credits a customer. That opens up every reward that starts outside Shopify: a review submitted in Klaviyo, a referral confirmed in a partner tool, a goodwill credit issued from your helpdesk.

Open **Settings**, then click **Manage external triggers**.

{% hint style="warning" %}
External triggers are available on the **Pro** plan. On Free and Grow, the **Manage external triggers** link in **Settings** is greyed out and labelled **Pro plan**, and the **External triggers** page is shown greyed out with its endpoint and secret hidden. Your endpoint and secret are kept while you're on another plan, and start accepting requests again as soon as you move to Pro. See [Plans & billing](/stork-credit/reference/plans-and-billing.md#external-triggers).
{% endhint %}

## Your endpoint

The page gives you two values:

* **Webhook URL** — unique to your store.
* **Secret** — proves the request came from you.

Copy both into the tool that will be sending requests.

### Authentication

Send the secret in the `X-Stork-Secret` header:

```
X-Stork-Secret: your-secret-here
```

If your tool can't set custom headers, pass it as a `?secret=` query parameter on the URL instead. The header is preferable — query strings turn up in logs.

Requests with a missing or wrong secret are rejected with `401`.

## Request body

Send JSON:

```json
{
  "email": "customer@example.com",
  "amount": "10.00",
  "currency": "USD",
  "reason": "Review reward",
  "expires_on": "2026-12-31",
  "external_id": "{{ event_id }}"
}
```

| Field         | Required | Description                                                  |
| ------------- | -------- | ------------------------------------------------------------ |
| `email`       | Yes      | The customer to credit. A customer is created if none exists |
| `amount`      | Yes      | The credit amount, e.g. `"10.00"`                            |
| `external_id` | Yes      | A unique ID for this event. Used to de-duplicate retries     |
| `currency`    | No       | ISO code. Defaults to your shop's primary currency           |
| `reason`      | No       | A note shown in the activity log, e.g. `"Review reward"`     |
| `expires_on`  | No       | A future date. Omit for credit that never expires            |

## De-duplication

`external_id` is what makes the endpoint safe to call from tools that retry.

Each `external_id` is credited **at most once per store**. A repeat request with an ID already seen is acknowledged but issues nothing. Since most tools retry on timeouts and network errors, this is what stands between you and accidental double credits.

{% hint style="danger" %}
Use a value that is genuinely unique **per reward event** — your source tool's event ID is ideal. A constant, or something that repeats like a customer ID, means only the first request ever credits anyone.
{% endhint %}

## Enabling and disabling

The endpoint has an **Enabled/Disabled** switch. Disabling makes it reject everything without deleting the URL or secret — useful for pausing an integration you're debugging.

## Rotating the secret

**Regenerate secret** issues a new one immediately.

{% hint style="warning" %}
The old secret stops working the moment you regenerate. Any integration still using it starts failing straight away — update your external tools right after rotating.
{% endhint %}

## Activity log

The page lists the **last 20 requests** that reached your endpoint: when, which customer, how much, the reason you sent, and whether it credited. This is the first place to check when an integration seems quiet.

## Connecting Klaviyo

Klaviyo's no-code webhook action is enough — no custom code.

{% stepper %}
{% step %}

#### Add a Webhook action to your flow

In the Klaviyo flow builder, add a **Webhook** action.
{% endstep %}

{% step %}

#### Set the URL

Paste the webhook URL from Stork Credit.
{% endstep %}

{% step %}

#### Add the secret header

Add a header, `X-Stork-Secret`, with your secret as the value.
{% endstep %}

{% step %}

#### Build the JSON body

Map `email` to the profile's email, set the `amount`, and set `external_id` to Klaviyo's event ID so retries de-duplicate.
{% endstep %}
{% endstepper %}

Zapier, Make, n8n, and anything else that can POST JSON with a custom header follow the same shape.

## Notifications

External triggers do **not** send Shopify's store credit email. The tool sending the webhook is usually the better place to message the customer — it has the context for it.

## Troubleshooting

| Symptom                             | Likely cause                                                         |
| ----------------------------------- | -------------------------------------------------------------------- |
| `401` responses                     | Wrong secret, or the secret was rotated and the tool wasn't updated  |
| Requests accepted, nothing credited | A repeated `external_id` — check the activity log                    |
| Nothing in the activity log         | Requests aren't arriving; check the URL, or the endpoint is disabled |
| Customer not found                  | Not an error — a customer is created automatically                   |
