SignerRequest from the Deposit SDK, creates a signed payment link, and returns a SignerResponse. This is the core security mechanism. It ensures every payment was authorized by your server.
Request format
The Deposit SDK sends aPOST request with this JSON body to your signer URL:
Example request body:
Implementation steps
Your endpoint must perform these steps in order:1. Validate the request
Return HTTP 400 with an error message for any validation failure.
Your signer should allowlist only Blink-supported destination
chainId and token combinations. See Supported Networks and Wallets for the current routing catalog.2. Verify destination ownership
Before signing, confirm that the authenticated user actually controls the destinationaddress. Without this check, a malicious caller could submit someone else’s wallet address and direct funds to an account they don’t own.
Your signer should look up the user’s wallets via your auth provider and verify the requested address is among them. Here is an example using Privy as the auth provider:
3. Generate an idempotency key
Generate a UUID v4 for this payment request. This prevents duplicate transfers if the user retries.4. Record the signature timestamp
Record the current time as the signature timestamp. Swype enforces a maximum signature age of 15 minutes server-side, so you do not need to manage expiration TTLs yourself.5. Build the payload JSON
6. Base64url-encode the payload
Convert the JSON string to a base64url-encoded string. Base64url uses- instead of +, _ instead of /, and no padding.
6. Sign the payload
Sign the encoded payload string (not the raw JSON) using ECDSA P-256 with SHA-256, then base64url-encode the signature:8. Return the response
Response format
Example response:
Complete Node.js implementation
A copy-paste-ready Express.js signer endpoint. ReplaceYOUR_MERCHANT_ID and load your private key from a secure source.
Python implementation
For merchants using Python:Signing algorithm summary
For merchants implementing the signer in any language:- Build the payload as a JSON string with fields:
amount,chainId,address,token,idempotencyKey,callbackScheme,signatureTimestamp,version. - Base64url-encode the JSON string (UTF-8 bytes to base64url, no padding).
- Sign the base64url-encoded string (not the raw JSON) using ECDSA with P-256 (prime256v1/secp256r1) and SHA-256. The input to the sign function is the ASCII bytes of the base64url string.
- Base64url-encode the raw signature bytes (DER format).
- Return the encoded payload, encoded signature, your merchant ID, and a preview object.
Security requirements
- HTTPS only. Never serve the signer over plain HTTP in production.
- Authenticate callers. The signer should only accept requests from your own frontend. Use session cookies, auth tokens, or CORS restrictions.
- Verify destination ownership. Confirm the authenticated user controls the destination
addressbefore signing. Without this, a malicious user could redirect funds to a wallet they don’t own. See step 2 above. - Server-enforced expiry. Swype enforces a maximum signature age of 15 minutes. Include
signatureTimestampin every payload so Swype can reject stale signatures. You do not need to manage expiration TTLs yourself. - Rate limit. Protect against abuse by rate-limiting signer requests per user/session.
- Log, but never log the private key. Log request metadata for debugging, but never log the private key or raw signature in production.
- CORS. Configure CORS to only allow your frontend origin(s).