RevClamp Enterprise B2B REVENUE ASSURANCE Start Free
REVCLAMP ENGINEERING DISPATCH
← Back to Engineering Blog • VISA CE 3.0 & UTF-16 EVIDENCE LINT • 5 min read

Why Stripe's 18,000-character dispute evidence ceiling is measured in UTF-16 code units — and how naive automation overwrites AE notes

When a B2B SaaS or AI/API merchant receives a charge.dispute.created webhook for Reason Code 10.4 (fraudulent), staging Visa Compelling Evidence 3.0 (CE 3.0) historical charge pairs alongside 90-day product usage telemetry inside evidence[access_activity_log] is the highest-leverage defense available. Yet in production audits, two subtle string-handling mistakes repeatedly ruin automated dispute staging: measuring character budgets with the wrong encoding unit and clobbering existing human account-executive (AE) or support notes already drafted in the Stripe Dashboard.

In RevClamp's dispute staging engine (buildNonDestructiveDisputeDraft, governed by invariants INV-SAAS-03 and INV-SAAS-04), we enforce an explicit 18,000 UTF-16 code unit budget (MAX_ACCESS_ACTIVITY_LOG_CHARS = 18_000), wrap machine-generated CE 3.0 evidence inside deterministic delimiter markers (--- BEGIN REVCLAMP CE3 EVIDENCE --- / --- END REVCLAMP CE3 EVIDENCE ---), and hard-lock submit: false.

Non-Destructive Visa CE 3.0 Delimiter Merge and 18,000 UTF-16 Code Unit Budget Pipeline Four-stage non-destructive dispute staging pipeline: Stage 1 reads existing merchant notes, Stage 2 validates 2+ prior undisputed charges (120d-365d) with IP/device overlap, Stage 3 splices the delimited CE 3.0 block while preserving notes above and below within 18,000 UTF-16 code units, and Stage 4 stages the draft with submit: false. NON-DESTRUCTIVE VISA CE 3.0 DELIMITER MERGE & 18,000 UTF-16 BUDGET PIPELINE 1. READ EXISTING NOTES GET /v1/disputes/:id Preserve AE & support text Above & below markers 2. CE 3.0 RUBRIC CHECK >= 2 prior charges (120-365d) IP subnet or device_id match Positive customer binding 3. UTF-16 BUDGET SPLICE payload.length <= 18,000 BEGIN / END CE3 markers Zero surrogate-pair splits 4. STAGE DRAFT ONLY POST /v1/disputes/:id submit: false (hard-locked) Finance reviews before send

1. Why UTF-16 code units (.length) diverge from UTF-8 bytes (Buffer.byteLength) and Unicode code points

Stripe's Dispute Evidence API enforces field-length ceilings on text fields such as evidence[access_activity_log] and evidence[uncategorized_text]. When engineers budget 90 days of API telemetry logs in Node.js, Python, or Go, three distinct measurements get conflated:

2. Why naive webhook handlers overwrite human AE & support notes

When a high-value B2B invoice is disputed, an Account Executive or Support Lead often opens the Stripe Dashboard immediately and types context into the dispute evidence fields (for example: “Customer signed annual MSA #2025-884; ticket #9102 resolved on Oct 12”). If your background webhook worker processes charge.dispute.created or charge.dispute.updated and writes evidence: { access_activity_log: generatedTelemetry } without reading the existing dispute object first, your automation permanently deletes the human notes.

To guarantee non-destructive updates across repeated webhook deliveries, RevClamp's buildNonDestructiveDisputeDraft inspects the existing field for --- BEGIN REVCLAMP CE3 EVIDENCE --- and --- END REVCLAMP CE3 EVIDENCE ---. If the markers already exist, only the inner block between the markers is replaced in-place (preserving merchant notes both above and below the block). If no markers exist yet, the delimited block is appended below the existing merchant notes.

3. Five Stripe dispute evidence staging failure modes vs. RevClamp guardrails

Dispute Evidence Failure Mode Root Technical Cause Chargeback & API Impact RevClamp Non-Destructive Guardrail
1. UTF-16 Ceiling Overflow (>18,000 units) Unbounded 90-day usage log dump exceeds character budget Stripe returns 400 parameter_invalid_string_length or truncates CE 3.0 summary Enforces MAX_ACCESS_ACTIVITY_LOG_CHARS = 18000 UTF-16 code units with whole-line budgeting
2. Human AE/Support Note Clobbering Webhook worker blindly overwrites evidence[access_activity_log] Erases signed MSA references and support ticket notes drafted by finance Splices only between --- BEGIN REVCLAMP CE3 EVIDENCE --- and --- END REVCLAMP CE3 EVIDENCE ---
3. Incomplete Visa CE 3.0 Prior-Charge Pair Only 1 prior charge or missing IP/device overlap in 120d-365d window Fails Visa CE 3.0 liability shift rubric on Reason Code 10.4 Requires priorMatchedCount >= 2 plus positive hasIpMatch || hasDeviceMatch
4. Premature Irreversible Submission Automation calls stripe.disputes.update with submit: true Locks dispute in acquiring bank portal before human finance review Hard-locks submit: false (submitForcedFalse: true) across all API and MCP paths
5. Cross-Customer Evidence Contamination Shared corporate email alias or missing customer_id binding Attaches another tenant's IP/device logs to the disputed charge Enforces positive expectedCustomerId binding (INV-SAAS-03) before log inclusion

4. Lint your dispute payload in the browser, via CLI, or via MCP (revclamp_lint_dispute_evidence)

You can validate any candidate evidence[access_activity_log] payload against the 18,000 UTF-16 code unit ceiling, non-destructive delimiter markers, and Visa CE 3.0 prior-charge rubric without an API key using our free browser linter (/tools/stripe-dispute-evidence-char-counter), our 9th MCP tool (revclamp_lint_dispute_evidence on POST https://api.revclamp.com/api/mcp), or the revclamp-mcp CLI:

# 1. One-shot CLI lint of a non-destructive Visa CE 3.0 dispute evidence payload
npx -y github:revclamp/revclamp-mcp --lint-evidence valid_ce3_non_destructive

# 2. JSON-RPC 2.0 MCP tools/call payload (POST https://api.revclamp.com/api/mcp)
{
  "jsonrpc": "2.0",
  "id": "dispute-lint-1",
  "method": "tools/call",
  "params": {
    "name": "revclamp_lint_dispute_evidence",
    "arguments": {
      "preset": "valid_ce3_non_destructive"
    }
  }
}
Open Free Dispute Evidence UTF-16 & CE 3.0 Linter → Enable Automated CE 3.0 Staging in /dashboard Try Visa CE 3.0 Readiness Checker Test revclamp_lint_dispute_evidence in MCP Playground