curl https://webhooks.sbx.moduluslabs.io/v1/webhooks \
-u sk_your_secret_key:
const axios = require('axios');
const jose = require('jose');
const SECRET_KEY = process.env.MODULUS_SECRET_KEY;
const ENCRYPTION_KEY = process.env.MODULUS_ENCRYPTION_KEY;
async function getWebhooks() {
try {
// Decode encryption key from base64
const key = Buffer.from(ENCRYPTION_KEY, 'base64');
const response = await axios.get(
'https://webhooks.sbx.moduluslabs.io/v1/webhooks',
{
auth: {
username: SECRET_KEY,
password: ''
}
}
);
// Decrypt the response token
const { plaintext } = await jose.compactDecrypt(
response.data.response.Token,
key
);
const webhooks = JSON.parse(new TextDecoder().decode(plaintext));
console.log(`Found ${webhooks.length} webhook(s)`);
webhooks.forEach(webhook => {
console.log('\nWebhook ID:', webhook.id);
console.log('URL:', webhook.callbackUrl);
console.log('Action:', webhook.webhookAction);
console.log('Status:', webhook.webhookStatus);
});
return webhooks;
} catch (error) {
if (error.response) {
console.error('Error:', error.response.status);
console.error('Details:', error.response.data);
} else {
console.error('Request failed:', error.message);
}
throw error;
}
}
getWebhooks();
import requests
import os
SECRET_KEY = os.getenv('MODULUS_SECRET_KEY')
def get_webhooks():
try:
response = requests.get(
'https://webhooks.sbx.moduluslabs.io/v1/webhooks',
auth=(SECRET_KEY, '')
)
response.raise_for_status()
data = response.json()
webhooks = data['webhooks']
print(f"Found {len(webhooks)} webhook(s)")
for webhook in webhooks:
print(f"\nWebhook ID: {webhook['id']}")
print(f"URL: {webhook['webhookUrl']}")
print(f"Actions: {', '.join(webhook['actions'])}")
print(f"Status: {webhook['status']}")
print(f"Created: {webhook['createdAt']}")
return webhooks
except requests.exceptions.HTTPError as e:
print(f' Error: {e.response.status_code}')
print('Details:', e.response.json())
raise
except requests.exceptions.RequestException as e:
print(f' Request failed: {str(e)}')
raise
if __name__ == '__main__':
get_webhooks()
<?php
$secretKey = getenv('MODULUS_SECRET_KEY');
$ch = curl_init('https://webhooks.sbx.moduluslabs.io/v1/webhooks');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERPWD, $secretKey . ':');
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode === 200) {
$data = json_decode($response, true);
$webhooks = $data['webhooks'];
echo "Found " . count($webhooks) . " webhook(s)\n";
foreach ($webhooks as $webhook) {
echo "\nWebhook ID: {$webhook['id']}\n";
echo "URL: {$webhook['webhookUrl']}\n";
echo "Actions: " . implode(', ', $webhook['actions']) . "\n";
echo "Status: {$webhook['status']}\n";
echo "Created: {$webhook['createdAt']}\n";
}
} else {
echo " Error: HTTP $httpCode\n";
echo "Details: $response\n";
}
import java.net.http.*;
import java.net.URI;
import java.util.Base64;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonArray;
public class GetWebhooksExample {
public static void main(String[] args) throws Exception {
String secretKey = System.getenv("MODULUS_SECRET_KEY");
// Create HTTP client
HttpClient client = HttpClient.newHttpClient();
// Encode credentials
String auth = secretKey + ":";
String encodedAuth = Base64.getEncoder().encodeToString(auth.getBytes());
// Build request
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://webhooks.sbx.moduluslabs.io/v1/webhooks"))
.header("Authorization", "Basic " + encodedAuth)
.GET()
.build();
// Send request
HttpResponse<String> response = client.send(
request,
HttpResponse.BodyHandlers.ofString()
);
if (response.statusCode() == 200) {
Gson gson = new Gson();
JsonObject data = gson.fromJson(response.body(), JsonObject.class);
JsonArray webhooks = data.getAsJsonArray("webhooks");
System.out.println("Found " + webhooks.size() + " webhook(s)");
for (int i = 0; i < webhooks.size(); i++) {
JsonObject webhook = webhooks.get(i).getAsJsonObject();
System.out.println("\nWebhook ID: " + webhook.get("id").getAsInt());
System.out.println("URL: " + webhook.get("webhookUrl").getAsString());
System.out.println("Status: " + webhook.get("status").getAsString());
}
} else {
System.out.println(" Error: HTTP " + response.statusCode());
System.out.println("Details: " + response.body());
}
}
}
package main
import (
"encoding/json"
"fmt"
"io"
"net/http"
"os"
)
type Webhook struct {
ID int `json:"id"`
WebhookURL string `json:"webhookUrl"`
Actions []string `json:"actions"`
Status string `json:"status"`
CreatedAt string `json:"createdAt"`
UpdatedAt string `json:"updatedAt"`
}
type WebhooksResponse struct {
Webhooks []Webhook `json:"webhooks"`
}
func getWebhooks() ([]Webhook, error) {
secretKey := os.Getenv("MODULUS_SECRET_KEY")
// Create request
req, err := http.NewRequest(
"GET",
"https://webhooks.sbx.moduluslabs.io/v1/webhooks",
nil,
)
if err != nil {
return nil, err
}
// Set basic auth
req.SetBasicAuth(secretKey, "")
// Send request
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
if resp.StatusCode == 200 {
var webhooksResp WebhooksResponse
json.Unmarshal(body, &webhooksResp)
fmt.Printf("Found %d webhook(s)\n", len(webhooksResp.Webhooks))
for _, webhook := range webhooksResp.Webhooks {
fmt.Printf("\nWebhook ID: %d\n", webhook.ID)
fmt.Printf("URL: %s\n", webhook.WebhookURL)
fmt.Printf("Actions: %v\n", webhook.Actions)
fmt.Printf("Status: %s\n", webhook.Status)
fmt.Printf("Created: %s\n", webhook.CreatedAt)
}
return webhooksResp.Webhooks, nil
}
fmt.Printf(" Error: HTTP %d\n", resp.StatusCode)
fmt.Printf("Details: %s\n", string(body))
return nil, fmt.Errorf("HTTP %d", resp.StatusCode)
}
func main() {
webhooks, err := getWebhooks()
if err != nil {
fmt.Printf("Failed to get webhooks: %v\n", err)
}
}
// Required NuGet package: jose-jwt
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using Jose;
class Program
{
static async Task Main(string[] args)
{
await GetWebhooks();
}
static async Task GetWebhooks()
{
// Get credentials from environment variables
var secretKey = Environment.GetEnvironmentVariable("MODULUS_SECRET_KEY");
var encryptionKey = Environment.GetEnvironmentVariable("MODULUS_ENCRYPTION_KEY");
if (string.IsNullOrEmpty(secretKey) || string.IsNullOrEmpty(encryptionKey))
{
Console.WriteLine("Error: MODULUS_SECRET_KEY and MODULUS_ENCRYPTION_KEY must be set");
return;
}
try
{
// Decode the Base64URL encryption key
var keyBytes = Base64UrlDecode(encryptionKey);
// Create HTTP client with Basic Authentication
using var client = new HttpClient();
var credentials = Convert.ToBase64String(
Encoding.ASCII.GetBytes($"{secretKey}:")
);
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Basic", credentials);
// Send GET request
var response = await client.GetAsync(
"https://webhooks.sbx.moduluslabs.io/v1/webhooks"
);
var responseBody = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
// Decrypt the response token
var encryptedResponse = JsonSerializer.Deserialize<JsonElement>(responseBody);
var responseToken = encryptedResponse
.GetProperty("response")
.GetProperty("Token")
.GetString();
var decryptedJson = JWT.Decode(responseToken, keyBytes);
// Response is a direct array of webhooks
var webhooks = JsonSerializer.Deserialize<Webhook[]>(
decryptedJson,
new JsonSerializerOptions { PropertyNameCaseInsensitive = true }
);
Console.WriteLine($"Found {webhooks.Length} webhook(s)");
foreach (var webhook in webhooks)
{
Console.WriteLine($"\nWebhook ID: {webhook.Id}");
Console.WriteLine($"URL: {webhook.CallbackUrl}");
Console.WriteLine($"Action: {webhook.WebhookAction}");
Console.WriteLine($"Status: {webhook.WebhookStatus}");
}
}
else
{
Console.WriteLine($"Error: HTTP {(int)response.StatusCode}");
Console.WriteLine($"Details: {responseBody}");
}
}
catch (Exception e)
{
Console.WriteLine($"Error: {e.Message}");
}
}
// Base64URL decoding helper
static byte[] Base64UrlDecode(string input)
{
var base64 = input.Replace('-', '+').Replace('_', '/');
switch (base64.Length % 4)
{
case 2: base64 += "=="; break;
case 3: base64 += "="; break;
}
return Convert.FromBase64String(base64);
}
}
// Response model
public class Webhook
{
public string Id { get; set; }
public string CallbackUrl { get; set; }
public string WebhookAction { get; set; }
public string WebhookStatus { get; set; }
}
{
"webhooks": [
{
"id": 123,
"webhookUrl": "https://api.yourcompany.com/webhooks/modulus",
"actions": ["QRPH_SUCCESS", "QRPH_DECLINED"],
"status": "ENABLED",
"createdAt": "2024-01-15T10:30:00Z",
"updatedAt": "2024-01-15T10:30:00Z"
}
]
}
{
"code": "10000013",
"error": "Invalid API Key",
"referenceNumber": "097bf60a-bdab-40bf-b615-3c0eae693b86"
}
{
"code": "10000015",
"error": "Insufficient permissions",
"referenceNumber": "097bf60a-bdab-40bf-b615-3c0eae693b86"
}
{
"code": "10000001",
"error": "An unexpected error occurred. Please try again later.",
"referenceNumber": "097bf60a-bdab-40bf-b615-3c0eae693b86"
}
QR PH Webhooks
Get Webhooks
Retrieve all registered webhook endpoints for your merchant account
GET
/
v1
/
webhooks
curl https://webhooks.sbx.moduluslabs.io/v1/webhooks \
-u sk_your_secret_key:
const axios = require('axios');
const jose = require('jose');
const SECRET_KEY = process.env.MODULUS_SECRET_KEY;
const ENCRYPTION_KEY = process.env.MODULUS_ENCRYPTION_KEY;
async function getWebhooks() {
try {
// Decode encryption key from base64
const key = Buffer.from(ENCRYPTION_KEY, 'base64');
const response = await axios.get(
'https://webhooks.sbx.moduluslabs.io/v1/webhooks',
{
auth: {
username: SECRET_KEY,
password: ''
}
}
);
// Decrypt the response token
const { plaintext } = await jose.compactDecrypt(
response.data.response.Token,
key
);
const webhooks = JSON.parse(new TextDecoder().decode(plaintext));
console.log(`Found ${webhooks.length} webhook(s)`);
webhooks.forEach(webhook => {
console.log('\nWebhook ID:', webhook.id);
console.log('URL:', webhook.callbackUrl);
console.log('Action:', webhook.webhookAction);
console.log('Status:', webhook.webhookStatus);
});
return webhooks;
} catch (error) {
if (error.response) {
console.error('Error:', error.response.status);
console.error('Details:', error.response.data);
} else {
console.error('Request failed:', error.message);
}
throw error;
}
}
getWebhooks();
import requests
import os
SECRET_KEY = os.getenv('MODULUS_SECRET_KEY')
def get_webhooks():
try:
response = requests.get(
'https://webhooks.sbx.moduluslabs.io/v1/webhooks',
auth=(SECRET_KEY, '')
)
response.raise_for_status()
data = response.json()
webhooks = data['webhooks']
print(f"Found {len(webhooks)} webhook(s)")
for webhook in webhooks:
print(f"\nWebhook ID: {webhook['id']}")
print(f"URL: {webhook['webhookUrl']}")
print(f"Actions: {', '.join(webhook['actions'])}")
print(f"Status: {webhook['status']}")
print(f"Created: {webhook['createdAt']}")
return webhooks
except requests.exceptions.HTTPError as e:
print(f' Error: {e.response.status_code}')
print('Details:', e.response.json())
raise
except requests.exceptions.RequestException as e:
print(f' Request failed: {str(e)}')
raise
if __name__ == '__main__':
get_webhooks()
<?php
$secretKey = getenv('MODULUS_SECRET_KEY');
$ch = curl_init('https://webhooks.sbx.moduluslabs.io/v1/webhooks');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERPWD, $secretKey . ':');
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode === 200) {
$data = json_decode($response, true);
$webhooks = $data['webhooks'];
echo "Found " . count($webhooks) . " webhook(s)\n";
foreach ($webhooks as $webhook) {
echo "\nWebhook ID: {$webhook['id']}\n";
echo "URL: {$webhook['webhookUrl']}\n";
echo "Actions: " . implode(', ', $webhook['actions']) . "\n";
echo "Status: {$webhook['status']}\n";
echo "Created: {$webhook['createdAt']}\n";
}
} else {
echo " Error: HTTP $httpCode\n";
echo "Details: $response\n";
}
import java.net.http.*;
import java.net.URI;
import java.util.Base64;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonArray;
public class GetWebhooksExample {
public static void main(String[] args) throws Exception {
String secretKey = System.getenv("MODULUS_SECRET_KEY");
// Create HTTP client
HttpClient client = HttpClient.newHttpClient();
// Encode credentials
String auth = secretKey + ":";
String encodedAuth = Base64.getEncoder().encodeToString(auth.getBytes());
// Build request
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://webhooks.sbx.moduluslabs.io/v1/webhooks"))
.header("Authorization", "Basic " + encodedAuth)
.GET()
.build();
// Send request
HttpResponse<String> response = client.send(
request,
HttpResponse.BodyHandlers.ofString()
);
if (response.statusCode() == 200) {
Gson gson = new Gson();
JsonObject data = gson.fromJson(response.body(), JsonObject.class);
JsonArray webhooks = data.getAsJsonArray("webhooks");
System.out.println("Found " + webhooks.size() + " webhook(s)");
for (int i = 0; i < webhooks.size(); i++) {
JsonObject webhook = webhooks.get(i).getAsJsonObject();
System.out.println("\nWebhook ID: " + webhook.get("id").getAsInt());
System.out.println("URL: " + webhook.get("webhookUrl").getAsString());
System.out.println("Status: " + webhook.get("status").getAsString());
}
} else {
System.out.println(" Error: HTTP " + response.statusCode());
System.out.println("Details: " + response.body());
}
}
}
package main
import (
"encoding/json"
"fmt"
"io"
"net/http"
"os"
)
type Webhook struct {
ID int `json:"id"`
WebhookURL string `json:"webhookUrl"`
Actions []string `json:"actions"`
Status string `json:"status"`
CreatedAt string `json:"createdAt"`
UpdatedAt string `json:"updatedAt"`
}
type WebhooksResponse struct {
Webhooks []Webhook `json:"webhooks"`
}
func getWebhooks() ([]Webhook, error) {
secretKey := os.Getenv("MODULUS_SECRET_KEY")
// Create request
req, err := http.NewRequest(
"GET",
"https://webhooks.sbx.moduluslabs.io/v1/webhooks",
nil,
)
if err != nil {
return nil, err
}
// Set basic auth
req.SetBasicAuth(secretKey, "")
// Send request
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
if resp.StatusCode == 200 {
var webhooksResp WebhooksResponse
json.Unmarshal(body, &webhooksResp)
fmt.Printf("Found %d webhook(s)\n", len(webhooksResp.Webhooks))
for _, webhook := range webhooksResp.Webhooks {
fmt.Printf("\nWebhook ID: %d\n", webhook.ID)
fmt.Printf("URL: %s\n", webhook.WebhookURL)
fmt.Printf("Actions: %v\n", webhook.Actions)
fmt.Printf("Status: %s\n", webhook.Status)
fmt.Printf("Created: %s\n", webhook.CreatedAt)
}
return webhooksResp.Webhooks, nil
}
fmt.Printf(" Error: HTTP %d\n", resp.StatusCode)
fmt.Printf("Details: %s\n", string(body))
return nil, fmt.Errorf("HTTP %d", resp.StatusCode)
}
func main() {
webhooks, err := getWebhooks()
if err != nil {
fmt.Printf("Failed to get webhooks: %v\n", err)
}
}
// Required NuGet package: jose-jwt
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using Jose;
class Program
{
static async Task Main(string[] args)
{
await GetWebhooks();
}
static async Task GetWebhooks()
{
// Get credentials from environment variables
var secretKey = Environment.GetEnvironmentVariable("MODULUS_SECRET_KEY");
var encryptionKey = Environment.GetEnvironmentVariable("MODULUS_ENCRYPTION_KEY");
if (string.IsNullOrEmpty(secretKey) || string.IsNullOrEmpty(encryptionKey))
{
Console.WriteLine("Error: MODULUS_SECRET_KEY and MODULUS_ENCRYPTION_KEY must be set");
return;
}
try
{
// Decode the Base64URL encryption key
var keyBytes = Base64UrlDecode(encryptionKey);
// Create HTTP client with Basic Authentication
using var client = new HttpClient();
var credentials = Convert.ToBase64String(
Encoding.ASCII.GetBytes($"{secretKey}:")
);
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Basic", credentials);
// Send GET request
var response = await client.GetAsync(
"https://webhooks.sbx.moduluslabs.io/v1/webhooks"
);
var responseBody = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
// Decrypt the response token
var encryptedResponse = JsonSerializer.Deserialize<JsonElement>(responseBody);
var responseToken = encryptedResponse
.GetProperty("response")
.GetProperty("Token")
.GetString();
var decryptedJson = JWT.Decode(responseToken, keyBytes);
// Response is a direct array of webhooks
var webhooks = JsonSerializer.Deserialize<Webhook[]>(
decryptedJson,
new JsonSerializerOptions { PropertyNameCaseInsensitive = true }
);
Console.WriteLine($"Found {webhooks.Length} webhook(s)");
foreach (var webhook in webhooks)
{
Console.WriteLine($"\nWebhook ID: {webhook.Id}");
Console.WriteLine($"URL: {webhook.CallbackUrl}");
Console.WriteLine($"Action: {webhook.WebhookAction}");
Console.WriteLine($"Status: {webhook.WebhookStatus}");
}
}
else
{
Console.WriteLine($"Error: HTTP {(int)response.StatusCode}");
Console.WriteLine($"Details: {responseBody}");
}
}
catch (Exception e)
{
Console.WriteLine($"Error: {e.Message}");
}
}
// Base64URL decoding helper
static byte[] Base64UrlDecode(string input)
{
var base64 = input.Replace('-', '+').Replace('_', '/');
switch (base64.Length % 4)
{
case 2: base64 += "=="; break;
case 3: base64 += "="; break;
}
return Convert.FromBase64String(base64);
}
}
// Response model
public class Webhook
{
public string Id { get; set; }
public string CallbackUrl { get; set; }
public string WebhookAction { get; set; }
public string WebhookStatus { get; set; }
}
{
"webhooks": [
{
"id": 123,
"webhookUrl": "https://api.yourcompany.com/webhooks/modulus",
"actions": ["QRPH_SUCCESS", "QRPH_DECLINED"],
"status": "ENABLED",
"createdAt": "2024-01-15T10:30:00Z",
"updatedAt": "2024-01-15T10:30:00Z"
}
]
}
{
"code": "10000013",
"error": "Invalid API Key",
"referenceNumber": "097bf60a-bdab-40bf-b615-3c0eae693b86"
}
{
"code": "10000015",
"error": "Insufficient permissions",
"referenceNumber": "097bf60a-bdab-40bf-b615-3c0eae693b86"
}
{
"code": "10000001",
"error": "An unexpected error occurred. Please try again later.",
"referenceNumber": "097bf60a-bdab-40bf-b615-3c0eae693b86"
}
Overview
The Get Webhooks endpoint returns a list of all webhook endpoints you’ve registered. Use this to view your webhook configurations, check their status, and retrieve webhook IDs for updates or deletions.Endpoint
GET https://webhooks.sbx.moduluslabs.io/v1/webhooks
Authentication
This endpoint requires HTTP Basic Authentication using your Secret Key.Authorization: Basic {base64(secret_key:)}
Request
Headers
| Header | Value | Required |
|---|---|---|
Authorization | Basic {base64(secret_key:)} | Yes |
accept | application/json | No |
Parameters
This endpoint does not accept any query parameters or request body.Response
Success Response
Status Code:200 OK
Returns an array of webhook objects.
array
required
Array of all registered webhooks for your merchant account. Returns an empty array
[] if no webhooks are registered.Each webhook object contains:Show Webhook Object Properties
Show Webhook Object Properties
integer
required
Unique identifier for the webhook.Example:
123string
required
The HTTPS URL where webhook notifications are sent.Example:
"https://api.yourcompany.com/webhooks/modulus"array
required
Array of webhook actions this endpoint receives.Possible values:
["QRPH_SUCCESS"], ["QRPH_DECLINED"], or ["QRPH_SUCCESS", "QRPH_DECLINED"]Example: ["QRPH_SUCCESS", "QRPH_DECLINED"]string
required
Current webhook status.Possible values:
ENABLED- Webhook is active and receiving notificationsDISABLED- Webhook is registered but not receiving notifications
"ENABLED"string
required
ISO 8601 timestamp of when the webhook was created.Example:
"2024-01-15T10:30:00Z"string
required
ISO 8601 timestamp of when the webhook was last updated.Example:
"2024-01-15T14:20:00Z"Response Examples
{
"webhooks": [
{
"id": 123,
"webhookUrl": "https://api.yourcompany.com/webhooks/modulus",
"actions": ["QRPH_SUCCESS", "QRPH_DECLINED"],
"status": "ENABLED",
"createdAt": "2024-01-15T10:30:00Z",
"updatedAt": "2024-01-15T10:30:00Z"
},
{
"id": 124,
"webhookUrl": "https://backup.yourcompany.com/webhooks/modulus",
"actions": ["QRPH_SUCCESS"],
"status": "DISABLED",
"createdAt": "2024-01-14T08:15:00Z",
"updatedAt": "2024-01-15T12:00:00Z"
}
]
}
{
"webhooks": [
{
"id": 123,
"webhookUrl": "https://api.yourcompany.com/webhooks/modulus",
"actions": ["QRPH_SUCCESS", "QRPH_DECLINED"],
"status": "ENABLED",
"createdAt": "2024-01-15T10:30:00Z",
"updatedAt": "2024-01-15T10:30:00Z"
}
]
}
{
"webhooks": []
}
{
"webhooks": [
{
"id": 123,
"webhookUrl": "https://api.yourcompany.com/webhooks/modulus",
"actions": ["QRPH_SUCCESS", "QRPH_DECLINED"],
"status": "ENABLED",
"createdAt": "2024-01-15T10:30:00Z",
"updatedAt": "2024-01-15T10:30:00Z"
}
]
}
{
"code": "10000013",
"error": "Invalid API Key",
"referenceNumber": "097bf60a-bdab-40bf-b615-3c0eae693b86"
}
{
"code": "10000015",
"error": "Insufficient permissions",
"referenceNumber": "097bf60a-bdab-40bf-b615-3c0eae693b86"
}
{
"code": "10000001",
"error": "An unexpected error occurred. Please try again later.",
"referenceNumber": "097bf60a-bdab-40bf-b615-3c0eae693b86"
}
Error Responses
401 Unauthorized
401 Unauthorized
Status Code: Solution:
401Cause: Invalid or missing authentication credentialsResponse Example:{
"code": "20000001",
"error": "Invalid or missing secret key",
"referenceNumber": "abc123-def456-ghi789"
}
- Verify your secret key is correct
- Ensure Authorization header format:
Basic {base64(secret_key:)} - Check you’re using the right environment (sandbox vs production)
403 Forbidden
403 Forbidden
Status Code:
403Cause: Account disabled or API access revokedSolution:- Contact Modulus Labs support
- Verify your account status
500 Internal Server Error
500 Internal Server Error
Status Code:
500Cause: Unexpected server errorSolution:- Retry the request
- If the issue persists, contact Modulus Labs support
curl https://webhooks.sbx.moduluslabs.io/v1/webhooks \
-u sk_your_secret_key:
const axios = require('axios');
const jose = require('jose');
const SECRET_KEY = process.env.MODULUS_SECRET_KEY;
const ENCRYPTION_KEY = process.env.MODULUS_ENCRYPTION_KEY;
async function getWebhooks() {
try {
// Decode encryption key from base64
const key = Buffer.from(ENCRYPTION_KEY, 'base64');
const response = await axios.get(
'https://webhooks.sbx.moduluslabs.io/v1/webhooks',
{
auth: {
username: SECRET_KEY,
password: ''
}
}
);
// Decrypt the response token
const { plaintext } = await jose.compactDecrypt(
response.data.response.Token,
key
);
const webhooks = JSON.parse(new TextDecoder().decode(plaintext));
console.log(`Found ${webhooks.length} webhook(s)`);
webhooks.forEach(webhook => {
console.log('\nWebhook ID:', webhook.id);
console.log('URL:', webhook.callbackUrl);
console.log('Action:', webhook.webhookAction);
console.log('Status:', webhook.webhookStatus);
});
return webhooks;
} catch (error) {
if (error.response) {
console.error('Error:', error.response.status);
console.error('Details:', error.response.data);
} else {
console.error('Request failed:', error.message);
}
throw error;
}
}
getWebhooks();
import requests
import os
SECRET_KEY = os.getenv('MODULUS_SECRET_KEY')
def get_webhooks():
try:
response = requests.get(
'https://webhooks.sbx.moduluslabs.io/v1/webhooks',
auth=(SECRET_KEY, '')
)
response.raise_for_status()
data = response.json()
webhooks = data['webhooks']
print(f"Found {len(webhooks)} webhook(s)")
for webhook in webhooks:
print(f"\nWebhook ID: {webhook['id']}")
print(f"URL: {webhook['webhookUrl']}")
print(f"Actions: {', '.join(webhook['actions'])}")
print(f"Status: {webhook['status']}")
print(f"Created: {webhook['createdAt']}")
return webhooks
except requests.exceptions.HTTPError as e:
print(f' Error: {e.response.status_code}')
print('Details:', e.response.json())
raise
except requests.exceptions.RequestException as e:
print(f' Request failed: {str(e)}')
raise
if __name__ == '__main__':
get_webhooks()
<?php
$secretKey = getenv('MODULUS_SECRET_KEY');
$ch = curl_init('https://webhooks.sbx.moduluslabs.io/v1/webhooks');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERPWD, $secretKey . ':');
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode === 200) {
$data = json_decode($response, true);
$webhooks = $data['webhooks'];
echo "Found " . count($webhooks) . " webhook(s)\n";
foreach ($webhooks as $webhook) {
echo "\nWebhook ID: {$webhook['id']}\n";
echo "URL: {$webhook['webhookUrl']}\n";
echo "Actions: " . implode(', ', $webhook['actions']) . "\n";
echo "Status: {$webhook['status']}\n";
echo "Created: {$webhook['createdAt']}\n";
}
} else {
echo " Error: HTTP $httpCode\n";
echo "Details: $response\n";
}
import java.net.http.*;
import java.net.URI;
import java.util.Base64;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonArray;
public class GetWebhooksExample {
public static void main(String[] args) throws Exception {
String secretKey = System.getenv("MODULUS_SECRET_KEY");
// Create HTTP client
HttpClient client = HttpClient.newHttpClient();
// Encode credentials
String auth = secretKey + ":";
String encodedAuth = Base64.getEncoder().encodeToString(auth.getBytes());
// Build request
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://webhooks.sbx.moduluslabs.io/v1/webhooks"))
.header("Authorization", "Basic " + encodedAuth)
.GET()
.build();
// Send request
HttpResponse<String> response = client.send(
request,
HttpResponse.BodyHandlers.ofString()
);
if (response.statusCode() == 200) {
Gson gson = new Gson();
JsonObject data = gson.fromJson(response.body(), JsonObject.class);
JsonArray webhooks = data.getAsJsonArray("webhooks");
System.out.println("Found " + webhooks.size() + " webhook(s)");
for (int i = 0; i < webhooks.size(); i++) {
JsonObject webhook = webhooks.get(i).getAsJsonObject();
System.out.println("\nWebhook ID: " + webhook.get("id").getAsInt());
System.out.println("URL: " + webhook.get("webhookUrl").getAsString());
System.out.println("Status: " + webhook.get("status").getAsString());
}
} else {
System.out.println(" Error: HTTP " + response.statusCode());
System.out.println("Details: " + response.body());
}
}
}
package main
import (
"encoding/json"
"fmt"
"io"
"net/http"
"os"
)
type Webhook struct {
ID int `json:"id"`
WebhookURL string `json:"webhookUrl"`
Actions []string `json:"actions"`
Status string `json:"status"`
CreatedAt string `json:"createdAt"`
UpdatedAt string `json:"updatedAt"`
}
type WebhooksResponse struct {
Webhooks []Webhook `json:"webhooks"`
}
func getWebhooks() ([]Webhook, error) {
secretKey := os.Getenv("MODULUS_SECRET_KEY")
// Create request
req, err := http.NewRequest(
"GET",
"https://webhooks.sbx.moduluslabs.io/v1/webhooks",
nil,
)
if err != nil {
return nil, err
}
// Set basic auth
req.SetBasicAuth(secretKey, "")
// Send request
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
if resp.StatusCode == 200 {
var webhooksResp WebhooksResponse
json.Unmarshal(body, &webhooksResp)
fmt.Printf("Found %d webhook(s)\n", len(webhooksResp.Webhooks))
for _, webhook := range webhooksResp.Webhooks {
fmt.Printf("\nWebhook ID: %d\n", webhook.ID)
fmt.Printf("URL: %s\n", webhook.WebhookURL)
fmt.Printf("Actions: %v\n", webhook.Actions)
fmt.Printf("Status: %s\n", webhook.Status)
fmt.Printf("Created: %s\n", webhook.CreatedAt)
}
return webhooksResp.Webhooks, nil
}
fmt.Printf(" Error: HTTP %d\n", resp.StatusCode)
fmt.Printf("Details: %s\n", string(body))
return nil, fmt.Errorf("HTTP %d", resp.StatusCode)
}
func main() {
webhooks, err := getWebhooks()
if err != nil {
fmt.Printf("Failed to get webhooks: %v\n", err)
}
}
// Required NuGet package: jose-jwt
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using Jose;
class Program
{
static async Task Main(string[] args)
{
await GetWebhooks();
}
static async Task GetWebhooks()
{
// Get credentials from environment variables
var secretKey = Environment.GetEnvironmentVariable("MODULUS_SECRET_KEY");
var encryptionKey = Environment.GetEnvironmentVariable("MODULUS_ENCRYPTION_KEY");
if (string.IsNullOrEmpty(secretKey) || string.IsNullOrEmpty(encryptionKey))
{
Console.WriteLine("Error: MODULUS_SECRET_KEY and MODULUS_ENCRYPTION_KEY must be set");
return;
}
try
{
// Decode the Base64URL encryption key
var keyBytes = Base64UrlDecode(encryptionKey);
// Create HTTP client with Basic Authentication
using var client = new HttpClient();
var credentials = Convert.ToBase64String(
Encoding.ASCII.GetBytes($"{secretKey}:")
);
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Basic", credentials);
// Send GET request
var response = await client.GetAsync(
"https://webhooks.sbx.moduluslabs.io/v1/webhooks"
);
var responseBody = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
// Decrypt the response token
var encryptedResponse = JsonSerializer.Deserialize<JsonElement>(responseBody);
var responseToken = encryptedResponse
.GetProperty("response")
.GetProperty("Token")
.GetString();
var decryptedJson = JWT.Decode(responseToken, keyBytes);
// Response is a direct array of webhooks
var webhooks = JsonSerializer.Deserialize<Webhook[]>(
decryptedJson,
new JsonSerializerOptions { PropertyNameCaseInsensitive = true }
);
Console.WriteLine($"Found {webhooks.Length} webhook(s)");
foreach (var webhook in webhooks)
{
Console.WriteLine($"\nWebhook ID: {webhook.Id}");
Console.WriteLine($"URL: {webhook.CallbackUrl}");
Console.WriteLine($"Action: {webhook.WebhookAction}");
Console.WriteLine($"Status: {webhook.WebhookStatus}");
}
}
else
{
Console.WriteLine($"Error: HTTP {(int)response.StatusCode}");
Console.WriteLine($"Details: {responseBody}");
}
}
catch (Exception e)
{
Console.WriteLine($"Error: {e.Message}");
}
}
// Base64URL decoding helper
static byte[] Base64UrlDecode(string input)
{
var base64 = input.Replace('-', '+').Replace('_', '/');
switch (base64.Length % 4)
{
case 2: base64 += "=="; break;
case 3: base64 += "="; break;
}
return Convert.FromBase64String(base64);
}
}
// Response model
public class Webhook
{
public string Id { get; set; }
public string CallbackUrl { get; set; }
public string WebhookAction { get; set; }
public string WebhookStatus { get; set; }
}
Use Cases
Audit Webhook Configuration
Audit Webhook Configuration
Verify which webhooks are active and what events they receive:
const webhooks = await getWebhooks();
const enabledWebhooks = webhooks.filter(w => w.status === 'ENABLED');
console.log(`${enabledWebhooks.length} active webhook(s)`);
enabledWebhooks.forEach(webhook => {
console.log(`- ${webhook.webhookUrl} receives ${webhook.actions.join(', ')}`);
});
Find Webhook ID for Update
Find Webhook ID for Update
Retrieve the webhook ID before updating or deleting:
const webhooks = await getWebhooks();
const webhook = webhooks.find(
w => w.webhookUrl === 'https://api.yourcompany.com/webhooks/modulus'
);
if (webhook) {
console.log('Webhook ID:', webhook.id);
// Use this ID to update or delete
await updateWebhook(webhook.id, { status: 'DISABLED' });
}
Monitor Webhook Status
Monitor Webhook Status
Check if your webhooks are enabled in health checks:
async function checkWebhookHealth() {
const webhooks = await getWebhooks();
const disabledWebhooks = webhooks.filter(w => w.status === 'DISABLED');
if (disabledWebhooks.length > 0) {
console.warn(` ${disabledWebhooks.length} webhook(s) are disabled`);
// Alert team
await alertOncall('Disabled webhooks detected', {
webhooks: disabledWebhooks.map(w => w.webhookUrl)
});
}
}
Prevent Duplicate Webhooks
Prevent Duplicate Webhooks
Check if a webhook URL is already registered before creating:
async function ensureWebhook(url, actions) {
const webhooks = await getWebhooks();
const existing = webhooks.find(w => w.webhookUrl === url);
if (existing) {
console.log('Webhook already exists:', existing.id);
return existing;
}
// Create new webhook
return await createWebhook(url, actions, 'ENABLED');
}
Sync Webhook Configuration
Sync Webhook Configuration
Compare current webhooks with expected configuration:
const expectedWebhooks = [
{ url: 'https://api.example.com/webhooks', actions: ['QRPH_SUCCESS'] },
{ url: 'https://backup.example.com/webhooks', actions: ['QRPH_SUCCESS'] }
];
const currentWebhooks = await getWebhooks();
// Find missing webhooks
const missing = expectedWebhooks.filter(expected =>
!currentWebhooks.some(current => current.webhookUrl === expected.url)
);
// Create missing webhooks
for (const webhook of missing) {
await createWebhook(webhook.url, webhook.actions, 'ENABLED');
}
Best Practices
Cache Webhook Configuration
Cache webhook IDs in your application to avoid repeated API calls:
// Cache webhook IDs on startup
const webhooks = await getWebhooks();
const webhookMap = new Map(
webhooks.map(w => [w.webhookUrl, w.id])
);
// Use cached ID for updates
const webhookId = webhookMap.get(url);
await updateWebhook(webhookId, { status: 'DISABLED' });
Regular Health Checks
Periodically verify webhooks are enabled and configured correctly:
setInterval(async () => {
const webhooks = await getWebhooks();
const enabled = webhooks.filter(w => w.status === 'ENABLED');
if (enabled.length === 0) {
alertOncall('No enabled webhooks!');
}
}, 3600000); // Every hour
Log Webhook Changes
Track webhook configuration changes for audit purposes:
const webhooks = await getWebhooks();
await db.webhookAudit.insert({
timestamp: new Date(),
webhookCount: webhooks.length,
webhooks: webhooks
});
Validate Expected Configuration
Ensure critical webhooks are present and enabled:
const webhooks = await getWebhooks();
const productionWebhook = webhooks.find(
w => w.webhookUrl === 'https://api.prod.com/webhooks'
);
if (!productionWebhook || productionWebhook.status !== 'ENABLED') {
throw new Error('Production webhook not configured');
}
Filtering and Processing Webhooks
const webhooks = await getWebhooks();
// Filter enabled webhooks
const enabledWebhooks = webhooks.filter(w => w.status === 'ENABLED');
// Filter by action type
const successOnlyWebhooks = webhooks.filter(w =>
w.actions.includes('QRPH_SUCCESS') && !w.actions.includes('QRPH_DECLINED')
);
// Sort by creation date (newest first)
const sortedWebhooks = webhooks.sort((a, b) =>
new Date(b.createdAt) - new Date(a.createdAt)
);
// Group by status
const groupedByStatus = webhooks.reduce((acc, webhook) => {
acc[webhook.status] = acc[webhook.status] || [];
acc[webhook.status].push(webhook);
return acc;
}, {});
console.log('Enabled:', groupedByStatus.ENABLED?.length || 0);
console.log('Disabled:', groupedByStatus.DISABLED?.length || 0);
Troubleshooting
Empty Webhooks Array
Empty Webhooks Array
Symptom: Response returns
{"webhooks": []}Possible Causes:- No webhooks have been created yet
- Using wrong secret key (different merchant account)
- Webhooks were deleted
- Verify you’re using the correct secret key
- Create a webhook using the Create Webhook API
- Check if you’re in the right environment (sandbox vs production)
Missing Expected Webhook
Missing Expected Webhook
Symptom: Webhook you created is not in the listPossible Causes:
- Wrong secret key (different merchant account)
- Webhook was deleted
- API cache delay (rare)
- Verify secret key matches the one used to create the webhook
- Check if webhook was accidentally deleted
- Retry the request after a few seconds
Outdated Webhook Information
Outdated Webhook Information
Symptom: Webhook status or URL doesn’t match recent updatesPossible Causes:
- Application caching old data
- Race condition with concurrent updates
- Clear application cache
- Call Get Webhooks API again to refresh data
- Implement cache invalidation after updates
Next Steps
Create Webhook
Register a new webhook endpoint
Update Webhook
Modify existing webhook configuration
Delete Webhook
Remove a webhook endpoint
Webhooks Overview
Learn about the Webhook API
Authorizations
HTTP Basic Authentication using your Secret Key as the username and an empty password
Response
List of webhooks retrieved successfully
Unique identifier for the webhook
List of transaction events this webhook receives
Available options:
QRPH_SUCCESS, QRPH_DECLINED Current status of the webhook
Available options:
ENABLED, DISABLED The HTTPS URL where notifications are sent
Was this page helpful?
⌘I