# Webhooks

Use the "Create Webhook Subscriber" endpoint and pass in a `callbackUrl` on your system that will receive a POST request for all of events listed below.&#x20;

Once the webhook subscriber is in place, you can have it choose to act on or disregard each of the following types of events.

### Webhooks Events

**Merchant events**

* `merchant.updated`
* `merchant.reinstall`

**Customer events**

* Account
  * `customer.created`
  * `customer.updated`
  * `customer.credits.updated`&#x20;
* Orders and Payments
  * `customer.ordered`&#x20;
  * `customer.resubscribed`
  * `customer.payment_succeeded`
  * `customer.payment_failed`
  * `customer.payment_methods.updated`
  * `customer_billing.attempt.failed`
* Cancellations **–**[ **more details below.**](#anecdote-cancellation-events)
  * `customer.cancellation_requested`&#x20;
  * `customer.confirmed_cancellation`&#x20;
  * `customer.cancelled`&#x20;
  * `customer.merchant_cancel`

### Create a Webhook Subscriber

**The `token` field in the response body for the Create Webhook Subscriber endpoint is important to take note of.** For security reasons, it only appears here, and in the body of post requests for events forwarded from the Inveterate system to the subscriber's `callbackUrl`. This will allow your 3rd party app to make sure the requests made to your endpoint are legitimate. Simply store the `token` value you get when you create the subscriber, and check for incoming events on your `callbackUrl` for a matching token in the request body.

## Create Webhook Subscriber

<mark style="color:green;">`POST`</mark> `https://public.inveterateapi.com/webhooks`

#### Headers

| Name                                                   | Type   | Description                                                                                            |
| ------------------------------------------------------ | ------ | ------------------------------------------------------------------------------------------------------ |
| X-Inveterate-Api-Key<mark style="color:red;">\*</mark> | String | Required to access all protected endpoints on this API. Obtained from merchant's Inveterate dashboard. |

#### Request Body

| Name                                          | Type   | Description                                                                                                   |
| --------------------------------------------- | ------ | ------------------------------------------------------------------------------------------------------------- |
| callbackUrl<mark style="color:red;">\*</mark> | String | The URL which will receive a POST request whenever an event should be passed from Inveterate to a subscriber. |
| name                                          | String | Descriptive name to help identify the subscriber.                                                             |

{% tabs %}
{% tab title="200: OK " %}

```javascript
{
    "success": true,
    "data": {
        "subscriber": {
            "merchantId": "inveterate-staging-barefoot",
            "id": "215498bda8d2169cc5db763377c0eda2",
            "token": "fe10df8a669462ee3ae368b0bfe5f910",
            "callbackUrl": "https://ztvfqj22g8.execute-api.us-east-1.amazonaws.com/prod/webhooks/callback-test",
            "name": "Webhook Subscriber Endpoint Test",
            "dateCreated": "2022-03-18T07:45:22.602Z",
            "dateUpdated": "2022-03-18T07:45:22.602Z",
            "createdByApp": "Default"
        }
    },
    "errors": []
}
```

{% endtab %}
{% endtabs %}

### Get Webhook Subscribers

You may have wondered about the `createdByApp` field in the response body for the "Create Webhook Subscriber" request. This is derived from the `app` field which is attached behind the scenes to your API key (the `X-Inveterate-Api-Key` one). For example, let's say you work at a SaaS company called "Smithy", and are developing an integration with Inveterate. Then the API key you are issued to access the Inveterate API will have an `app` field value of `Smithy`, and all the webhook subscriber objects created with your API key will have the same `createdByApp` value.

**TLDR: The "Get Webhook Subscribers" endpoint responds with all the webhook subscribers associated with the `X-Inveterate-Api-Key` included in the request.** Note that this is not necessarily all of the webhook subscribers associated with a particular merchant, but a particular app.

## Get Webhook Subscribers

<mark style="color:blue;">`GET`</mark> `https://public.inveterateapi.com/webhooks`

Get all webhook subscribers associated with this `X-Inveterate-Api-Key` value.

#### Headers

| Name                                                   | Type   | Description                                                                                            |
| ------------------------------------------------------ | ------ | ------------------------------------------------------------------------------------------------------ |
| X-Inveterate-Api-Key<mark style="color:red;">\*</mark> | String | Required to access all protected endpoints on this API. Obtained from merchant's Inveterate dashboard. |

{% tabs %}
{% tab title="200: OK " %}

```javascript
{
    "success": true,
    "data": {
        "subscribers": [
            {
                "merchantId": "inveterate-staging-barefoot",
                "id": "215498bda8d2169cc5db763377c0eda2",
                "callbackUrl": "https://ztvfqj22g8.execute-api.us-east-1.amazonaws.com/prod/webhooks/callback-test",
                "name": "Webhook Subscriber Endpoint Test",
                "dateCreated": "2022-03-18T07:45:22.602Z",
                "dateUpdated": "2022-03-18T07:45:22.602Z",
                "createdByApp": "Default"
            }        
        ]
    },
    "errors": []
}
```

{% endtab %}
{% endtabs %}

## Delete Webhook Subscriber

<mark style="color:red;">`DELETE`</mark> `https://public.inveterateapi.com/webhooks`

#### Headers

| Name                                                   | Type   | Description                                                                                            |
| ------------------------------------------------------ | ------ | ------------------------------------------------------------------------------------------------------ |
| X-Inveterate-Api-Key<mark style="color:red;">\*</mark> | String | Required to access all protected endpoints on this API. Obtained from merchant's Inveterate dashboard. |

#### Request Body

| Name                                 | Type   | Description        |
| ------------------------------------ | ------ | ------------------ |
| id<mark style="color:red;">\*</mark> | String | The subscriber id. |

{% tabs %}
{% tab title="200: OK " %}

```javascript
{
    "success": true,
    "data": {
        "subscriber": {}
    },
    "errors": []
}
```

{% endtab %}
{% endtabs %}

### Anecdote: Cancellation Events

Customer cancellation events follow different patterns depending on the cause of cancellation (payment failure or customer request) and, for the latter, also the store's cancellation policy.&#x20;

Please take a look at the trees of events below to see which cancellation lifecycle should be expected for a given customer, given the circumstances of their cancellation.

#### Event Timeline: Cancellation due to payment failure

Let's say the customer's payment was due on Jan 10, it failed then. Two more follow-up attempts will be performed over the next two days. If these two fail as well, then the customer will be automatically cancelled and will lose access to their benefits.

**Jan 10**

* **Event trigger:** `customer_billing.attempt.failed`&#x20;
  * If enabled in merchant's messaging, user also gets an e-mail communicating them of the payment failure and informing them that they have three days to update their payment methods.

**Jan 11**

* **Event trigger:** `customer_billing.attempt.failed`&#x20;

**Jan 12**

* **Event trigger:** `customer_billing.attempt.failed` , `customer.payment_failed`
* Customer gets cancelled and loses access to their benefits
  * if cancellation policy is immediately,  customer `status`: `ACTIVE` -> `CANCELLED`. Then `customer.cancelled`  event is triggered.&#x20;
  * &#x20;if cancellation policy is end of billing cycle,  customer `status`: `ACTIVE` -> `PENDING_CANCELLATION` . Then on the same day or the next day, customer gets cancelled and `customer.cancelled` event is triggered.&#x20;

#### Event Timelines: Cancellation due to customer request

*For stores with cancellation policy set to **immediate:***

* Customer requests cancellation
  * Event trigger: `customer.cancellation_requested`
* Confirmation e-mail is sent, asking customer to confirm
  * If user confirms e-mail
    * Event trigger: `customer.confirmed_cancellation`
    * Customer gets cancelled and loses access to their benefits
      * `status`: `ACTIVE` -> `CANCELLED`
    * Email gets sent: `Confirmed cancellation`
    * Event trigger: `customer.cancelled`

*Stores with cancellation policy set to **end of billing cycle:***

* Customer requests cancellation
* Event trigger: `customer.cancellation_requested`
* Confirmation e-mail is sent, asking customer to confirm
* If user confirms e-mail
  * Event trigger: `customer.confirmed_cancellation`
  * Customer update: `status` from `ACTIVE` -> `PENDING_CANCELLATION`
  * Email gets sent: `Confirmed cancellation`
  * When customer's billing cycle ends
    * Customer gets cancelled and loses access to their benefits
      * `status` from `PENDING_CANCELLATION` -> `CANCELLED`
    * Event trigger: `customer.cancelled`
