HMAC Calculation

A guide to calculating your HMAC secret

HMAC Authentication

Accept callbacks rely on HMAC authentication to verify Accept's identity and integrity of its data.
Every and each callback invoked from Accept's server-side has its own HMAC validation, and they all calculated with the same methodology, once you implemented one of them you can implement the others.

Main Method

Whenever you receive a callback from Accept's end, You will receive a value of the HMAC related to the data received in the request in a query param called hmac, you should calculate an HMAC value equal to the HMAC sent with the received callback, in order to calculate an HMAC similar to the one you received, prepare your endpoint to perform the following:

  1. Sort the data received by key Lexicographical order.

  2. Depending on the type of the received callback, concatenate the values of the keys/params in one string, for any transaction callback, the data fields that should be taken in the concentrations are:

amount_cents
created_at
currency
error_occured
has_parent_transaction
obj.id
integration_id
is_3d_secure
is_auth
is_capture
is_refunded
is_standalone_payment
is_voided
order.id
owner
pending
source_data.pan
source_data.sub_type
source_data.type
success

The keys/params should be in the same order shown in the above text.

  1. Calculate the hash of the concatenated string using SHA512 and your HMAC secret, found in the profile tab in your dashboard.

  2. Now compare both HMAC values, the one you received with the sent request and the one you calculated out of this request if both are equal, you can safely save this data and use it in your system.

Transaction Processed/Response Callback:

For the processed callbacks, you should concatenate a string from the mentioned fields with the same order.
So, if we considered the up-mentioned sample transaction processed callback sample, the resultant string should be like:

1002020-03-25T18:39:44.719228EGPfalsefalse25567066741truefalsefalsefalsetruefalse47782394705false2346MasterCardcardtrue

And if you considered the up-mentioned transaction processed callback sample, the HMAC related to it should be:

6965eb228a2ee5003f9dc01528d68271fdbeae7af0e5bbb1d4915cecff675c2fcb3f08aec78e5859e198ca2b1e53c622a7b5ab7dcb9d15b6ab051a25d1ea1a74

So the total results should be like

{
  "obj": {
    "id": 2556706,
    "pending": false,
    "amount_cents": 100,
    "success": true,
    "is_auth": false,
    "is_capture": false,
    "is_standalone_payment": true,
    "is_voided": false,
    "is_refunded": false,
    "is_3d_secure": true,
    "integration_id": 6741,
    "profile_id": 4214,
    "has_parent_transaction": false,
    "order": {
      "id": 4778239,
      "created_at": "2020-03-25T18:36:05.494685",
      "delivery_needed": true,
      "merchant": {
        "id": 4214,
        "created_at": "2019-09-22T18:32:56.764441",
        "phones": [
          "01032347111"
        ],
        "company_emails": [
          "[email protected]"
        ],
        "company_name": "Accept Payments",
        "state": "",
        "country": "EGY",
        "city": "",
        "postal_code": "",
        "street": ""
      },
      "collector": {
        "id": 115,
        "created_at": "2019-06-29T00:48:26.910433",
        "phones": [],
        "company_emails": [],
        "company_name": "logix - test",
        "state": "Heliopolis",
        "country": "egypt",
        "city": "cairo",
        "postal_code": "123456",
        "street": "Marghany"
      },
      "amount_cents": 2000,
      "shipping_data": {
        "id": 2558893,
        "first_name": "abdulrahman",
        "last_name": "Khalifa",
        "street": "Wadi el Nile",
        "building": "5",
        "floor": "11",
        "apartment": "1565162",
        "city": "Cairo",
        "state": "Cairo",
        "country": "EG",
        "email": "[email protected]",
        "phone_number": "01011994353",
        "postal_code": "",
        "extra_description": " ",
        "shipping_method": "UNK",
        "order_id": 4778239,
        "order": 4778239
      },
      "shipping_details": {
        "id": 1401,
        "cash_on_delivery_amount": 0,
        "cash_on_delivery_type": "Cash",
        "latitude": null,
        "longitude": null,
        "is_same_day": 0,
        "number_of_packages": 1,
        "weight": 1,
        "weight_unit": "Kilogram",
        "length": 1,
        "width": 1,
        "height": 1,
        "delivery_type": "PUD",
        "return_type": null,
        "order_id": 4778239,
        "notes": "im so tired",
        "order": 4778239
      },
      "currency": "EGP",
      "is_payment_locked": false,
      "is_return": false,
      "is_cancel": false,
      "is_returned": false,
      "is_canceled": false,
      "merchant_order_id": null,
      "wallet_notification": null,
      "paid_amount_cents": 100,
      "notify_user_with_email": false,
      "items": [],
      "order_url": "https://accept.paymobsolutions.com/i/nYWD",
      "commission_fees": 0,
      "delivery_fees_cents": 0,
      "delivery_vat_cents": 0,
      "payment_method": "tbc",
      "merchant_staff_tag": null,
      "api_source": "OTHER",
      "pickup_data": null,
      "delivery_status": []
    },
    "created_at": "2020-03-25T18:39:44.719228",
    "transaction_processed_callback_responses": [],
    "currency": "EGP",
    "source_data": {
      "pan": "2346",
      "type": "card",
      "sub_type": "MasterCard"
    },
    "api_source": "IFRAME",
    "terminal_id": null,
    "is_void": false,
    "is_refund": false,
    "data": {
      "acq_response_code": "00",
      "avs_acq_response_code": "Unsupported",
      "klass": "VPCPayment",
      "receipt_no": "008603626261",
      "order_info": "[email protected]",
      "message": "Approved",
      "gateway_integration_pk": 6741,
      "batch_no": "20200325",
      "card_num": null,
      "secure_hash": "832F4673452F9538CCD57D6B07B74183A0EEB1BEF7CA58704E31B244E8366549",
      "avs_result_code": "Unsupported",
      "card_type": "MC",
      "merchant": "TEST999999EGP",
      "created_at": "2020-03-25T16:40:37.127504",
      "merchant_txn_ref": "6741_572e773a5a0f55ff8de91876075d023e",
      "authorize_id": "626261",
      "currency": "EGP",
      "amount": "100",
      "transaction_no": "2090026774",
      "txn_response_code": "0",
      "command": "pay"
    },
    "is_hidden": false,
    "payment_key_claims": {
      "lock_order_when_paid": true,
      "integration_id": 6741,
      "billing_data": {
        "email": "[email protected]",
        "building": "8028",
        "apartment": "803",
        "street": "Ethan Land",
        "country": "CR",
        "state": "Utah",
        "last_name": "Nicolas",
        "first_name": "Clifford",
        "postal_code": "01898",
        "extra_description": "NA",
        "phone_number": "+86(8)9135210487",
        "floor": "42",
        "city": "Jaskolskiburgh"
      },
      "order_id": 4778239,
      "user_id": 4705,
      "pmk_ip": "197.57.37.135",
      "exp": 1585157836,
      "currency": "EGP",
      "amount_cents": 100
    },
    "error_occured": false,
    "is_live": false,
    "other_endpoint_reference": null,
    "refunded_amount_cents": 0,
    "source_id": -1,
    "is_captured": false,
    "captured_amount": 0,
    "merchant_staff_tag": null,
    "owner": 4705,
    "parent_transaction": null
  },
  "type": "TRANSACTION"
}
1002020-03-25T18:39:44.719228EGPfalsefalse25567066741truefalsefalsefalsetruefalse47782394705false2346MasterCardcardtrue
6965eb228a2ee5003f9dc01528d68271fdbeae7af0e5bbb1d4915cecff675c2fcb3f08aec78e5859e198ca2b1e53c622a7b5ab7dcb9d15b6ab051a25d1ea1a74
DF42E0CDDDEABBC182E7297FC4C0206B

Token Object HMAC Calculation:

If you are saving cards and using them as tokens, you should receive token objects which will contain the card details and their respective tokens and will receive the token object HMAC as a query parameter. To calculate it, you should use the following order to create the HMAC string and then follow the same steps above to reach the final HMAC result and match it to the one received.

The order will be as follows:

card_subtype
created_at
email
id
masked_pan
merchant_id
order_id
token

πŸ‘

Try to implement a logic that calculates the HMAC out of the up-mentioned sample callback, and if you got the same results, add this logic to your Transaction processed/response callback endpoints.