API reference
One endpoint turns a name into a signature image drawn by our own model. Send JSON with your API key, get the
image back in the response body, with its metadata in X-Signature-* headers.
Quickstart
- Create a key
Open your Account and create a key. It is shown once; keep it on your server, never in a browser or a mobile app.
- Authenticate
Send the key with every request as
Authorization: Bearer hs_live_…orX-API-Key. - Generate a signature
POST /v1/signaturesreturns the image directly in the response body.curl https://handsign.app/v1/signatures \ -H "Authorization: Bearer $HANDSIGN_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Jordan Hayes", "style": "flourish", "size": "L", "color": "navy", "background": "transparent", "format": "png" }' \ -o signature.png
Parameters
JSON body of POST /v1/signatures. Only name is required.
Text
name required
1 to 80 characters. Accents are normalized.
Signature
style default random
Overall gesture: natural is plain cursive, elegant is thin with long loops, flourish adds a sweeping underline, scrawl is fast with a strike-through and a paraph. Not needed with hand: the hand sets the style, and a different style returns 422.
randomnaturalelegantflourishscrawlhand default derived from the name
Which real signature lends its hand. Every hand comes from a real signature; the name is written in that hand. Left empty, the hand is derived from the name, so the same name always gets the same hand in a given style. Pass an id from GET /v1/hands to choose one, without style; the seed then only changes the take. Ink weight comes from the hand. Choosing a hand is available from the Starter plan.
Ink
color name or hex
Ink color: a name or #RRGGBB.
blackbluenavyroyalredgreengrayOutput
format default png
Image format of the response body. SVG is available from the Starter plan; PNG on the Free plan carries a light watermark.
pngsvgsize default M
Image width: S 128 px, M 256 px, L 512 px or XL 768 px. Height follows the signature. For high-density screens, request the next size up and display it at half width, or use SVG.
SMLXLbackground default transparent
Image background.
transparentwhiteseed 0 to 2147483647
The same seed and parameters always give the same signature. With a fixed hand, changing the seed gives another take in the same hand.
Response
A successful call returns 200 with the image as the body and its Content-Type set to the
requested format. Metadata comes in headers.
Response headers 10
X-Signature-Seed- Seed used, to reproduce the signature
X-Signature-Style- Style used
X-Signature-Text- Text written
X-Signature-Size- Size used
X-Signature-Width- Image width in pixels
X-Signature-Height- Image height in pixels
X-Signature-Realism- Resemblance of the returned take to real signatures, 0 to 1
X-Signature-Hand- Id of the hand used, to reuse it with the hand parameter
X-Signature-Elapsed-Ms- Generation time in milliseconds
X-Signature-Cache- Present with the value hit when the same request was served again within 24 hours
Quality
Signatures are drawn by our own image model, trained on real handwritten signatures. The hand comes from a real
signature, the name is written in that hand. The model sees that signature cut into shuffled strips, so it takes
the stroke without the letters. Each request writes the name in that hand several times and returns the take closest
to the hand, with its resemblance to real signatures in X-Signature-Realism. Paid plans write three takes, the Free plan two. The same name always gets the
same hand, so your users keep one signature across documents; a hand is never lent for the name of the person
it belongs to. Identical requests are served from a 24 hour cache.
Like any generative model it can misspell a letter or leave a small artefact. When it matters, retry with another seed, or call the batch endpoint and keep the best take. We are improving these details with every
version.
Endpoints
POST /v1/signatures/batch
Same body plus count (1 to 16). Returns JSON with base64 images. Starter plan and above.
GET /v1/styles
Every accepted value, as JSON. No key needed.
GET /v1/hands
Catalogue of hands as JSON, with id and style. Filter with ?style=. No key needed.
GET /v1/plans
Plans and quotas, as JSON. No key needed.
GET /health
Service status.
Errors
Error bodies are JSON shaped as {"detail": "…"}.
401 Unauthorized
Missing, invalid or revoked API key.
403 Forbidden
Not available on your plan (batch, hand choice, SVG), or key limit reached.
422 Invalid parameters
A parameter is missing or outside its accepted values.
429 Too many requests
Monthly quota reached (resets on the 1st at 00:00 UTC), or rate limit exceeded: 10 signatures a minute on Free, 60 on paid plans. Rate limited responses carry a Retry-After header in seconds.
503 Unavailable
Generator temporarily unavailable, retry shortly.
Privacy
Names travel only in request bodies, never in URLs, so they do not end up in access logs. Nothing you send is stored; see the Terms