Designed for the paths
that usually break
Most transaction integrations are fine on the happy path. TrustedPayer is engineered for the edge cases: duplicate requests, network timeouts, out-of-order webhooks, and dispute freezes.
Six architectural rules for reliable transactions
These behaviors ensure your engineering team launches with confidence and zero payment reconciliation anomalies.
Environment separation
Sandbox and production credentials are completely distinct. A sandbox key can create test data and simulate states only.
Idempotent requests
Send an idempotency key with every state-changing request so an automatic retry never creates a duplicate deal or charge.
Signed webhooks
Verify every event signature with your shared secret, tolerate duplicate delivery, and design for out-of-order arrival.
Stable identifiers
Your reference is yours. Our identifiers (deal_..., pty_...) are stable, opaque, and safe to persist in your database.
Least privilege
Scope API keys strictly to the environments, read/write actions, and webhook topics your service actually requires.
Documented errors
Every error carries a machine-readable code, a trace request ID, and the concrete action your system should take next.
Verifying Signed Webhooks
Never trust an unverified webhook payload. Always validate the HMAC SHA-256 signature and timestamp before mutating order records.
import crypto from "crypto";
export function verifyWebhookSignature(payload: string, signatureHeader: string, secret: string): boolean {
// Extract timestamp and signature hash
const parts = signatureHeader.split(",");
const timestamp = parts.find((p) => p.startsWith("t="))?.slice(2);
const signature = parts.find((p) => p.startsWith("v1="))?.slice(3);
if (!timestamp || !signature) return false;
// Prevent replay attacks (5 minute clock tolerance)
const now = Math.floor(Date.now() / 1000);
if (Math.abs(now - parseInt(timestamp, 10)) > 300) return false;
// Compute expected HMAC SHA-256
const signedPayload = `${timestamp}.${payload}`;
const expectedSignature = crypto
.createHmac("sha256", secret)
.update(signedPayload, "utf8")
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(signature, "hex"),
Buffer.from(expectedSignature, "hex")
);
}Errors that instruct what to do next
An error code is part of the API interface. Every failure is grouped into clear developer remediation paths rather than opaque generic 500 strings.
| Category | Representative Code | Recommended Integrator Action |
|---|---|---|
| Authentication | invalid_api_key | Check the environment and rotate or replace the key. |
| Validation | invalid_release_condition | Correct the request schema before retrying. |
| State conflict | deal_not_fundable | Read current deal state and permitted transitions; do not blindly retry. |
| Idempotency | idempotency_key_reused_with_different_payload | Use a fresh UUID key for a new logical request. |
| Permissions | action_not_allowed_for_role | Change the party role or use the authorized workflow. |
| Dependency | funding_provider_unavailable | Retry with exponential backoff and show a clear pending user state. |
| Rate limit | rate_limited | Respect the Retry-After header and apply bounded jittered backoff. |
| Internal | internal_error | Record the request_id and contact engineering support if it persists. |
Your first test transaction takes minutes
No sales call required. Launch the interactive sandbox, generate temporary keys, and simulate deals, milestones, disputes, and webhooks now.
