Skip to content

Signing Algorithm

Every Open Platform API request must be authenticated with a signature. The scheme is intentionally minimal:

sign = MD5(timestamp + body + appSecret)

All credentials go into HTTP headers; the request body stays as pristine business JSON.

Three Required Headers

HeaderTypeDescription
X-Loxily-AppKeystringProject App Key
X-Loxily-Timestampnumber (as string)Unix seconds (or milliseconds), valid within a 5-minute window
X-Loxily-Signstring (32-char lowercase hex)MD5 signature (see below)

Signing Formula

sign = MD5(<timestamp> + <body> + <appSecret>)
  • <timestamp>: The value of the X-Loxily-Timestamp header, used as-is (string concatenation)
  • <body>: The raw HTTP request body bytes (UTF-8). For GET or empty-body requests, use ""
  • <appSecret>: The project App Secret (matched against X-Loxily-AppKey)
  • Take the lowercase 16-character hex digest (32 chars total)

No URL encoding, no parameter sorting, no canonical JSON, no intermediate hash — just three strings concatenated and MD5-ed.

Example

Given:

timestamp1713780317
body (request payload verbatim){"name":"Demo","target_languages":["en"],"strings":[{"string_id":"a","content":"hi"}]}
appSecretmy_secret_key

Concatenate:

1713780317{"name":"Demo","target_languages":["en"],"strings":[{"string_id":"a","content":"hi"}]}my_secret_key

MD5 the result (lowercase hex) → that's your X-Loxily-Sign.

Code Examples

Java

java
import java.security.MessageDigest;
import java.nio.charset.StandardCharsets;

public class LoxilySign {
    public static String sign(String timestamp, String body, String appSecret) throws Exception {
        String source = timestamp + body + appSecret;
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] digest = md.digest(source.getBytes(StandardCharsets.UTF_8));
        StringBuilder hex = new StringBuilder();
        for (byte b : digest) {
            hex.append(String.format("%02x", b));
        }
        return hex.toString();
    }
}

Python

python
import hashlib

def sign(timestamp: str, body: str, app_secret: str) -> str:
    source = f"{timestamp}{body}{app_secret}"
    return hashlib.md5(source.encode("utf-8")).hexdigest()

JavaScript / Node.js

javascript
const crypto = require('crypto');

function sign(timestamp, body, appSecret) {
  return crypto.createHash('md5')
    .update(`${timestamp}${body}${appSecret}`, 'utf8')
    .digest('hex');
}

Go

go
package main

import (
    "crypto/md5"
    "fmt"
)

func Sign(timestamp, body, appSecret string) string {
    data := timestamp + body + appSecret
    return fmt.Sprintf("%x", md5.Sum([]byte(data)))
}

Full Request Example

bash
TIMESTAMP=$(date +%s)
BODY='{"client_task_id":"uuid-1","name":"Demo","target_languages":["en"],"strings":[{"string_id":"a","content":"hi"}]}'
SIGN=$(printf '%s' "${TIMESTAMP}${BODY}my_secret_key" | md5)

curl -X POST "https://api.loxily.com/api/open/v1/tasks/create" \
  -H "Content-Type: application/json" \
  -H "X-Loxily-AppKey: 5685414646a54423c891d87194d87f3f" \
  -H "X-Loxily-Timestamp: ${TIMESTAMP}" \
  -H "X-Loxily-Sign: ${SIGN}" \
  -d "${BODY}"

Integration checklist

  1. The body used to compute the signature must be byte-identical to what is sent over the wire (same JSON string, don't pretty-print or re-serialize just before sending)
  2. Pass timestamp as a string to preserve precision
  3. UTF-8 encoding throughout — most languages' MD5 functions default to UTF-8 already