Skip to main content
To ensure the authenticity of a webhook, a digital signature is generated from the message payload and a secret key (sign-secret). The sign-secret is created by mobway when the webhook is configured and must be kept confidential.

How the signature is generated

The webhook signature is generated using the HMAC (Hash-based Message Authentication Code) method with the SHA-256 algorithm. This method combines the sign-secret with the transmitted data (payload) to create a unique signature. Any modification to the webhook content or headers will change the signature, making any tampering attempt evident.

Code example (Python) for consuming the Webhook

The example below shows how to create an interface to receive real-time vehicle data via Webhook using Python and the Flask library. This application must be hosted online at a URL that mobway can access to send the information.
import hmac
import json
import logging
import asyncio
import hashlib
import threading

from flask import Flask, request, jsonify, abort

app = Flask(__name__)

# Sign secret provided by mobway
SIGN_SECRET = 'YOUR_SIGN_SECRET_PROVIDED_BY_MOBWAY'

logging.basicConfig(level=logging.INFO)

def verify_signature(payload, signature):
    """
    Checks the authenticity of the webhook signature.
    
    Args:
      Payload (str): The content of the webhook received.
      Signature (str): The HMAC signature received in the webhook header.
    
    Returns:
      Bool: True if the signature is valid, False otherwise.
    """
    logging.info("Checking signature...")
    computed_signature = hmac.new(SIGN_SECRET.encode(), payload.encode(), hashlib.sha256).hexdigest()
    is_valid = hmac.compare_digest(computed_signature, signature)
    logging.info(f"Valid signature: {is_valid}")
    return is_valid

def process_data(data):
    """
    Processes the data received from the webhook.
    
    Args:
      Data (dict): Payload data in JSON format.
    """
    logging.info(f"Processing data: {data}")
    # Here you can add the logic to process the received data

async def handle_request(payload, signature):
    """
      Deals with the webhook request, verifying the signature and processing the payload.
      
      Args:
        Payload (str): The content of the webhook received.
        Signature (str): The HMAC signature received in the webhook header.
    """
    if not verify_signature(payload, signature):
        logging.warning("Invalid signature, aborting...")
        abort(403)
    
    logging.info("Signature successfully verified, processing request...")
    data = json.loads(payload)
    thread = threading.Thread(target=process_data, args=(data,))
    thread.start()
    thread.join()

@app.route('/', methods=['GET'])
def home():
    """
    Basic route for server status check.
    
    Returns:
      Response: Returns a success message.
    """
    return jsonify({"status": "success"}), 200

@app.route('/webhook', methods=['POST'])
async def webhook():
    """
    Route to receive webhook data.
    
    Returns:
      Response: Returns a success message after webhook processing.
    """
    logging.info("Webhook received...")
    payload = request.get_data(as_text=True)
    signature = request.headers.get('X-Signature')
    await handle_request(payload, signature)
    logging.info("Webhook processed successfully!")
    return jsonify({"status": "success"}), 200

if __name__ == '__main__':
    logging.info("Starting the Flask app...")
    app.run(host='0.0.0.0', port=5000, debug=True)
The /webhook route is where the server expects to receive webhooks sent by mobway. This route is configured to accept only POST HTTP requests. The webhook function associated with this route is asynchronous, allowing the server to handle multiple requests simultaneously and efficiently, without blocking execution while previous requests are being processed. Inside the webhook function, the payload (the webhook data) and the digital signature are extracted from the request. The signature is sent in the request header under the name X-Signature. The function then delegates signature verification and data processing to the handle_request function. The mobway server that sends data through the webhook expects an HTTP 200 response code, indicating that the data was received successfully. If any other error code is returned, the server will retry sending the data successively until a predefined limit is reached. To ensure that no data is lost, the information is stored so it can be retrieved through other means if necessary. If the issue with receiving data persists, webhook delivery will be interrupted, and mobway will contact you to review and resolve the situation. The handle_request function is responsible for validating the authenticity of the signature and processing the received data. It receives the payload and the signature as parameters. First, it calls the verify_signature function to compare the received signature with the expected signature. Validation is performed using HMAC with the SHA-256 algorithm, combining the payload with the sign-secret stored on the server. If the signature is not valid, the function aborts the operation and returns an HTTP 403 status code, indicating that the request was rejected because it could not be authenticated. If the signature is valid, the data is converted from a JSON string into a dictionary and processed in a separate thread. The verify_signature function plays a key role in webhook security. It generates the signature locally using HMAC with SHA-256 and the sign-secret, and then compares that signature with the signature received in the request.

Payload example

The payload below is sent to the client as soon as vehicle data is received and processed by mobway. The structure includes all available data that the client is authorized to access, organized by VIN:
Response
{
  "6AHFT68CKAF501652": [
    {
      "vin": "6AHFT68CKAF501652",
      "date_time": "2023-02-14 09:51:48",
      "speed": 109.78,
      "latitude": 56.073055,
      "longitude": -177.689265,
      "heading": 357.92,
      "rpm": 3737.16,
      "odometer": 806942.06,
      "fuel_level": 79.79,
      "range": -75.68,
      "left_front_tire_pressure": 31.66,
      "right_front_tire_pressure": 31.95,
      "left_rear_tire_pressure": 31.17,
      "right_rear_tire_pressure": 31.88,
      "oil_level": 15.28,
      "engine_cooling_temperature": 11.4,
      "lv_battery_voltage": 12.41,
      "hv_battery_voltage": 596.41,
      "hv_battery_soc": 38.48,
      "hv_battery_charging_status": "other",
      "seat_belt_status": "not buckled",
      "event": "charging plug status change",
      "flag": {}
    },
    {
      "vin": "6AHFT68CKAF501652",
      "date_time": "2023-02-14 09:51:51",
      "speed": 265.23,
      "latitude": 56.089004,
      "longitude": -177.71086,
      "heading": 357.92,
      "rpm": 5591.89,
      "odometer": 806942.21,
      "fuel_level": 21.35,
      "range": -76.13,
      "left_front_tire_pressure": 31.66,
      "right_front_tire_pressure": 31.95,
      "left_rear_tire_pressure": 31.17,
      "right_rear_tire_pressure": 31.88,
      "oil_level": 95.38,
      "engine_cooling_temperature": 129.52,
      "lv_battery_voltage": None,
      "hv_battery_voltage": None,
      "hv_battery_soc": 17.87,
      "hv_battery_charging_status": "charging",
      "seat_belt_status": "not buckled",
      "event": "charging plug status change",
      "flag": {
        "lv_battery_voltage": {
          "value": 35.44,
          "flag": "out of range"
        },
        "hv_battery_voltage": {
          "value": 1200.54,
          "flag": "out of range"
        }
      }
    }
  ]
}
This payload is sent in real time whenever new data is received by mobway, ensuring that the client has immediate access to the most up-to-date information from the monitored vehicles.