Docs Signing
Signed URLs
Paid features need a signature on the address. You make it on your server with a secret only you hold.
B Klug, updated October 27, 2026
Private designs, AI drawn marks and the kit API (/v2/kit.zip) are paid features. A request for one of them has to carry api_key and sig. The signature proves that the address was made by the owner of the key, so nobody can copy your key from a web page and spend your allowance. The free features never need a signature.
Your signing secret
Every paid account has a signing secret on its account page, in the box called Signing secret. It is a long random string. Keep it on your server, in an environment variable or a secrets store, and never in a web page, an app or a public repository. The site itself never puts it in your browser: the Logo Maker and the account page ask the server to sign for you.
You can change the secret from the same box. The page asks twice, because a new secret breaks every address you have signed so far: they stop drawing until you sign them again. Private designs themselves are not affected. Your private design space does not depend on the secret, so a design you made stays yours after a change.
How a signature is made
- Take every parameter of the address,
api_keyincluded, and leave outsig. - Sort the parameters by name, and by value when a name repeats.
- Write them as
name=valuepairs joined with&, percent-encoded the standard way: every character except the letters A to Z and a to z, the digits and- . _ ~becomes%and two capital hex digits, and a space is%20. The encoding a browser's form uses is accepted too (a space is+and*stays as it is), so you are not stuck on whichever your language's library gives. - Compute HMAC-SHA256 of that string with your signing secret, write it as lowercase hex, and keep the first 24 characters.
- Add the result to the address as
sig.
The order of parameters in the final address does not matter. The service sorts them again before it checks. A change to any parameter, or a missing one, makes the signature fail and the request gets a 401.
Code
Node
import { createHmac } from 'node:crypto';
export function sign(secret, params) {
const pairs = Object.entries(params).sort(([a, x], [b, y]) => (a < b ? -1 : a > b ? 1 : x < y ? -1 : x > y ? 1 : 0));
const canonical = new URLSearchParams(pairs).toString(); // the browser's form encoding, which is accepted
const sig = createHmac('sha256', secret).update(canonical).digest('hex').slice(0, 24);
return 'https://api.logolava.com/v2/logo.png?' + canonical + '&sig=' + sig;
}
sign(process.env.LOGOLAVA_SECRET, { text: 'Juniper & Vale', seed: '1140956701', private: '1', api_key: process.env.LOGOLAVA_KEY });PHP
function ll_sign(string $secret, array $params): string {
ksort($params, SORT_STRING);
$canonical = http_build_query($params, '', '&', PHP_QUERY_RFC3986);
$sig = substr(hash_hmac('sha256', $canonical, $secret), 0, 24);
return 'https://api.logolava.com/v2/logo.png?' . $canonical . '&sig=' . $sig;
}This signs a list with each name once. A name that repeats needs the pairs sorted by value too, so build the list yourself in that case.
Python
import hashlib, hmac
from urllib.parse import quote, urlencode
def sign(secret, params):
pairs = sorted(params.items())
canonical = urlencode(pairs, quote_via=quote)
sig = hmac.new(secret.encode(), canonical.encode(), hashlib.sha256).hexdigest()[:24]
return 'https://api.logolava.com/v2/logo.png?' + canonical + '&sig=' + sigcurl and openssl
Q='api_key=YOUR_KEY&private=1&seed=1140956701&text=Juniper%20%26%20Vale'
SIG=$(printf '%s' "$Q" | openssl dgst -sha256 -hmac "$LOGOLAVA_SECRET" -hex | awk '{print substr($NF,1,24)}')
curl -o logo.png "https://api.logolava.com/v2/logo.png?$Q&sig=$SIG"Here you write the canonical form yourself: parameters in name order, already encoded.
If a request fails
- 401 with a bad signature. The most common cause is a parameter added after signing, or the secret from another account. Sign the final list of parameters, and sign again after any change.
- 402 with the plan image. The signature is fine, but the plan does not include the feature. A private design needs Pro or Business, and the kit API needs Business.
The API keys page covers the key itself. Private designs are drawn from your account's own seed space: the same name and seed give you your design and give everyone else a different one.
Next: Private designs