SIGIL · INTEGRATION DOCS← Back to site
[ PAYLOAD FORMAT ]

Payload format
& callback

Required fields

The d parameter encodes a JSON envelope. The request object inside it requires these fields on every type:

FieldTypeNotes
type *stringOne of connect, transfer, sc_call, sign_message, verify_message
nonce *string16–128 chars, alphanumeric or -_=+. Must be unique — Sigil tracks seen nonces for 1 hour and rejects replays
dapp.origin *stringMust be a valid HTTPS URL, e.g. https://yourapp.example
dapp.namestringDisplay name shown to the user. Strongly recommended
dapp.iconstringURL to the dApp's icon. Optional
expintegerUnix seconds. Defaults to 5 min from receipt if omitted. Max 1 hour from now — requests further out are rejected

Encoding the URI

Encode the envelope (not just the request) with URL-safe base64, no padding.

TYPESCRIPT
function b64url(str: string): string {
  return btoa(str)
    .replaceAll('+', '-')
    .replaceAll('/', '_')
    .replaceAll('=', '');
}

function buildSigilUri(
  request: SigilRequest,
  options: { callback?: string; redirect_uri?: string } = {},
): string {
  const envelope = {
    request,
    callback: options.callback ?? null,
    redirect_uri: options.redirect_uri ?? null,
  };
  return `sigil://v1/request?d=${b64url(JSON.stringify(envelope))}`;
}

Receiving the result

Two delivery modes are available. Set one or both in the envelope — they are independent and can be combined.

FieldHow it worksBest for
callbackSigil POSTs the result as JSON from the Rust layer after the user actsApps with a server — production dApps, anything that handles money or needs server-side nonce verification
redirect_uriSigil opens redirect_uri?result=<base64url JSON> in the default browser after the user actsStatic sites, SPAs, and tools with no server — read new URLSearchParams(location.search).get("result") client-side

callback — server POST

Sigil POSTs a JSON body to your callback URL from the Rust layer. If delivery fails, the result stays recoverable in request history for retry, JSON export, or clipboard copy.

Constraints

  • Must be https:// in production
  • http://localhost and http://127.0.0.1 are allowed for local dev
  • Private / loopback addresses are blocked (except localhost)

redirect_uri — client redirect

Sigil opens redirect_uri?result=<value> in the browser after the user acts. The result query parameter is the same JSON response body as the POST callback, base64url-encoded (no padding). Read it client-side — no server required.

  • Same URL constraints as callback: HTTPS in production, localhost HTTP for dev
  • The result is visible in the browser URL bar and history — do not use for high-value transactions where the signed result must stay private
  • Reject responses are also delivered via redirect so the dApp can handle both outcomes

If the user rejects

POST ‹callback› or ?result= ‹redirect_uri›
{
  "status": "rejected",
  "type": "<original request type>",
  "nonce": "<the nonce you sent>",
  "reason": "user_rejected"
}
[ ALWAYS VERIFY THE NONCE ]

Match the nonce in the callback body against the one you sent. Different nonce = different request. Don't trust the body until that matches.

Trust levels

Requests can be unsigned (legacy_unverified — dApp name/origin are self-reported) or carry an ES256 proof. If a proof is present but the signature is invalid, or the issuer's origin doesn't match, Sigil blocks approval entirely. See the @sigil-oss/connect SDK page for how to sign requests.

LevelMeaningBlocks?
legacy_unverifiedNo proof — dApp name/origin self-reportedNo
signed_untrustedValid ES256 signature, issuer not in user's registryNo
verified_registrySignature valid, issuer in registry, origin matchesNo
signature_invalidProof present but signature verification failedYes
registry_revokedIssuer in registry but marked revokedYes
registry_origin_mismatchIssuer registered but dapp.origin doesn't match trusted originsYes