# Custom API Integration

Learn how to connect your custom ecommerce store with Sign Customiser using webhooks, product creation, and order processing APIs

- Source URL: https://www.signcustomiser.com/help/integrations/custom-api-integration/
- Markdown URL: https://www.signcustomiser.com/help/integrations/custom-api-integration.md
- Category: Integrations
- Last updated: 2026-04-18

## Article

This guide will walk you through the process of integrating your custom ecommerce store with Sign Customiser, allowing your customers to design custom signs directly on your website.

## Overview

The integration consists of two main components:

1.  **Product Creation Flow**: When a customised sign is created, we'll notify your system and you'll provide us with a product ID

2.  **Order Processing**: When an order is placed, you'll send the order details to our API for processing

## Part 1: Setting Up the Integration in Sign Customiser

## Step 1: Access Integration Settings

1.  Log into your Sign Customiser account.

2.  In the left sidebar, under **Integrate**, click **Integrations**.

3.  Find the **Custom Integration** card and click **Connect Custom**.

## Step 2: Configure Your Create Product URL

1.  Enter the full URL where we should POST when a product is created

    -   This should be an endpoint on your server that can receive and process product data

    -   Example: [`https://yourstore.com/api/sign-customiser/products`](https://yourstore.com/api/sign-customiser/products)

2.  Enter a name on the form click on **Create** to save the integration.

## Step 3: Get Your Embed Code

After creating the integration, click `View Details`.
On the detail page you can reveal/copy the `Integration Secret` and copy the embed code. You will need this secret to verify signed requests from Sign Customiser.
​

```html
<script src="https://integrations.signcustomiser.com/sign-customiser-embed.js"></script>
<sign-customiser-embed
  customiser-id="YOUR_CUSTOMISER_ID"
  integration-id="YOUR_INTEGRATION_ID"
  driver="custom">
</sign-customiser-embed>
```

Place this code on the pages where you want customers to customise signs.

Underneath the HTML embed code, you should handle the "add to cart" step based on your own e-commerce platform:

```html
<script>
window.addEventListener("message", (event) => {
  if (event.data.type === "sc:product:created") {
    // add the product to cart
    // console.log("Product Data", event.data.product)
  }
});
</script>
```

## Part 2: Handling Product Creation

## Your Product Creation Endpoint

When a customer creates a customised sign, we'll send a POST request to your configured URL with the following payload:

```
{ "product": { // Product details from Sign Customiser } }
```

You should verify that the request came from us by checking the signature.

Sign Customiser includes two important headers with each webhook:

-   `x-webhook-timestamp`: The Unix timestamp when the webhook was sent

-   `x-webhook-signature`: A SHA-256 HMAC signature of the payload

<div class="intercom-interblocks-callout" style="background-color: #feedaf80; border-color: #fbc91633;"><p class="no-margin">Signature verification must use the raw request body. In Node/Express, use route-level raw body middleware such as <code>express.raw(\{ type: "application/json" \})</code> before parsing JSON.</p></div>

## Implementation Steps

### Step 1: Extract Headers and Payload

When your endpoint receives a request, extract the timestamp and signature from the headers, plus capture the raw request body:

```
const timestamp = req.headers["x-webhook-timestamp"];
const signature = req.headers["x-webhook-signature"];
const rawPayload = req.body.toString("utf8"); // Raw JSON string
```

### Step 2: Verify Timestamp (Prevent Replay Attacks)

Check that the webhook timestamp is recent (within 5 minutes) to prevent replay attacks:

```
const currentTime = Math.floor(Date.now() / 1000);
const webhookTime = Number.parseInt(timestamp, 10);
const timeDiff = Math.abs(currentTime - webhookTime);
if (timeDiff > 300) { // 5 minutes in seconds 
  return false; // Reject old webhooks
}
```

### Step 3: Create the Signature String

Combine the timestamp and raw payload to create the string that was signed:

```
const stringToSign = `${timestamp}.${rawPayload}`;
```

### Step 4: Calculate Expected Signature

Using your secret (copied from the detail page), calculate what the signature should be:

```
const expectedSignature = crypto.createHmac("sha256", webhookSecret).update(stringToSign).digest("hex");
```

### Step 5: Compare Signatures Securely

Use a constant-time comparison to prevent timing attacks:

```
const isValid = crypto.timingSafeEqual( Buffer.from(signature, "hex"), Buffer.from(expectedSignature, "hex") );
```

### Step 6: Create the product in your system and return the ID

Your endpoint must return a 200 status code and a JSON object with an "external\_id" key

```
{ "external_id": "your-product-id-123" }
```

The `external_id` should be the unique identifier for the product in your system. We'll need this ID later when processing orders.

## Part 3: Processing Orders

## Generate API Token

Before you can send orders to Sign Customiser, you'll need to generate API keys. [View our API documentation](../../universal-app/how-to-create-an-api-token/) for detailed instructions on generating and managing your API keys.

## Send Orders to Sign Customiser

When an order is placed in your system that contains Sign Customiser products, POST the order details to:

​**Endpoint:** [`https://web.signcustomiser.com/api/v2/orders`](https://web.signcustomiser.com/api/v2/orders)

**Headers:**

```
Authorization: Bearer YOUR_API_TOKEN
Content-Type: application/json
Accept: application/json 
```

## Order Payload Structure

```
{
"integration_id": 42,
"external_id": "your-order-id-456",
"external_order_number": "ORDER-2024-001",
"currency": "USD",
"billing_address": {
"first_name": "John",
"last_name": "Doe",
"email": "john@example.com",
"phone": "+1234567890",
"address_1": "123 Main St",
"address_2": "Apt 4B",
"city": "New York",
"province": "NY",
"postcode": "10001",
"country": "US"
 },
"shipping_address": {
"first_name": "John",
"last_name": "Doe",
"address_1": "123 Main St",
"address_2": "Apt 4B",
"city": "New York",
"province": "NY",
"postcode": "10001",
"country": "US"
 },
"shipping_line": "Standard Shipping",
"customer": {
"first_name": "John",
"last_name": "Doe",
"email": "john@example.com",
"phone": "+1234567890"
 },
"products": [
{
"external_id": "your-product-id-123",
"quantity": 2,
"price": 2999
 }
]
}
```

## Field Requirements

### Required Fields

-   `integration_id`: Your Sign Customiser integration ID

-   `external_id`: Your internal order ID

-   `external_order_number`: Human-readable order number

-   `products`: Array of products in the order

-   `products.*.external_id`: Must match the ID you returned during product creation

-   `products.*.quantity`: Optional. Defaults to `1` if omitted, if provided, it must be at least `1`

### Optional Fields

-   `currency`: Order currency (e.g., "USD", "EUR")

-   `billing_address`: Customer billing information

-   `shipping_address`: Delivery address

-   `shipping_line`: Shipping method description

-   `customer`: Customer details

-   `products.*.price`: Product price in cents (e.g., 2999 = $29.99)

### Important Notes

-   **Product External IDs**: The `external_id` values in your order must exactly match the IDs you returned during the product creation process. This is how we link orders to the correct customised signs.

-   **Prices**: All price values should be in the smallest currency unit (cents for USD, pence for GBP, etc.)
