Callback URL

For long-running actions, clients need to maintain a polling to track the action's status periodically. When the action is finished, the client will have access to the response url to get the response data. Sometimes this is not a convenient process.

The Callback URL feature makes our server send back the response data actively to a prepared callbackUrl when it finishes the action. The callbackUrl is an endpoint prepared and maintained by client that must be able to receive and process our server's request message.

Usage

Request

The client attaches a value for the callbackUrl field into the request data. This callbackUrl field is optional.

{
  "callbackUrl": "https://bespokify.com/callbackUrl"
}

WARNING

The client must prepare the endpoint for callbackUrl to handle POST messages from our server.

Response data

When server finishes processing, it connects to the callbackUrl and sends a POST message with resource data that includes:

Parameter Type Description
id string Resource id
type string Resource type
url string Resource url
data object Resource data. it is instant response data at the time of completion. (The client can also retrieve this data by accessing the response url).

The response is sent along with the X-Bespokify-Signature header, which is generated using a shared secret (this will be provided).

Verification

To verify that the request came from Bespokify, compute the HMAC digest according to the following algorithm and compare it to the value in the X-Bespokify-Signature header. If they match, you can be sure that the request was sent from Bespokify and the data has not been compromised.

Below is a simple example in NodeJS with Express framework:

const express = require('express');
const bodyParser = require('body-parser');
const app = express();
const crypto = require('crypto');

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

/**
 *
 * @param {object} data
 * @param {hmacHeader} string
 */
function verifyWebhook({ data, hmacHeader }) {
  const secretToken = 'YOUR_SECRET_TOKEN';
  const calculatedHmac = crypto
    .createHmac('sha256', secretToken)
    .update(JSON.stringify(data))
    .digest('hex');
  return calculatedHmac === hmacHeader;
}

app.post('/', (req, res) => {
  const hmacHeader = req.headers['X-Bespokify-Signature'];
  const data = req.body;
  const verified = verifyWebhook({ data, hmacHeader });
  res.send(`Webhook verified: ${verified}`);
});

Example

In this case, the client has prepared the callback URL at: https://bespokify.com/callbackUrl.

The following is the request data for the export function:

{
  "draftId": "e02bc2c6-ff09-4f71-9b31-062f5ef7e751",
  "callbackUrl": "https://bespokify.com/callbackUrl",
  "fileType": "dxf",
  "config": {
    "format": "aama",
    "driver": "generic",
    "singleInstance": true,
    "materialGroup": false,
    "singleFile": false
  },
  "nesting": {
    "sheetWidth": 140,
    "preNestRotation": 45,
    "partRotation": 0,
    "partMargin": 1,
    "sheetLength": 3000,
    "sheetEdgeMargin": 10
  },
  "objects": ["ShirtFront", "ShirtBack"]
}

WARNING

Currently, the callbackUrl feature is supported only for the draft, export, and batch functions (which need long execution times).

After the server prepares the export file, it posts the response data to https://bespokify.com/callbackUrl:

{
  "id": "467b7a82-ecb6-4591-af37-bc775baffdb3",
  "type": "export",
  "url": "https://api.bespokify.com/v2/exports/467b7a82-ecb6-4591-af37-bc775baffdb3",
  "data": {
    "id": "467b7a82-ecb6-4591-af37-bc775baffdb3",
    "draftId": "e02bc2c6-ff09-4f71-9b31-062f5ef7e751",
    "fileType": "dxf",
    "config": {
      "format": "aama",
      "driver": "generic",
      "singleInstance": true,
      "materialGroup": false,
      "singleFile": false
    },
    "nesting": {
      "sheetWidth": 140,
      "preNestRotation": 45,
      "partRotation": 0,
      "partMargin": 1,
      "sheetLength": 3000,
      "sheetEdgeMargin": 10
    },
    "objects": ["ShirtFront", "ShirtBack"],
    "createdAt": "2018-08-04T07:37:02.278Z",
    "status": "completed",
    "files": [
      {
        "filename": "output.dxf",
        "url": "https://path/to/output.dxf"
      }
    ]
  }
}