Developer Documentation

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.

Core Principles

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.

Webhook Security

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")
  );
}
Error Taxonomy

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.

CategoryRepresentative CodeRecommended Integrator Action
Authenticationinvalid_api_keyCheck the environment and rotate or replace the key.
Validationinvalid_release_conditionCorrect the request schema before retrying.
State conflictdeal_not_fundableRead current deal state and permitted transitions; do not blindly retry.
Idempotencyidempotency_key_reused_with_different_payloadUse a fresh UUID key for a new logical request.
Permissionsaction_not_allowed_for_roleChange the party role or use the authorized workflow.
Dependencyfunding_provider_unavailableRetry with exponential backoff and show a clear pending user state.
Rate limitrate_limitedRespect the Retry-After header and apply bounded jittered backoff.
Internalinternal_errorRecord 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.