Transfers above a threshold
Bind the beneficiary account, the amount, and the currency. A signature for 25,000 to one IBAN cannot be replayed against a different account or a different figure.
Payments and treasury operations
Payment fraud rarely defeats an approval workflow. It arrives through one — an authorized person approving a payment whose details changed after they looked, or a compromised service spending an entitlement granted months earlier for something else entirely. Both are failures of binding: the approval was attached to a person's session or role, not to the beneficiary and the figure that actually left the account.
Call INTYGA immediately before submitting the payment, with the values you are about to submit. The approver sees those exact values on their own device and signs them.
If anything about the payment changes between the request and the submission, the receipt no longer verifies and the code refuses to send it. That check runs in your process, against parameters you derived, with no call back to us.
The approval is also single-use and bound to the executing system. Redeeming it a second time fails, and an approval granted for the payments service cannot be spent by the refunds service — the target is part of what was signed.
const action = {
target: PAYMENTS_TARGET, // this service — so the approval can't be replayed against another
actionType: "wire_transfer",
params: { beneficiaryIban, amountCents: 2500000, currency: "EUR" }
};
const approval = await intyga.requireApproval("Wire — 25,000.00 EUR", action);
if (approval.status !== "APPROVED") throw new Error("not approved");
// nonce and approvers come from YOUR side — a receipt cannot vouch for its own signer.
const anchor = parseTrustAnchorFile(readFileSync(process.env.INTYGA_APPROVERS_FILE!, "utf8"));
const TRUSTED_APPROVERS = trustAnchorApprovers(anchor); // quorum counts PEOPLE, not keys
const check = verifyApprovalReceipt(approval.receipt!, {
...action, nonce: approval.nonce!, approvers: TRUSTED_APPROVERS,
}, {
expectedOrigin: anchor.webauthn?.origin,
expectedRpId: anchor.webauthn?.rpId,
});
if (!check.ok) throw new Error("receipt mismatch: " + check.reason);
await submitPayment(beneficiaryIban, 2500000);Not a summary the requesting service composed, and not an email that could have been spoofed. The notification carries an opaque reference and a kind — no beneficiary, no amount, no account details, no PII of any kind. The approver's browser fetches the authoritative payment from the gateway over TLS and displays every parameter key by key.
Those canonical bytes are what the passkey signs, and the same bytes are what your payment service recomputes before submitting. There is no gap between what was displayed, what was signed, and what executes — which is precisely the gap business-email-compromise fraud lives in.
It also means a leaked notification, a forwarded message, or a compromised chat channel discloses nothing about the payment itself.
{
"target": "payments-prod",
"actionType": "wire_transfer",
"display": "Wire — 25,000.00 EUR",
"params": {
"beneficiaryIban": "DE89 3704 0044 0532 0130 00",
"beneficiaryName": "Acme GmbH",
"amountCents": 2500000,
"currency": "EUR",
"invoiceRef": "INV-2026-0431"
},
"nonce": "single-use challenge",
"expiresAt": "short approval window"
}Bind the beneficiary account, the amount, and the currency. A signature for 25,000 to one IBAN cannot be replayed against a different account or a different figure.
The bank-details update is the step the fraud actually targets, and it is usually gated more weakly than the payment it enables.
A support agent or an automated workflow can request; a person approves. The record keeps the two apart rather than inferring it from a role.
Bind the file digest and the total. A batch that gained a line after review no longer matches what was signed.
Sweeps, FX conversions and inter-company transfers are high-value, routine, and rarely re-checked at execution time.
Raising a spending ceiling or adding a signatory should be at least as hard to do as spending against it. Gate the control plane, not only the payment.
Quorum, four-eyes and hardware-key requirements are server-side approval rules, frozen onto the challenge at the moment it is created. A caller can request an authorization; it cannot ask for a lower threshold, and a compromised service cannot lower its own.
The classic invoice-redirection attack changes the beneficiary between review and submission. Here that is structurally impossible to hide: the signature covers the IBAN and the amount, so a changed beneficiary means the receipt no longer verifies and your own code refuses to send. Broken alongside it: replaying a session-scoped entitlement, spending an old approval on a new payment, and a compromised service quietly approving on its own behalf.
If a fraudulent invoice reaches your finance team and someone approves it having read it carefully, they have signed the fraud. The gate proves a named person decided over exact details; it does not know the vendor is fake. Keep supplier verification and callback procedures — this composes with them, and makes the record of who decided unambiguous afterwards.
Each approval produces a signed receipt over the canonical payload — the beneficiary, the amount, the currency, the nonce, the time.
An auditor recomputes the payload from your records and checks the signature against the approver's public key using @intyga/verify. No INTYGA secret, no API call.
Approvals, denials and rule changes append to a hash-linked ledger with periodic checkpoints, so committed entries cannot be quietly rewritten later.
Stated precisely: the log proves that committed entries were not altered. It cannot prove that an event was never withheld from commitment. Evidence retention on the Business tier is 3-year, with auditor export.
If you operate under DORA, the same receipts are the evidence its change management and authentication requirements ask for — a per-action, parameter-bound record of who authorized what, verifiable outside the platform that produced it. Nobody can sell you conformity with a regulation; what this gives you is the artefact an assessor asks to see. See the DORA mapping, or read “Signing the Letter, Not the Envelope” for the underlying argument.
Anywhere a machine performs an irreversible action on behalf of a person, the same architecture applies: AI agents issuing payouts or refunds, privileged operations on the systems of record, deployments that change how payments are computed, and releases of the software that moves the money.
One transfer type, one approval rule. When the flow works, widen it. Approvals are not metered, so the Developer tier gates as many transfers as you make, at no cost — what the paid tiers add is seats, a longer evidence-retention window, and quorum rules.
See the DORA mapping →