---
updatedAt: 2025-09-24T12:50:18.000Z
agentTools:
  projectIndex: https://docs.skipify.com/llms.txt
---

# API Authentication: MAC with SHA-256

<HTMLBlock>{`
<style>
.App {
  --font-family: 'poppins', 'helvetica';
}
</style>
`}</HTMLBlock>

# Overview

Message Authentication Code (MAC) with SHA-256 cryptographic hashing is a common security mechanism used for Authentication and Authorization when sending requests to secure APIs. The process involves both encryption and hashing elements. To ensure that Skipify remains secure, we utilize MAC with SHA-256 for **most** Skipify API requests.

## Required Headers for MAC with SHA-256 Requests

API calls that utilize MAC with SHA-256 authentication require a set of 4 headers to be sent along with the request:

* x-merchant-id
* timestamp
* nonce
* signature

The first three headers will be used to generate the string for the signature as shown below.

<HTMLBlock>{`
<style>
  /* Terrell From ReadMe Here */
  .markdown-body .rdmd-table table {
    table-layout: fixed;
}
</style>
`}</HTMLBlock>

<Table align={["left","left","left"]}>
  <thead>
    <tr>
      <th>
        Header Element
      </th>

      <th>
        Description
      </th>

      <th>
        Example Value
      </th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>
        x-merchant-id
      </td>

      <td>
        This is a GUID (Globally Unique Identifier) that was provided to you during onboarding by the Skipify team. You can also view this identifier by logging into the [merchant portal](https://docs.skipify.com/docs/merchant-portal).
      </td>

      <td>
        76aae15d-de06-46df-91c8-3ff5beca1c8d
      </td>
    </tr>

    <tr>
      <td>
        timestamp
      </td>

      <td>
        This is the current timestamp in Unix Epoch time (s).
      </td>

      <td>
        1616562172
      </td>
    </tr>

    <tr>
      <td>
        nonce
      </td>

      <td>
        A nonce is a unique identifier to protect private communications by preventing replay attacks. Nonces are random or pseudo-random numbers/strings that authentication protocols attach to communications.  

        This is a string set by you that must be unique for each request.
      </td>

      <td>
        51c1442ebe284b74814cbc8411502b7c
      </td>
    </tr>

    <tr>
      <td>
        signature
      </td>

      <td>
        The signature is a hashed string containing both your Skipify merchant credentials, and elements of the specific request.  

        Below are additional Instructions for generating the signature.
      </td>

      <td>
        8bd00d630eea81f7ec1243cc0e2bc40516ecc3b91d863ba5d398d19aa294c2d8
      </td>
    </tr>
  </tbody>
</Table>

## Generating the Signature

Signatures will be generated from a string containing the `x-merchant-id, x-api-key, timestamp, nonce, requestUri, requestMethod,` and `requestBody`. Descriptions for these elements are listed below:

<Table align={["left","left","left"]}>
  <thead>
    <tr>
      <th>
        String Element
      </th>

      <th>
        Description
      </th>

      <th>
        Example Value
      </th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>
        **X-Merchant-Id**
      </td>

      <td>
        This is a GUID (Globally Unique Identifier) that was provided to you during onboarding by the Skipify team. You can also view this identifier by logging into the [merchant portal](https://docs.skipify.com/docs/merchant-portal).
      </td>

      <td>
        76aae15d-de06-46df-91c8-3ff5beca1c8d
      </td>
    </tr>

    <tr>
      <td>
        **X-Api-Key**
      </td>

      <td>
        Your API Key that was provided to you during onboarding by the Skipify team. You can view your key in the Configuration page of the [merchant portal](https://docs.skipify.com/docs/merchant-portal).
      </td>

      <td>
        f51fa8fc7b2d55689c21009ab3ffcbc4
      </td>
    </tr>

    <tr>
      <td>
        **Timestamp**
      </td>

      <td>
        This is the current timestamp in Unix Epoch time (s).
      </td>

      <td>
        1616562172
      </td>
    </tr>

    <tr>
      <td>
        **Nonce**
      </td>

      <td>
        A nonce is a unique identifier to protect private communications by preventing replay attacks. Nonces are random or pseudo-random numbers/strings that authentication protocols attach to communications.  

        This is a string set by you that must be unique for each request.
      </td>

      <td>
        51c1442ebe284b74814cbc8411502b7c
      </td>
    </tr>

    <tr>
      <td>
        **RequestURI**
      </td>

      <td>
        This is the request path. If performing a GET request, the query string must be included.  

        Note: The query string parameters must be in alphabetical order and the parameter values must be URL encoded using UTF-8 format like the example shown.
      </td>

      <td>
        orders/e40b83b7-4c5e-47e9-b6a7-c005831eb1d8/capture  

        payment-requests?begin=2022-02-02t21%3a21%3a21z\&end=2022-02-02t21%3a21%3a21z\&pageNumber=1\&pageSize=25  

        * \*Note\*\*: do not include a  leading or trailing forward slash, "/", in the URI
      </td>
    </tr>

    <tr>
      <td>
        **RequestMethod**
      </td>

      <td>
        Method associated with the request.
      </td>

      <td>
        GET | POST | PUT | DELETE
      </td>
    </tr>

    <tr>
      <td>
        **RequestBody**
      </td>

      <td>
        Body of the request (empty for GET requests).  

        See specific documentation for the required body for each endpoint.
      </td>

      <td>
```
  {
    "object": {
      "a": "b",
      "c": "d",
      "e": "f"
    },
    "array": [],
    "string": "Hello World"
  }
```
</td>

    </tr>
  </tbody>
</Table>

The string should be formatted as follows:

`[x-merchant-id]|[x-api-key]|[Timestamp]|[Nonce]|[RequestURI]|[RequestMethod]|[RequestBody]`

Using the example data from the table above, the generated string will be as follows:

**POST:**\
`76aae15d-de06-46df-91c8-3ff5beca1c8d|f51fa8fc7b2d55689c21009ab3ffcbc4|1616562172|51c1442ebe284b74814cbc8411502b7c|orders/e40b83b7-4c5e-47e9-b6a7-c005831eb1d8/capture|POST|{"object":{"a":"b","c":"d","e":"f"},"array":[1,2],"string":"Hello World"}`

**GET:**\
`76aae15d-de06-46df-91c8-3ff5beca1c8d|f51fa8fc7b2d55689c21009ab3ffcbc4|1616562172|51c1442ebe284b74814cbc8411502b7c|payment-requests?begin=2022-02-02t21%3a21%3a21z&end=2022-02-02t21%3a21%3a21z&pageNumber=1&pageSize=25|GET|`

Once the string has been generated, it should be formatted, encoded, and hashed following the steps below:

1. Remove all whitespace from the string (spaces, line feeds, carriage returns, and tabs should be replaced with an empty string)
2. Convert string to uppercase
3. Encode the string with Base64
4. Generate a SHA-256 hash from the Base64 encoded string

### Generating the Signature Examples

The following are code examples, all of which generate the MAC with SHA256 signature. These methods take in the parameters (`X-Merchant-Id, X-Api-Key, Timestamp, Nonce, RequestURI, RequestMethod, RequestBody`) and return a value to be used in the request **signature** header.

```java Java Example
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

public class HeaderUtil
{
    /*
    Generate the MAC with SHA-256 signature using the necessary keys and HTTP elements
    <param name="merchantId">The provided MID (e.g., "00000000-0000-0000-0000-000000000000") </param>
    <param name="apiKey">The provided API key (e.g., "00000000-0000-0000-0000-000000000000")</param>
    <param name="timestamp">The current Unix Epoch time (in seconds) (e.g., "1634324248" )</param>
    <param name="nonce">Unique Request Identifier (e.g., "00000000-0000-0000-0000-000000000000")</param>
    <param name="uriPath">Path of the request URI (e.g., "items/1")</param>
    <param name="httpVerb">HTTP verb of the request (e.g., "POST")</param>
    <param name="body">Body of the request(e.g., "{ "field1": "value1" }")</param>
    <returns> The signature header for MAC with SHA-256 requests </returns> */

    public String macSignature(String merchantId, String apiKey, String timestamp, String nonce, String uriPath,
                                String httpVerb, String body)
            throws NoSuchAlgorithmException
    {
        String formattedSignature = merchantId + "|" + apiKey + "|" + timestamp
                + "|" + nonce + "|" + uriPath + "|" + httpVerb + "|" + body;
        //remove all whitespace and convert to uppercase
        formattedSignature = formattedSignature.replaceAll("[\\r\\n\\t\\s]", "").toUpperCase();
        //base 64 encode
        String base64EncodedString = Base64.getEncoder().encodeToString(formattedSignature.getBytes());
        MessageDigest digest = MessageDigest.getInstance("SHA-256");
        byte[] sha256Hash = digest.digest(base64EncodedString.getBytes(StandardCharsets.UTF_8));
        return convertBytesToHex(sha256Hash);

    }

    private static String convertBytesToHex(byte[] hash)
    {
        StringBuilder hexString = new StringBuilder(2 * hash.length);
        for (byte b : hash)
        {
            String hex = Integer.toHexString(0xff & b);
            if (hex.length() == 1)
            {
                hexString.append('0');
            }
            hexString.append(hex);
        }
        return hexString.toString();
    }
}
```
```csharp C# Example
using System;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;

namespace MAC {
    public class HeaderUtility {

        /// <summary>
        /// Generate the MAC signature with SHA-256 using the necessary keys and HTTP elements
        /// </summary>
        /// <param name="merchantId">The provided MID (e.g., "00000000-0000-0000-0000-000000000000") </param>
        /// <param name="apiKey">The provided API key (e.g., "00000000-0000-0000-0000-000000000000")</param>
        /// <param name="timestamp">The current Unix Epoch time (in seconds) (e.g., "1634324248" )</param>
        /// <param name="nonce">Unique Request Identifier (e.g., "00000000-0000-0000-0000-000000000000")</param>
        /// <param name="uriPath">Path of the request URI (e.g., "items/1")</param>
        /// <param name="httpVerb">HTTP verb of the request (e.g., "POST")</param>
        /// <param name="body">Body of the request(e.g., "{ "field1": "value1" }")</param>
        /// <returns>The signature header for MAC with SHA-256 requests </returns>
        public static string GenerateSignature(string merchantId, string apiKey, string timestamp, string nonce, string uriPath, string httpVerb, string body) {
            // Compose signature elements
            string signatureRaw = $"{merchantId}|{apiKey}|{timestamp}|{nonce}|{uriPath}|{httpVerb}|{body}";

            // Remove characters CR, LF, TAB, and whitespace
            string signatureCleaned = Regex.Replace(signatureRaw, @"[\r\n\t\s]", string.Empty);

            // Convert string to upper-case
            string signatureUpper = signatureCleaned.ToUpperInvariant();

            // Base64 encode string
            string signatureBase64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(signatureUpper));

            // SHA-256 hashed string
            using SHA256 sha256 = SHA256.Create();
            byte[] signatureHashedBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(signatureBase64));
            string signature = string.Join(null, signatureHashedBytes.Select(b => b.ToString("x2")));

            return signature;
        }
    }
}
```
```php PHP Example
<?PHP
/**
 * Generate the MAC with SHA-256 signature using the necessary keys and HTTP elements
 * @param string $merchant_id The provided MID (e.g., "00000000-0000-0000-0000-000000000000")
 * @param string $api_key The provided API key (e.g., "00000000-0000-0000-0000-000000000000")
 * @param integer $timestamp The current Unix Epoch time (in seconds) (e.g., "1634324248"
 * @param string $nonce Unique Request Identifier (e.g., "00000000-0000-0000-0000-000000000000")
 * @param string $uri_path Path of the request URI (e.g., "items/1")
 * @param string $http_verb HTTP verb of the request (e.g., "POST")
 * @param string $body Body of the request(e.g., "{ "field1": "value1" }")
 * @return string The signature header for MAC with SHA-256 requests
 */
function mac_signature($merchant_id, $api_key, $timestamp, $nonce, $uri_path, $http_verb, $body)
{
    // Compose signature elements
    $signature_raw = "{$merchant_id}|{$api_key}|{$timestamp}|{$nonce}|{$uri_path}|{$http_verb}|{$body}";

    // Remove characters CR, LF, TAB, and whitespace
    $signature_cleaned = str_replace(array("\r", "\n", "\t", " ") , '', $signature_raw);

    // Convert string to upper-case
    $signature_upper = strtoupper($signature_cleaned);

    // Base64 encode string
    $signature_base64 = base64_encode($signature_upper);

    // SHA-256 encode string
    $signature = hash('sha256', $signature_base64);

    return $signature;
}
?>
```

***

<HTMLBlock>{`
<a href="https://www.skipify.com/get-in-touch"><img src="https://files.readme.io/279452f-CTA_Contact_Footer_1440x205_Final.png" alt="Skipify baner with link to contact us form"></a>
`}</HTMLBlock>