Documentation Index Fetch the complete documentation index at: https://docs.scenext.cn/llms.txt
Use this file to discover all available pages before exploring further.
Signature Verification
To ensure the security and integrity of callback notifications, Scenext uses the HMAC-SHA256 algorithm to sign all callback requests.
Signature Algorithm
Generation Process
Convert callback data to JSON string (sorted by key names)
Use your API key as the secret key
Generate signature using HMAC-SHA256 algorithm
Convert signature to hexadecimal string
Python Implementation
import hmac
import hashlib
import json
def generate_signature ( payload , api_key ):
"""
Generate HMAC-SHA256 signature
:param payload: Data to be sent
:param api_key: API key for signing
:return: Hexadecimal signature
"""
# Convert payload to JSON string
if isinstance (payload, dict ):
payload_str = json.dumps(payload, sort_keys = True )
else :
payload_str = str (payload)
# Generate signature using HMAC-SHA256
signature = hmac.new(
key = api_key.encode( 'utf-8' ),
msg = payload_str.encode( 'utf-8' ),
digestmod = hashlib.sha256
).hexdigest()
return signature
def verify_signature ( payload , signature , api_key ):
"""
Verify HMAC-SHA256 signature
"""
expected_signature = generate_signature(payload, api_key)
return hmac.compare_digest(expected_signature, signature)
JavaScript Implementation
const crypto = require ( 'crypto' );
function generateSignature ( payload , apiKey ) {
// Convert payload to JSON string (sorted by keys)
const payloadStr = JSON . stringify ( payload , Object . keys ( payload ). sort ());
// Generate signature
const signature = crypto
. createHmac ( 'sha256' , apiKey )
. update ( payloadStr , 'utf8' )
. digest ( 'hex' );
return signature ;
}
function verifySignature ( payload , signature , apiKey ) {
const expectedSignature = generateSignature ( payload , apiKey );
return crypto . timingSafeEqual (
Buffer . from ( expectedSignature , 'hex' ),
Buffer . from ( signature , 'hex' )
);
}
PHP Implementation
<? php
function generateSignature ( $payload , $apiKey ) {
// Convert payload to JSON string (sorted by keys)
if ( is_array ( $payload )) {
ksort ( $payload );
$payloadStr = json_encode ( $payload );
} else {
$payloadStr = ( string ) $payload ;
}
// Generate signature
return hash_hmac ( 'sha256' , $payloadStr , $apiKey );
}
function verifySignature ( $payload , $signature , $apiKey ) {
$expectedSignature = generateSignature ( $payload , $apiKey );
return hash_equals ( $expectedSignature , $signature );
}
?>
Complete Verification Examples
Flask (Python) Server
from flask import Flask, request, jsonify
import hmac
import hashlib
import json
app = Flask( __name__ )
API_KEY = "your_api_key_here" # Your API key
def verify_signature ( payload , signature ):
"""Verify signature"""
payload_str = json.dumps(payload, sort_keys = True )
expected_signature = hmac.new(
key = API_KEY .encode( 'utf-8' ),
msg = payload_str.encode( 'utf-8' ),
digestmod = hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected_signature, signature)
@app.route ( '/webhook' , methods = [ 'POST' ])
def webhook ():
# Get signature
signature = request.headers.get( 'X-Signature' )
if not signature:
return jsonify({ 'error' : 'Missing signature' }), 400
# Get request data
try :
data = request.get_json()
except Exception :
return jsonify({ 'error' : 'Invalid JSON' }), 400
# Verify signature
if not verify_signature(data, signature):
return jsonify({ 'error' : 'Invalid signature' }), 401
# Process callback data
task_id = data.get( 'task_id' )
status = data.get( 'status' )
print ( f "Received webhook for task { task_id } with status { status } " )
# Process based on status
if status == 'COMPLETED' :
# Task completion handling
result = data.get( 'result' , {})
video_url = result.get( 'video_url' )
print ( f "Video completed: { video_url } " )
elif status == 'FAILED' :
# Task failure handling
result = data.get( 'result' , {})
error = result.get( 'error' )
print ( f "Video generation failed: { error } " )
return jsonify({ 'message' : 'OK' }), 200
if __name__ == '__main__' :
app.run( debug = True )
Express (Node.js) Server
const express = require ( 'express' );
const crypto = require ( 'crypto' );
const app = express ();
const API_KEY = 'your_api_key_here' ; // Your API key
app . use ( express . json ());
function verifySignature ( payload , signature ) {
const payloadStr = JSON . stringify ( payload , Object . keys ( payload ). sort ());
const expectedSignature = crypto
. createHmac ( 'sha256' , API_KEY )
. update ( payloadStr , 'utf8' )
. digest ( 'hex' );
return crypto . timingSafeEqual (
Buffer . from ( expectedSignature , 'hex' ),
Buffer . from ( signature , 'hex' )
);
}
app . post ( '/webhook' , ( req , res ) => {
const signature = req . headers [ 'x-signature' ];
if ( ! signature ) {
return res . status ( 400 ). json ({ error: 'Missing signature' });
}
const data = req . body ;
if ( ! verifySignature ( data , signature )) {
return res . status ( 401 ). json ({ error: 'Invalid signature' });
}
// Process callback data
const { task_id , status , result } = data ;
console . log ( `Received webhook for task ${ task_id } with status ${ status } ` );
if ( status === 'COMPLETED' ) {
console . log ( `Video completed: ${ result . video_url } ` );
} else if ( status === 'FAILED' ) {
console . log ( `Video generation failed: ${ result . error } ` );
}
res . status ( 200 ). json ({ message: 'OK' });
});
app . listen ( 3000 , () => {
console . log ( 'Webhook server listening on port 3000' );
});
Security Best Practices
FAQ
What to do if signature verification fails?
Check if the API key is correct
Ensure JSON serialization sorts keys by name
Verify that request data hasn’t been modified
Check that character encoding is UTF-8
Can I skip signature verification?
We strongly recommend not skipping signature verification. This would expose your system to security risks, including but not limited to: forged callback requests, data tampering, etc.
Is timestamp verification required?
Timestamp verification is not required but recommended. You can check if the timestamp is within a reasonable range (e.g., within 5 minutes) to prevent replay attacks.