Gearment Webhook API (1.0.0)

The Gearment Webhook API provides real-time notifications for critical order and product events—such as order completion, cancellation, shipping updates, stock changes, and variant modifications—across multiple payload versions to ensure seamless integration with your existing systems.

Download OpenAPI description
Overview
Support Integration

integration@gearment.com

Languages
Servers
Your Webhook URL

https://your-webhook-url/

Overview

Webhook events are one-way events sent to your app over HTTP to notify you when an event occured. Unlike events that are sent over Gateway connections, events sent over webhooks are not realtime or guaranteed to be in order.

While incoming webhooks are triggered by an external service, webhook events (i.e. outgoing webhooks) are triggered by events happening in Gearment. This means your app will need to set up a public URL where you can receive HTTP events, which is detailed in the preparing for events section.

You can configure only one webhook URL per webhook event and version.

Signature

When Gearment sends an alert payload to your webhook URL, we include a variety of headers that you can use to verify that the payload came from QuickAlerts. For additional security, you can implement signature validation, which is an optional way to verify the authenticity of payloads received by your webhook URL.


Headers We Send

HeaderDescription
X-Connect-TimestampThe timestamp when this payload was sent.
X-Connect-NonceThe nonce we used in the generation of the payload signature.
X-Connect-SignatureThe signature we generated for this payload.
X-Connect-Client-KeyThe key we use in the generation to sign

Locating the Webhook Security Token

  1. Sign in to the Gearment Developer Setting.
  2. Click to Setting Teams.
  3. Navigate on the Developer settings tab.
  4. Click to API credentials.
  5. Click to Request API key.
  6. In the details, find the API key and API signature field.

The API key and signature is a value known only to you and Gearment. It is used to generate a signature that can be validated on your end to ensure the authenticity of the received payloads.


Signature Construction Logic

The HMAC-SHA256 signature is computed as follows:

  1. Read the HTTP body of the request.
  2. Base64-URL encode the body content.
  3. Construct a signing string using:
    <URL path> + <nonce> + <timestamp> + <base64-url-encoded body>
  4. Compute the HMAC-SHA256 digest using your client secret as the key.
  5. Base64-URL encode the result.
  6. Compare the computed signature to the one provided in the X-Connect-Signature header.

Verifying a Payload

Below are code snippets demonstrating how to verify the signature for different programming languages. These examples assume that the webhook headers (timestamp, nonce, signature, etc.) are already available as variables. Replace the clientSecret constant with your Webhook Security Token.


Go

package main

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/base64"
	"io"
	"net/http"
	"strings"
)

func verifySignature(r *http.Request) bool {
	timestamp := r.Header.Get("X-Connect-Timestamp")
	nonce := r.Header.Get("X-Connect-Nonce")
	signature := r.Header.Get("X-Connect-Signature")
	clientKey := r.Header.Get("X-Connect-Client-Key")

	clientSecret := "client_secret" // Replace with your actual secret

	// Read and preserve the body
	bodyBytes, err := io.ReadAll(r.Body)
	if err != nil {
		return false
	}
	// Reset r.Body so it can be read again later if needed
	r.Body = io.NopCloser(strings.NewReader(string(bodyBytes)))

	// Base64 URL encode the body
	bodyEncoded := base64.URLEncoding.EncodeToString(bodyBytes)

	// Build the signing string
	signingString := r.URL.Path + nonce + timestamp + bodyEncoded

	// Compute HMAC-SHA256
	h := hmac.New(sha256.New, []byte(clientSecret))
	h.Write([]byte(signingString))
	expectedSignature := base64.URLEncoding.EncodeToString(h.Sum(nil))

	// Constant-time comparison
	return hmac.Equal([]byte(signature), []byte(expectedSignature))
}

NodeJS

// Replace with your actual secret
const clientSecret = '0TxSN1NN7A8_v3_AsbbCffjEPEchBewtuRHCUMvVHy0DOh422PaHrbAk5WccWW0F';

function verifySignature(req: Request): boolean {
    const timestamp = req.header('X-Connect-Timestamp');
    const nonce = req.header('X-Connect-Nonce');
    const signature = req.header('X-Connect-Signature');
    const clientKey = req.header('X-Connect-Client-Key');

    const rawBody = req.body;
    if (!timestamp || !nonce || !signature || !clientKey) {
        return false;
    }
    if (!rawBody) {
        return false;
    }
    const bodyEncoded = base64UrlEncode(rawBody.toString());
    const signingString = req.path + nonce + timestamp + bodyEncoded;

    const expectedSignature = generateSignature(signingString, clientSecret);

    // Secure compare
    const result = crypto.timingSafeEqual(
        Buffer.from(signature),
        Buffer.from(expectedSignature)
    );
    return result;

}

export function base64UrlEncode(input: string): string {
    const encoded = typeof window === 'undefined'
        ? Buffer.from(input).toString('base64')
        : btoa(unescape(encodeURIComponent(input)));

    return encoded.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
}

function generateSignature(signingString: string, clientSecret: string): string {
    const hmac = crypto.createHmac('sha256', clientSecret);

    hmac.update(signingString);

    const digest = hmac.digest();
    // Base64 URL encode: replace '+' with '-', '/' with '_', and remove '=' padding
    return digest.toString('base64').replace(/\+/g, '-').replace(/\//g, '_');
}

Java

private boolean verifySignature(HttpServletRequest request) throws IOException {
        String timestamp = request.getHeader("X-Connect-Timestamp");
        String nonce = request.getHeader("X-Connect-Nonce");
        String signature = request.getHeader("X-Connect-Signature");

        // Read raw body
        String body = new Scanner(request.getInputStream(), "UTF-8").useDelimiter("\\A").next();
        byte[] bodyBytes = body.getBytes(StandardCharsets.UTF_8);

        // Base64 URL encode the body
        String bodyEncoded = Base64.getUrlEncoder().withoutPadding().encodeToString(bodyBytes);

        // Build signing string
        String signingString = request.getRequestURI() + nonce + timestamp + bodyEncoded;

        try {
            Mac hmacSha256 = Mac.getInstance("HmacSHA256");
            SecretKeySpec secretKey = new SecretKeySpec(CLIENT_SECRET.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
            hmacSha256.init(secretKey);

            byte[] hashBytes = hmacSha256.doFinal(signingString.getBytes(StandardCharsets.UTF_8));
            String expectedSignature = Base64.getEncoder().encodeToString(hashBytes);

            if (expectedSignature.equals(signature)) {
                return true;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return false;
    }

Payload

Webhook events that can be received from Gearment

Webhooks