Webhook endpoint
Listen to events in your Ophelos account on your webhook endpoints so your integration and automatically trigger reactions.
When building Ophelos integrations, you might want your applications to reiceve events as they occur in your Ophelos accounts, so that your back-end systems can execute actions accordingly.
Create a webhook endpoint to receive events via HTTPS. After you register a webhook event, Ophelos can push real-time event data to your application's webhook endpoint when events happen in your Ophelos account. Ophelos uses HTTPS to send webhook events to your application as a JSON payload that includes a Event object.
Receiving webhook events is particulary useful for listening to asynchronous events such as when payments are received, when a customer accepts a payment plan, or when debts are fully paid.
Getting started
To start receiving webhook events in your app, create and register a webhook endpoint:
- Create a webhook endpoint handler to receive event data POST requests.
- Register your endpoint within Ophelos using the API.
- Secure your webhook endpoint.
You can register and create one endpoint to handle several different event types at the same time, or setup individual endpoints for specific events.
1. Create a handler
Set up an HTTPS endpoint function that can accept webhook requests with a POST method. If you're still developing your endpoint function on your local machine, it can use HTTP. After it's publicly accessible, your webhook endpoint must use HTTPS.
Setup your endpoint function so that it:
- Handles POST request with a JSON payload consisting of an event object.
- Quickly returns successful status code (
2XX
) prior to any complex logic that could cause a timeout.
2. Test your handler
Before you go-live with your webhook endpoint function, we recommend that you test your application integration. You can do so by constructing event payloads in your favourite API request constructor.
3. Register your endpoint
After testing your webhook endpoint function, register the webhook endpoint's accessible URL using the API so Ophelos knows where to deliver etents. Registered webhook endpoints must be publicly accessible HTTPS URLs.
Webhook URL format
The URL format to register a webhook endpoint is:
https://<your-website>/<your-webhook-endpoint>
For example, if your domain is https://mycompanysite.com
and the route to your webhook endpoint is /ophelos_webhooks
, specity https://mycompanysite.com/ophelos_webhooks
as the Endpoint URL.
Register a webhook endpoint within the Ophelos API
You can programmatically create webhook endpoints.
The following example creates an endpoint that notifies you when a payment is successful and a debt is updated.
curl --request POST \
--url https://api.ophelos.dev/webhooks \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '
{
"enabled_events": [
"payment.succeeded",
"debt.updated"
],
"url": "https://example.com/ophelos_webhook"
}
'
const url = 'https://api.ophelos.dev/webhooks';
const options = {
method: 'POST',
headers: {accept: 'application/json', 'content-type': 'application/json'},
body: JSON.stringify({
enabled_events: ['payment.succeeded', 'debt.updated'],
url: 'https://example.com/ophelos_webhook'
})
};
fetch(url, options)
.then(res => res.json())
.then(json => console.log(json))
.catch(err => console.error(err));
require 'uri'
require 'net/http'
url = URI("https://api.ophelos.dev/webhooks")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["accept"] = 'application/json'
request["content-type"] = 'application/json'
request.body = "{\"enabled_events\":[\"payment.succeeded\",\"debt.updated\"],\"url\":\"https://example.com/ophelos_webhook\"}"
response = http.request(request)
puts response.read_body
<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.ophelos.dev/webhooks",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'enabled_events' => [
'payment.succeeded',
'debt.updated'
],
'url' => 'https://example.com/ophelos_webhook'
]),
CURLOPT_HTTPHEADER => [
"accept: application/json",
"content-type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.ophelos.dev/webhooks"
payload := strings.NewReader("{\"enabled_events\":[\"payment.succeeded\",\"debt.updated\"],\"url\":\"https://example.com/ophelos_webhook\"}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("accept", "application/json")
req.Header.Add("content-type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}
import requests
url = "https://api.ophelos.dev/webhooks"
payload = {
"enabled_events": ["payment.succeeded", "debt.updated"],
"url": "https://example.com/ophelos_webhook"
}
headers = {
"accept": "application/json",
"content-type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)
4. Secure your endpoint
You need to secure your integration by making sure your handler verifies that all your webhook request are generated by Ophelos.
Verify webhook signatures manually
The Ophelos-Signature
header included in each signed event contains a timestamp and one or more signatures that you must verify. The timestamp is prefixed by t=
, and each signature is prefixed by a scheme. Schemes start with v
, followed by an integer. Currently, the only valid live signature scheme is v1
.
Ophelos-Signature:
t=1492774577,
v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd
We provide newlines for clarity, but a real
Ophelos-Signature
header is on a single line.
Ophelos generates signatures using a hash-based message authentication code (HMAC) with SHA-256. To prevent downgrade attacks, ignore all schemes that aren't v1
.
To create a manual solution for verifying signatures, you must complete the following steps:
- Extract the timestamp and signatures from the header
Split the header using the,
character as the separator to get a list of elements. Then split each element using the=
character as the separator to get a prefix and value pair.
The value of thet
corresponds to the timestamp, andv1
corresponds to the signature (or signatures). You can discard all other elements. - Prepare the
signed_payload
string
Thesigned_payload
string is created by concatenating:- The timestamp (as a string)
- The character
.
- The actual JSON payload (that is, the request body)
- Determine the expected signature
Compute an HMAC with the SHA-256 hash function. Use the endpoint's signing secret as the key, and use thesigned_payload
string as the message. - Compare the signatures
Compare the signature (or signatures) in the header to the expected signature. For an equality match, compute the difference between the current timestamp and the received timestamp, then decide if the difference is within your tolerance.
To protect against timing attacks, use a constant-time-string comparison to compare the expected signature to each of the received signatures.
Debug webhook integrations
Multiple types of issues can occur when delivering events to your webhook endpoint:
- Ophelos might not be able to deliver an event to your webhook endpoint.
- Your webhook endpoint might have an SSL issue.
- Your network connectivity is intermittent.
- Your webhook endpoint isn't reciving events that you expect to receive.
View event deliveries
To view all events that were triggered in your account, view the Webhook Events (https://crm.ophelos.dev/api/admin/webhook_events for staging) tab in.
Fix HTTP status codes
When an event displays a status code of 200
, it indicates successful delivery to the webhook endpoint. You might also recieve a status code rather than 200
. View the table below for a list of common HTTP status codes and recommended solutions
Pending webhook status | Description | Fix |
---|---|---|
(unable to connect) ERR | We're unable to establish connection to the destination server. | Make sure that your host domain is publicly accessible to the internet. |
(302 ) ERR (or other 3xx status) | The destination server attempted to redirect the request to another location. We consider redirect responses to webhook requests as failures. | Set the webhook endpoint to the destination to the URL resolves by the redirect. |
(400 ) ERR (or other 4xx status) | The destination server can't or won't process the request. This might occur when the server detects an error (400 ), when the destination URL has access restrictions, (401 ,403 ), or when the destination URL doesn't exist (404 ) | - Make sure that your endpoint is publicly accessible to the internet. - Make sure that your endpoint accepts POST HTTP method. |
(500 ) ERR (or other 5xx status | The destination server encountered an error while processing the request. | Review your application’s logs to understand why it’s returning a 500 error. |
(TLS error) ERR | We couldn’t establish a secure connection to the destination server. Issues with the SSL/TLS certificate or an intermediate certificate in the destination server’s certificate chain usually cause these errors. Ophelos requires TLS version v1.2 or higher. | Perform an SSL server test to find issues that might cause this error. |
(Timed out) ERR | The destination server took too long to respond to the webhook request. | Make sure you defer complex logic and return a successful response immediately in your webhook handling code. |
Updated 7 months ago