# Webhooks / Introduction

# Webhooks
Webhooks allow you to subscribe to a number of events in Shopfront that allow you application to act dynamically
and avoid having to schedule tasks to query Shopfront (and allows your application to be "live").

## Getting Started
To start using Webhooks, you'll first need to register a URL to receive an event.

You can register a webhook by using the [register webhook mutation](/documentation/Mutations/Webhooks#registerWebhook).

We support two different types of webhooks, one which is based off our GraphQL objects and one which is a "thin" layer.
If you need most of the details from a GraphQL object then the GraphQL webhooks are the best to use, but if you need
only a few pieces of information, it might be better to use the thin webhooks. Some GraphQL webhooks can become
quite large (e.g. the deprecated `REGISTER_CLOSED_DETAILED` can be a couple of megabytes depending upon the number
of sales).

An additional benefit of thin register closures are that they process quite quickly on our system, leading to less
delay between the event occurring and your application being notified.

### GraphQL Webhooks

The GraphQL webhooks return the specified GraphQL object (excluding connections) up to three levels deep. This may 
change in the future and if it does we will communicate changes directly to you via email. You can check the GraphQL 
endpoint by using the payload link below for the event you wish to receive.

| Event                    | Description                                                                                                            | Payload                                                                         |
|--------------------------|------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------|
| PRODUCT_CREATED          | A product has been created                                                                                             | [Product](/documentation/Objects/Products#Product)                              |
| PRODUCT_UPDATED          | A product has been updated (not called on inventory changes such as sales)                                             | [Product](/documentation/Objects/Products#Product)                              |
| PRODUCT_DELETED          | A product has been deleted                                                                                             | [Product](/documentation/Objects/Products#Product)                              |
| CUSTOMER_CREATED         | A customer has been created                                                                                            | [Customer](/documentation/Objects/Customers#Customer)                           |
| CUSTOMER_UPDATED         | A customer has been updated (not called on account balance changes such as sales and payments)                         | [Customer](/documentation/Objects/Customers#Customer)                           |
| CUSTOMER_DELETED         | A customer has been deleted                                                                                            | [Customer](/documentation/Objects/Customers#Customer)                           |
| PROMOTION_CREATED        | A promotion has been created                                                                                           | [Promotion](/documentation/Objects/Promotions#Promotion)                        |
| PROMOTION_UPDATED        | A promotion has been updated (not called when a promotion is sold)                                                     | [Promotion](/documentation/Objects/Promotions#Promotion)                        |
| PROMOTION_DELETED        | A promotion has been deleted                                                                                           | [Promotion](/documentation/Objects/Promotions#Promotion)                        |
| SALE                     | A sale has been completed (only completed sales are sent through this webhook, not parked sales)                       | [Sale](/documentation/Objects/Sales#Sale)                                       |
| SALE_PARKED              | A sale has been parked (this could be called multiple times if the sale is parked multiple times)                      | [Sale](/documentation/Objects/Sales#Sale)                                       |
| SALE_MODIFIED            | A sale has been modified (e.g. date has changed)                                                                       | [Sale](/documentation/Objects/Sales#Sale)                                       |
| SALE_CANCELLED           | A sale has been cancelled                                                                                              | [Sale](/documentation/Objects/Sales#Sale)                                       |
| PAYMENT                  | A customer payment has occurred                                                                                        | [Customer Payment](/documentation/Objects/Customers#CustomerPayment)            |
| ORDER_CREATED            | An order has been created                                                                                              | [Order](/documentation/Objects/Orders#Order)                                    |
| ORDER_SENT               | An order has been sent                                                                                                 | [Order](/documentation/Objects/Orders#Order)                                    |
| ORDER_RECEIVED           | An order has been received                                                                                             | [Order](/documentation/Objects/Orders#Order)                                    |
| ORDER_CANCELLED          | An order has been cancelled                                                                                            | [Order](/documentation/Objects/Orders#Order)                                    |
| REGISTER_CLOSED          | A register has been closed                                                                                             | [Register Closure](/documentation/Objects/Closures#RegisterClosure)             |
| REGISTER_CLOSED_DETAILED | _DEPRECATED_ A register has been closed (this contains every sale that was made during the time the register was open) | [Register Closure](/documentation/Objects/Closures#RegisterClosure)             |

### Thin Webhooks

The payload for thin webhooks returns only the ID of the object that the event occurred on (e.g. if the register was
closed, the payload would contain just a single field `id` that corresponds to the id of the closure).

| Event                  | Description                                                                                                                       |
|------------------------|-----------------------------------------------------------------------------------------------------------------------------------|
| THIN_PRODUCT_CREATED   | A product has been created                                                                                                        |
| THIN_PRODUCT_UPDATED   | A product has been updated (not called on inventory changes such as sales)                                                        |
| THIN_PRODUCT_DELETED   | A product has been deleted                                                                                                        |
| THIN_CUSTOMER_CREATED  | A customer has been created                                                                                                       |
| THIN_CUSTOMER_UPDATED  | A customer has been updated (not called on account balance changes such as sales and payments)                                    |
| THIN_CUSTOMER_DELETED  | A customer has been deleted                                                                                                       |
| THIN_PROMOTION_CREATED | A promotion has been created                                                                                                      |
| THIN_PROMOTION_UPDATED | A promotion has been updated (not called when a promotion is sold)                                                                |
| THIN_PROMOTION_DELETED | A promotion has been deleted                                                                                                      |
| THIN_SALE              | A sale has been completed (only completed sales are sent through this webhook, not parked sales)                                  |
| THIN_SALE_PARKED       | A sale has been parked (this could be called multiple times if the sale is parked multiple times)                                 |
| THIN_SALE_UNPARKED     | A sale has been unparked (removed from the parked sale, this could be called multiple times if the sale is parked multiple times) |
| THIN_SALE_MODIFIED     | A sale has been modified (e.g. date has changed)                                                                                  |
| THIN_SALE_CANCELLED    | A sale has been cancelled                                                                                                         |
| THIN_CUSTOMER_PAID     | A customer payment has occurred                                                                                                   |
| THIN_ORDER_CREATED     | An order has been created                                                                                                         |
| THIN_ORDER_SENT        | An order has been sent                                                                                                            |
| THIN_ORDER_RECEIVED    | An order has been received                                                                                                        |
| THIN_ORDER_CANCELLED   | An order has been cancelled                                                                                                       |
| THIN_REGISTER_CLOSED   | A register has been closed                                                                                                        |
| THIN_INVENTORY_UPDATED | A product's inventory has been changed (e.g. a Sale has been performed or an Invoice has been received)                           |
| THIN_TICKET_QUEUED     | A ticket has been queued for printing                                                                                             |
| THIN_TICKET_PRINTED    | A ticket has been printed from the queue                                                                                          |
| THIN_TICKET_DELETED    | A ticket has been deleted from the queue                                                                                          |

### Miscellaneous Webhooks

These are webhooks that don't have a common payload, these are typically related to something that can't be described by
the standard webhook system.

Details on the payloads for these can be found on the [Custom Webhooks page](/documentation/Webhooks/Custom).

- `INTEGRATION_REVOKED`
- `OUTLET_CREATED`
- `OUTLET_DELETED`
- `REGISTER_CREATED`
- `REGISTER_DELETED`
- `CUSTOMERS_MERGED`
- `INVENTORY_UPDATED`
- `BULK_INVENTORY_UPDATED`
- `ORDER_ATTACHMENT_UPLOADED`
- `ORDER_ATTACHMENT_DELETED`

## Removing Webhooks
If your webhook is no longer required, you should remove it by using the [remove webhook mutation](/documentation/Mutations/Webhooks#removeWebhook).

## Receiving Webhooks
Once your webhook is registered and the event occurs you'll receive a JSON payload that will look similar to:

```json
{
    "id": "12adf-445-a",
    "event": "PRODUCT_CREATED",
    "timestamp": "2019-01-01T10:00:00+00:00",
    "vendor": "example",
    "failedAttempts": 0,
    "webhookId": "11e6...",
    "payload": {},
    "context": null
}
```

The ID is a unique alphanumeric string for the request, you can use it to ensure that you don't receive the payload
multiple times (more about retry rules below). 

The event is the corresponding event that you are registered to.

The timestamp is the time the server first attempted to send the message.

The vendor is the subdomain of the vendor that the event belongs to.

The payload varies depending upon the event. See above for the type of payload that will be received corresponding
to the event you're registered to.

The context may be present in some webhooks, it contains more information about the event that caused the webhook to fire.
If present, its contents will be detailed under the webhook's name in the [Custom](/documentation/Webhooks/Custom) documentation.
If not present, it will be set to `null`

We also two additional headers `X-Shopfront-Signature` and `X-Shopfront-Signature-Time`, these can be used to [verify 
the event came from Shopfront](/documentation/Webhooks/Verification).

Once you've received the webhook you'll need to return a response with a 2xx status (e.g. 200, 204) and
with no body. If there is a body or the status is not in the 2xx range, the webhook will be marked as failed.

You'll need to return the response within 30 seconds or the webhook will automatically time out and be marked as failed.

## Failing Webhooks
When your webhook fails, it will be put back into the queue to send at a later point in time. After the first failure,
it will attempt to send the webhook again in 1 - 5 minutes. If it fails a second or third time, it will attempt to send 
the webhook again in 5 - 15 minutes (of failure). If it fails a fourth time, the event will be removed from the queue 
and your webhook will be made inactive which will require you to reactivate it.

> If your webhook is failing, but has not yet been made inactive, other events will still fire. This could result in 
> the handling of data out of order. You can use the webhook's `timestamp` to verify the intended order of each received 
> event.

To reactivate a webhook you'll need to use the [activate webhook mutation](/documentation/Mutations/Webhooks#activateWebhook).

## Inactive Webhooks
If your webhook is marked as inactive for at least 6 months, it will be deleted from our system