VizumVizum

Documentation

Base URL

https://sandbox.vizum.mx

All API requests should be prefixed with this base URL.

Authentication

Calculation of Signature

The signature is calculated as a hash of a concatenation of specific strings according to the following formula:

signature = BASE64 ( HASH ( httpmethod + urlpath + salt + timestamp + accesskey + secretkey + bodystring ) )

Components:

  • BASE64 - Base-64 encoding algorithm
  • HASH - HMAC-SHA256 algorithm
  • httpmethod - The HTTP method, in lower-case letters
  • urlpath - The portion of the URL after the base URI (starts with /api/v1)
  • salt - A random string for each request (recommended length: 8-16 characters)
  • timestamp - The time of the request, in Unix time (seconds)
  • accesskey - A unique string assigned by Vizum for each user
  • secretkey - A unique string assigned by Vizum (do not share or transmit in plaintext)
  • bodystring - A valid JSON string (for requests with a body, empty if no body)

Implementation:

import CryptoJS from 'crypto-js';

const accessKey = '<VIZUM_CLIENT_ID>' 
const secretKey = '<YOUR_SECRET_KEY>' 
const log = true; 

/**
 * @param {string} method - HTTP method
 * @param {string} url - URL path
 * @param {object} body - Body of the request
 */
export async function buildRequest(method, urlPath, body = null) {
  try {
    let headers = {}

    const salt = generateRandomString();
    const idempotency = new Date().getTime().toString();
    const timestamp = (Math.floor(new Date().getTime() / 1000) - 10).toString();
    const signature = await sign(method, urlPath, salt, timestamp, body);

    headers = {
      path: urlPath,
      port: 443,
      method: method,
      headers: {
        'Content-Type': 'application/json',
        access_key: accessKey,
        signature: signature,
        timestamp: timestamp,
        salt: salt,
        idempotency: idempotency
      },
      body: body ? JSON.stringify(body) : body
    }
    
    return headers;
  }
  catch(err) {
    log && console.log('buildRequest |', err)
  }
}

function generateRandomString(size = 12) {
  try {
    let salt = CryptoJS.lib.WordArray.random(size);
    return salt.toString();
  }
  catch (error) {
    log && console.log('salt error |', error)
  }
}

/**
 * @param {string} httpMethod - HTTP method
 * @param {string} urlPath - URL path
 * @param {string} salt - Salt for the signature
 * @param {string} timestamp - Timestamp in ISO format
 * @param {object} body - Body of the request
 */
async function sign(httpMethod, urlPath, salt, timestamp, body) {
  try {
    let bodyString = "";
        if (body) {
            bodyString = JSON.stringify(body);
            bodyString = bodyString == "{}" ? "" : bodyString;
        }
    const toSign = httpMethod.toLowerCase() + urlPath + salt + timestamp + accessKey + secretKey + bodyString;
    let signature = CryptoJS.enc.Hex.stringify(
      CryptoJS.HmacSHA256(toSign, secretKey)
    );
    signature = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(signature));
    
    return signature;
  }
  catch (error) {
    throw error
  }
}

// # How to use this function
//   const url = {VIZUM_URL}{urlPath};
//    return await fetch(url, headers)
//      .then();
//    console.log(headers);

Important: Never share your secret key or include it directly in client-side code. The signature calculation should be performed on your server.

Response Format

All API responses follow a standard format with the following fields:

  • id - A unique identifier for the request
  • body - The response data
  • status - HTTP status code
  • message - A human-readable message describing the result
{
  "id": "fd5596a1-e141-4830-8441-20630350538d",
  "body": {
    // Response data specific to the endpoint
  },
  "status": 200,
  "message": "Operation completed successfully"
}