---
title: "Asynchronous Webhooks"
canonical: "https://red-ant-documentation.refined.site/space/RDD/558792731/Asynchronous%20Webhooks"
format: markdown
---
Asynchronous webhooks can be configured to push updates to external systems. Typically, this might be used to tell another system (for example, Salesforce) about a new customer or a new order that has been created within RetailOS


> Macro (toc)


## Setting up webhooks

Creating and amending webhooks are actioned by Red Ant. Requests for webhook changes should be supplied with the information in the ‘Integration configuration’ section. 

In addition, since our webhooks are different per environment (normally set up as QA, UAT and Production), it will need to be clear which environment this webhook is being set up for. For example, you may wish to have a UAT webhook pointed at a test CRM system, and a Production webhook pointed at your live CRM system.

## Integration configuration

This integration can be configured with the following parameters:

***Required***

- **url** - Webhook URL
- **method** - Webhook HTTP method

***Optional***

- **requestHeaders** - Object Key/Value pairs of request headers to send with the webhook request
- **shallow** - POST the data without nesting in a `data` property.
- **externalIdFrom** - Where a successful response is received, this property defines the path to use to extract the externalId for the updated resource
- **externalIdTo** - This defines the property name on the resource to store the externalId against
- **authenticator** - Authenticator config object if using OAuth2. If using just an API key, this is not required.
- **authenticator.name** - Authenticator name (currently only OAuth2 is supported)
- **authenticator.config.url** - OAuth2 authentication endpoint (POST request)
- **authenticator.config.resource** - Resource to request access (typically your webhook URL)
- **authenticator.config.client_id** - OAuth2 client id
- **authenticator.config.client_secret** - OAuth2 client secret
- **authenticator.config.grant_type** - OAuth2 grant type (typically `client_credentials`)
- **authenticator.config.username** - OAuth2 username (when using `password` grant type)
- **authenticator.config.password** - OAuth2 password (when using `password` grant type. If integrating with Salesforce, this will typically be concatenated with an api security token)
- **getOneQueryParams **- Query parameters to be utilised by the webhook when getting the payload data

Example Webhook integration configuration object (`client_credentials` grant type)

```
{
  "url": "https://example.com/your-webhook-endpoint",
  "method": "POST",
  "authenticator": {
    "name": "OAuth2",
    "config": {
      "url": "https://example.com/oauth2/token",
      "resource": "https://example.com/your-webhook-endpoint",
      "client_id": "example-client-uuid",
      "grant_type": "client_credentials",
      "client_secret": "example-client-secret",
      "getOneQueryParams": {
        "includes": [
          "store",
          "customer",
          "user",
          "previousOrder"
        ],
        "excludeNestedDetails": true
      }
    }
  },
  "requestHeaders": {
    "x-api-key": "some-api-key"
  }
}
```

Example Webhook integration configuration object (`password` grant type)

```
{
  "url": "https://example.com/your-webhook-endpoint",
  "method": "POST",
  "authenticator": {
    "name": "OAuth2",
    "config": {
      "url": "https://example.com/oauth2/token",
      "grant_type": "password",
      "client_id": "example-client-uuid",
      "client_secret": "example-client-secret",
      "username": "example-username",
      "password": "example-password"
    }
  }
}
```

Considering the below response received after the successful creation/update of a resource, the `crmID` refers to the external id of the resource. In order to generalise and account for different external systems we may wish to integrate with, you can define the `externalIdFrom` property in the api event config to extract this value, setting it to the path to the value within the response object. Using the example below, this would be set to: `'body.crmID'`. As the name of the property on the resource to store this value against may vary as well, you are able to define the name of this property by setting `externalIdTo` in the api event config also. For example, we could set this to `'externalCustomerId'`.

```
{
  "body": {
    {
      "success": true,
      "error": null,
      "crmID": "0035E00001WZ3i3QAD"
    }
  }
}
```

---

## Authentication and security

- **API Key**: An API key can be passed as part of the request headers to authenticate the request from RetailOS to external systems
- **OAuth2**: The OAuth2 authentication mechanism is supported. see the integration configuration for more information.

---

## Webhook implementation

The following are assumed expectations of any URLs that RetailOS pushes data to:

### Content type

RetailOS will send JSON data in all of its requests and expect JSON format in response. The following request headers will be sent:

```
Content-Type: application/json
Accept: application/json
```

### HTTP request body

RetailOS will send JSON data with an object property `data`, and the value as an object of the resource data. For example, a customer JSON request body will have a *shape similar to*:

***Example:***

```
{
    "data": {
        "id": "8348b38e-8fd0-4a24-b6db-45189bb9587f",
        "externalCustomerId": "example-customer-id",
        "title": "Mr",
        "gender": "Female",
        "firstName": "Example",
        "lastName": "Customer",
        "telephone": "+44 8800000000",
        "email": "89b7ae5e-351e-4ac1-9646-65c060d3bdb2@example.com",
        "dob": "01/01/1904",
        "generalMarketing": false,
        "thirdPartyMarketing": false,
        "storeMarketing": false,
        "smsMarketing": false,
        "emailMarketing": false,
        "postMarketing": false,
        "address": {
            "city": "",
            "county": "",
            "country": "",
            "address1": "",
            "address2": "",
            "postCode": ""
        },
        "details": {},
        "reporting": {},
        "anonymised": false,
        "registeredById": "012b6188-8d14-404e-b76a-8463abf420cf",
        "registeredAtId": "04a32e42-a27f-40c5-a173-29d7658266f7",
        "territoryId": "be35c9e2-a24e-4958-9bf6-7421996f3359",
        "createdAt": "2020-03-25T13:41:30.709Z",
        "updatedAt": "2020-03-25T13:41:30.709Z"
    }
}
```

Please see the up to date resource object model definitions at the [RetailOS SwaggerUI interface](https://digital-store-api-qa.redant.cloud/v2/public/docs)

### HTTP response status codes

RetailOS will use the HTTP status codes to determine whether an integration was successful/unsuccessful

- `2xx` responses are considered successful integrations
- `4xx and 5xx` responses are considered unsuccessful integrations

### HTTP response body

RetailOS will save the HTTP response (in JSON format) therefore it is advisable to respond with as much information as possible for unsuccessful requests to aid any debugging. Successful responses could also return any useful metadata, if applicable.

Example successful response

```
{
  "success": true,
  "error" null
}
```

Example unsuccessful response

```
{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Validation error",
    "details": [
      "Customer email is invalid"
    ]
  }
}
```

## IP Ranges

Due to RetailOS utilising flexible cloud infrastructure, by default, requests sent from RetailOS will originate from a highly dynamic range of IP addresses, the exact region varying based on which [AWS region](https://docs.aws.amazon.com/vpc/latest/userguide/aws-ip-ranges.html) your instance of RetailOS is hosted in. 

### Requesting a fixed IP range

If your servers require a fixed IP range as part of your security measures, RetailOS can support this at an additional cost. The exact cost can vary depending on use-case, so contact your Red Ant Account Manager to get started.