Webhooks merchant documentation
What are webhooks
Webhooks notify you about events that occur with regards to the payments that you process via Ingenico ePayments, like status changes on payments. You can select which type of events you want to be notified about and where we should send them to. This allows you to be easily aware of things that happen, even after the consumer is no longer on your site.
When to use webhooks
Whenever an event occurs in your Ingenico ePayments account you most likely want to be informed. Webhooks provides this information by doing a POST request to one or more HTTPS endpoints on your server.
There are two ways events can be triggered: as a direct result of an API call you do, or by something ‘out of your sight’. Events of the first type don't add much value for you since you'll be informed about them via the API call's response anyway. However, events of the second type are more interesting to subscribe to using webhooks. Let's take a look at an example:
The online authorization of a redirect payment only happens after the consumer finishes the process at the 3rd party provider. This action is not visible to you as the consumer is not on your website at that time. You could periodically check the current payment status using our API ('poll'), but that is not very efficient. Using webhooks however, you can subscribe to one or more payment events, which will trigger us to do a POST request to an HTTPS endpoint on your server at the moment the payment status changes. Or in webhooks terms: when the 'event occurs'.
We will include the full JSON 'payment' object in that message, so you have all relevant information directly at hand.
Currently we support events that happen on payments, payouts and refunds . Please see the Webhooks event types page to see all events that webhooks can inform you about.
Preparing to use webhooks
To start using webhooks you need to do two things:
- Configure webhooks in the configuration center.
This way we know which event(s) you are interested in and to which endpoints we should send them.
- Set up your webhooks endpoint.
This means that you need to build an application that handles incoming webhooks events and run that on an HTTPS endpoint on your server. Our server SDKs can help you with common tasks like translating the JSON into objects and signature verification. Please also notice the S in HTTPS, since we only support encrypted communication. Your application should be able to:
- Respond to get GET action and echo the 'X-GCS-Webhooks-Endpoint-Verification' header value in the body.
- Respond to the POST action with a 2XX status code for all events delivered.
- Validate the signature on the message.
We will explain all this in more details in the remainder of this page.
Configuring webhooks in the configuration center
To set up webhooks in the configuration center you need to do two things:
- Create a webhooks key.
You can do this in the configuration center on the 'webhooks keys' page. Click on the 'request webhooks key' button. Just like with the API key, this key is used to sign the messages that are sent between you and us. In the webhooks case we sign the message and you should verify the signature to make sure that it was indeed sent by us. Verification of the signature occurs automatically if you use one of our server SDKs, or eCommerce plugins. Since webhooks keys are defined per account they are used to sign the messages of all your listed merchant ids. You do not need to create a webhooks key per merchant id.
- Add one or more webhooks endpoints.
If you have more than one merchant id connected to your account then first select the merchant id for which you would like to add an endpoint. Then open the 'webhooks' page, and click on the 'add endpoint' button. In the popup provide the endpoint's secure (HTTPS) URL and select which type of events it needs to receive. You can either choose to subscribe to all event types or to a subset that you can select in the popup as well.
To make sure the URL is a valid webhooks endpoint we do an HTTPS GET request to it as soon as it is created. This request includes a random string in the 'X-GCS-Webhooks-Endpoint-Verification' HTTP header. The endpoint's response should be a plain text body that contains only the value of this header. If your endpoint fails to do this it will still be added to your list of endpoints, but it will be deactivated. If this happens you can fix the issue on your end and then use the endpoint's 'activate' action at a later moment, which will trigger that validation call again. The endpoint will start receiving messages a couple of minutes after it has been successfully activated.
You can add up to five endpoints per merchant id. You will only be able to have one endpoint subcribed to a specific event.
Keep in mind that it can take up to 10 minutes for webhooks to have picked up changes you made in the configuration center.
Please see the FAQ below for more details on configuring webhooks.
Setting up your webhooks endpoint
The webhooks messages will be sent to your endpoints via HTTPS POST requests. The body of the request contains JSON that describes the event and the object the event occurred on. The structure of these objects is identical to the objects that are returned in our REST API. For instance the 'payment' object in a webhooks message is identical to the object that is returned by the get payment REST endpoint. See the Webhooks event structure page for a detailed explanation of the webhooks message structure.
To actually handle these incoming messages you should set up your server to listen to both POST and GET requests on the endpoints you've set up in the configuration center. POST for the handling of the actual messages and GET for the URL validation as mentioned in the previous section. How this is done depends on your server technology. If you're using one of our eCommerce plugins you can simply use the plugin's configuration page to set this up.
The PrestaShop webhooks screen where merchants can configure the webhooks keys.
In case you cannot use one of the eCommerce plugins you should configure the framework that you're using to listen on the endpoints and pass the request to our SDK. The SDK will check the signature and will return an actual object instead of the JSON that was included in the request. You can then pass this data into you own business logic.
Responding to a webhooks event
All successfully received webhooks messages should return an HTTP status code in the 2xx range. Any additional information in the body or header is ignored. Whenever an endpoint responds with a status code that is not in that range, webhooks assumes that your endpoint did not receive the messaged and it will retry at a later time. This means that HTTP redirects, which are 3xx codes, will also fail. See 'retrying failed events' further down for more information on how webhooks performs retries.
If an endpoint does not respond within 10 seconds webhooks will also assume your endpoint did not receive the message and we will retry at a later time. To prevent this, it is important to decouple as much of your business logic from the handling of the request as possible. We suggest that you respond with an 2xx HTTP status code immediately after receiving the message and handle all other tasks afterwards.
Testing webhooks endpoints
Now you can use the configuration center to test your endpoints. You can do this inside the configuration center, select your desired merchant id, and go to the 'Webhooks' page. There you can, for the endpoint you want to test, click on the 'Actions' pulldown menu en select 'Test'. This action will result in webhooks executing a POST request to that endpoint with a dummy event. In the popup you can see if the test was successful, or if something went wrong. Successful means that we could reach your endpoint and that it responded with the expected 2xx status code before the request timed out. The popup also shows you the request we made, the response that we received from the endpoint, and how long it took the endpoint to reply.
Common issues found while testing are:
- An endpoint redirect to a different URL using an HTTP 30x status code. Webhooks does not accept redirects. The required response status code needs to be in the 2xx range.
- Webhooks requests are blocked on your end due to the webhooks IP not being in your whitelist. You may need to whitelist our webhooks IPs.
- The request times out before the endpoints returns a response. Make sure your endpoint responds within 10 seconds.
The test described above only checks if webhooks can reach the endpoint. If you want to test if an endpoint handles the different event types correctly you'll have to actually use our REST API to make calls that trigger the desires event. For example: if you want to test the handling of a 'captured' event on a payment object you'll have to create a payment using the REST API that will trigger a 'captured' event. You can use our preproduction environment to make these test calls without actually making payments.
We will send events to the endpoints as quickly as possible, typically a few seconds after its occurrence. In rare circumstances the delivery may take longer, but in all cases the first delivery attempt will take place within 24 hours of the event's creation time.
Some known limitations are:
- The order in which we'll send the events might be different from the order in which they occurred. Mostly they will be in order, but keep in mind that this may not always be the case. A common case where this happens is when the first delivery attempt of an event failed and before it is retried a second event occurs which is immediately succefully delivered.
- Event can be sent more than once. Since all events have a unique id you can protect against this by verifying that an event's id has not already been handled earlier.
How webhooks will retry failed deliveries of events
Whenever a message was not successfully received by an endpoint two things will happen:
- If an endpoint fails too often we will temporarily stop sending messages to it by temporarily blacklisting the endpoint
- We will retry to send the failed message and all skipped messages at a later time
If 5 consecutive messages will fail to get delivered to an endpoint we will stop sending messages to that endpoint for 5 minutes. This is called 'blacklisting of the endpoint'. All messages that should have been sent while the endpoint was blacklisted will be sent at a later time via the retry mechanism. We use blacklisting because it's very likely that the endpoint is offline or overloaded for some time and it often takes a couple at minutes before it gets back online again. Sending messages will most likely result in failed delivery which will potentially only overload the endpoint even more.
We will retry to deliver each failed message, but we'll delay the resending of that message a little longer with each unsuccessful attempt. The list below shows the times at which we'll retry relative to the initial delivery attempt. For instance the 7th retry will happen 8 hours after the first time we sent the event to the endpoint The 8th retry will happen a full 8 hours after that: 16 hours after our first attempt.
|Retry attempt||Retry time relative to first delivery attempt|
We consider an event undeliverable after 10 retry attempts, meaning 48 hours after our first attempt. Currently we do not offer manually resending of events, but you can of course use our REST API to retrieve the state of the objects you are interested in.
The messages will be signed with the key that has been added first, so the oldest key is what we'll use. If we would use the most recently created key we could break the system since you would not have had time to configure the new key on your servers yet. The safest way to incorporate this on your end is to look at the request's X-GCS-KeyId HTTP header which contains the key id of the key that we used to sign the message. You can look up the secret key in your own configuration based on that key id.
For security it's best to have "separate keys for separate things". Signing REST API calls and verifying the signature of webhooks messages are two different things each with their own level of sensitivity. Having two keys allows you to handle signing REST API calls and verifying webhooks messages on different machines (with perhaps different security measures in place) without having to deploy a single "superkey" on both systems. It also allows us to handle the keys differently, as we for instance do with respect to the expiration time: the webhooks key does not expire, but the REST API key does.
Since the REST API calls can contain sensitive card information PCI/DSS requires us to use keys that expire. Adding an expiration date to a key requires you to periodically change these keys, so it increases the complexity of your operational processes. Since the webhooks messages do not contain any sensitive card information we decided to not use expiration dates on the webhooks keys so we can keep the webhooks integration as simple as possible.
You can always manually validate the signature. The validation process works as follows:
- Retrieve the key id from the X-GCS-KeyId header.
- From your own configuration: retrieve the webhooks secret key belonging to that webhooks key id.
- Retrieve the body of the request and convert it to bytes using UTF-8 encoding.
- Create an HMAC-SHA256 signature of the resulting byte array and the webhooks secret key.
- Encode the created signature using base64.
- Retrieve the signature we created from the request's X-GCS-Signature HTTP header and verify it is the same as the base64 encoded signature you just created.
- Below is an example in Java.
String signature = getHeaderValue(requestHeaders, "X-GCS-Signature");
String keyId = getHeaderValue(requestHeaders, "X-GCS-KeyId");
String secretKey = secretKeyStore.getSecretKey(keyId);
Mac hmac = Mac.getInstance("HmacSHA256");
SecretKeySpec key = new SecretKeySpec(secretKey.getBytes(CHARSET), "HmacSHA256");
byte unencodedResult = hmac.doFinal(body);
String expectedSignature = Base64.encodeBase64String(unencodedResult);
boolean isValid = areEqualSignatures(signature, expectedSignature);
You can of course also copy the validation code from the SDKs. The table below contains links to the SDK files in Github that contain the relevant code.
SDK / Language SDK file Method or function in file .NET WebhooksHelper.cs ValidateBody Go webhooks/Helper.go validate Java WebhooksHelper.java validateBody Node.js webhooks/index.js validateBody PHP WebhooksHelper.php validateBody Python 2 web_hooks_helper.py __validate_body Python 3 web_hooks_helper.py __validate_body Ruby webhooks_helper.rb validate_body
Changing the webhooks key needs to be done carefully because otherwise the events that are sent to you may be signed with a key that you do not have configured yet. It's best to follow these steps:
- Create a second key in the configuration center. Webhooks will still sign all events with old one.
- Now add the new key to your server configuration. Do not override the old one, just add it.
- Now delete the old key in our configuration center. From that moment we will sign the messages with the new key
- For a couple of minutes the incoming messages can be signed with either the new or the old key depending on if they were signed before or after the deletion of the old key. It's important that your code uses the X-GCS-KeyId to determine which key should be used for validating. If you are using the eCommerce plugins this will be done automatically as long as you configure the plugin with both the old and the new webhooks key. Keep in mind that messages that are in our retry queue will be signed with the new key at the moment they are sent again.
- After an hour you can safely remove the old key from the plugin config so the only key that is still configured is the new one.
I changed the webhooks configuration in the configuration center but the changes aren't picked up. What can I do?
It can take up to 10 minutes for webhooks to have picked up changes you made using the configuration center. Both for webhooks key changes and for endpoint changes, including activating or deactivating endpoints.
No, all endpoints need to be unique within one merchant, even without taking the subscribed events into account. We do this to prevent merchants from mistakenly adding two identical endpoints. As an easy fix you can add dummy query parameters to one of the endpoint's URL so they become different.
Will I receive webhooks messages for events that were triggered by a different account on a merchant that we both manage?
In some setups two or more accounts manage the same merchant. If one of those accounts triggers an event then all subscribed endpoints of all accounts that manage that merchant will receive a webhooks messages. The message is signed with the webhooks key of the account the endpoint belong to, so you will be able to verify the signature. The message itself does not show which account triggered the event, if any. If your integration makes use of this setup make sure to handle this scenario.
Yes, you can use the same endpoint since the merchant id is part of the message body.This makes it possible for your single endpoint to figure out for which merchant the message is meant. However: you will have to add that endpoint to each merchant separately in the configuration center.
No, this can not be prevented in all cases. You should make sure you can handle these situations. Since all events have a unique id you can protect against this by verifying that an event's id has not already been handled earlier. Since the unique id is part of the message body and thus also included in the messages signature this check will also guard against replay attacks.
Here are some examples of when we'll send an event twice:
- Your endpoint did receive the message but the request timed out before you could send a proper response. We have no choice but to conclude that the delivery failed so we will retry sending the message at a later time. From your perspective this would look like us sending the same event twice.
- Your endpoint did receive the message but did not send back an HTTP status code in the 2xx range. We will also retry in such a case.
- The webhooks system experienced some issues and, for some event, wasn't able to reliably determine if they had already been delivered. These events will be send again to make sure that the endpoints received them at least once.
CSRF tokens are a security measure that websites use to prevent cross-sIte request forgery attacks. Although this is a very important feature of the framework it will also prevent your server from successfully handling incoming webhooks requests. You will have to add an exception for the webhooks endpoints for webhooks to work properly.