Fintech

How to Write a Cancellation Policy That an Agent Can Apply

Antonio Evans10 min read

A side-by-side workbench: on the left, a policy document with numbered clauses, some highlighted in yellow (eligibility), some in green (notice window).
Key points

Key points

  1. 1Write the policy as a decision table: each row names one contract field, one trigger value, one deadline event, and one fallback action.
  2. 2Every deadline must state the event it counts from (signature, billing date, delivery) and whether it counts calendar days or business days.
  3. 3State document precedence explicitly, so the agent knows whether the negotiation contract or the standard terms win when they disagree.
  4. 4Give the agent a fallback for every missing field and an escalation path for anything the table cannot resolve.

Why prose terms fail an agent

A cancellation policy written as paragraphs is optimized for a human lawyer reading top to bottom, with context, cross references and the ability to weigh ambiguity. An agent does the opposite: it retrieves fragments, matches them to a customer record, and must produce one answer with a timestamp and a rationale. Prose hides three things the agent needs and cannot reliably infer: which facts the clause depends on, which document wins when two clauses conflict, and what to do when a fact is absent.

This is the same problem legal and public sector engineers have studied under the name "law as code," in which statutes and rules are turned into computational logic so a system can apply them consistently and explain the result; the authors of one such pipeline describe the goal as explainable decision support rather than text retrieval from the Law as Code study. The lesson for policy authors is straightforward: the hard work belongs upstream, in the drafting, not in the prompt.

The same pattern shows up in contract operations, where teams extract clauses, dates and obligations into structured fields because unstructured review does not scale and produces errors when formats vary per Icertis. Cancellation terms are a narrow case of contract extraction with one important difference: you control the wording, so you can write for extraction instead of reverse engineering it.

A worked example makes the cost visible. Suppose the standard terms say "you may cancel within 14 days of purchase" and a negotiated enterprise contract says "cancellation permitted within 30 days of the effective date." An agent asked whether a customer who signed on the 3rd and asked on the 20th can cancel has two overlapping rules, two different start events, and no instruction on precedence. It will pick one, and about half the time it will pick wrong. Rewriting the policy as rows removes the coin flip.

Step 1: Split the prose into atomic clauses

Take the customer-facing terms and cut them into sentences that each express exactly one permission, prohibition or obligation. Keep the original sentence somewhere in the row so a human reviewer can audit the mapping. A clause that contains "and" or "unless" is usually two rows or a row plus a condition.

For each clause, record four things:

  • The condition it tests, expressed as field, operator, value.
  • The deadline it imposes, expressed as a number of days plus the event the count starts from.
  • The outcome if the condition passes.
  • The outcome if it fails.

Here is what a converted row looks like in a machine-readable form a developer or agent can actually consume:

clause_id: CAN-014
source_text: "You may cancel within 14 days of purchase for a full refund."
tests:
  field: contract.signed_at
  operator: present
deadline:
  days: 14
  counted_from: contract.signed_at
  day_type: calendar
outcome_pass: cancel_full_refund
outcome_fail: offer_standard_termination
fallback_if_missing: escalate_billing_ops

The YAML is not mandatory; a spreadsheet with the same columns works, and many teams start there. What matters is that every clause resolves to one unambiguous row, because a row can be tested, logged and reviewed in a way that a paragraph cannot.

Watch for the traps that survive the split. A deadline counted from "purchase" is not the same as one counted from "signature" when a customer signs on the 28th and is billed on the 1st. A deadline that says "14 days" without saying calendar or business days is a defect, because the two produce different answers around a weekend. Statutory cooling-off schemes are explicit about this: federal and state guidance counts in business days, excludes Sundays and federal holidays, and treats the cancellation as effective when the postmark is dated, not when the seller reads it per the FTC consumer guidance and the Ohio Attorney General.

Step 2: Tag each clause with the fields and windows it depends on

A row is only applicable if the agent can see the facts it tests. Inventory the contract and billing fields available to the agent before you write the rows, then tag every row with the fields it needs. If a field does not exist, that is a data project, not a prompt problem.

The field inventory should include, at minimum: contract signature date, contract effective date, billing date of first charge, delivery or activation date, plan or product identifier, customer segment (consumer or business), jurisdiction, whether a trial applies, whether the contract is a negotiated variant, and the current date in the customer's time zone. Time zone is not a detail. "Midnight of the third business day" is a specific instant, and an agent comparing a naive UTC timestamp to a local deadline will misjudge the boundary case as the Florida Attorney General's summary of home solicitation sales shows.

The tagging discipline is simple: a row may not reference a field that is not in the inventory, and a field in the inventory should be used by at least one row or explained as unused. That second rule catches fields the agent collects and nobody applies, which is where silent errors come from.

Statutory windows deserve their own tag, separate from contractual ones, because they usually cannot be waived or shortened by contract language. Federal cooling-off rules apply to certain sales made away from the seller's normal place of business, with dollar thresholds and a long list of exclusions such as sales made entirely online or by phone per the Cornell Legal Information Institute. State schemes vary widely and add their own categories and lengths; Washington, for example, lists different windows for health clubs, hearing aids, credit repair and business opportunities per the Washington State Attorney General, while Ohio runs from 3 days for door-to-door sales to 30 days for hearing aids per the Ohio Attorney General. If your product touches any of these categories, the statutory row sits above the contractual row and the agent must test it first.

Step 3: Write the decision table

The table is the deliverable. Every column must be answerable from the field inventory or from a fixed rule, and no cell may contain the phrase "as appropriate."

RowTests (field = value)Start eventWindowOutcome if passOutcome if failFallback if field missing
S1statutory_scheme = true, jurisdiction in listStatutory start event (sale, delivery, signing)Statutory length, business daysFull statutory cancellationContinue to contractual rowsEscalate to compliance
C1contract.variant = negotiatedContract effective dateNegotiated windowCancel per negotiationContinueTreat as standard terms, flag
C2contract.type = standardSignature dateStandard windowFull refundOffer termination on noticeUse billing date, flag
C3delivery.pending = trueDelivery datePre-delivery windowCancel at no chargePro-rate from deliveryEscalate to billing
C4all above failNot applicableNot applicableStandard termination with notice periodRefuse and explainEscalate to account owner

Read the table as a sequence of tests, not a menu. Row S1 runs first because statutory rights usually override contract text; C1 next because a negotiated contract beats standard terms; C2 and C3 then cover the ordinary cases; C4 is the catch-all that keeps the agent from inventing a policy when nothing matches.

The insight most first drafts miss is that precedence is a property of your contract architecture, not of the law in general. If your order form incorporates the standard terms by reference and the negotiated master agreement says it prevails over any conflicting terms, then C1 above is correct. If your documents are silent on which wins, the agent has no defensible rule and will produce inconsistent answers across customers.

The second insight is that windows should be expressed as data, not as sentences the model re-reads. A row that says "14 calendar days from signature" can be evaluated by deterministic code, with the model only handling the conversation and the explanation. That split keeps arithmetic out of the model, where it is least reliable, and keeps judgment in the model, where it is most useful. Human-in-the-loop design guidance makes the same point in reverse: require a human approval gate when the next action is irreversible, costly or regulated, and pass the approver an evidence pack that makes the decision obvious in seconds per StackAI. A row from your table, with the field values filled in, is exactly that evidence pack.

Step 4: Define precedence and conflict resolution

Conflicts come in three flavors, and each needs a stated rule.

Vertical conflict, where a statute and a contract disagree: the statute wins on rights it grants to consumers, and the contract wins only where it is more generous. Write this as a rule with a citation to the specific scheme, not a general statement about "applicable law."

Horizontal conflict, where two documents in your own stack disagree: name the document that prevails. The usual ordering is negotiated agreement, then order form, then standard terms, then help center article. Remove the help center article from the agent's knowledge base if it contradicts the others, because retrieval will find it and the agent will cite it.

Temporal conflict, where the policy changed mid-tenancy: apply the version in force at signature unless the newer version is more favorable to the customer. Record a policy version identifier on every row and store it with the customer's contract, so the agent knows which vintage to apply.

One practical test: have a product manager and a support lead independently resolve a set of ten conflict scenarios using only the table. If they disagree on any scenario, the precedence rules are underspecified, and the agent will disagree with itself in production. Payment infrastructure choices create similar conflicts when one party owns tax and dispute obligations and another only moves money, which is precisely why the distinction between a merchant of record and a payment facilitator is written into the contract rather than left to a support article as Stripe explains and as Paddle frames it. If your billing stack involves a merchant of record, add a row for "who processes the refund" with a named owner.

Refund mechanics belong in the table too, not in a separate runbook the agent never reads. Florida's guidance, for instance, requires a refund within 20 days of receiving notice for future-services contracts and within 10 days for home solicitation sales per the Florida Attorney General, while Washington requires a health studio refund within 30 days per the Washington State Attorney General. If any of those deadlines bind you, they are rows with a clock, and the agent must open a refund task with a due date rather than telling the customer "shortly."

Step 5: Write fallbacks and escalation for every row

Fallbacks are where most policies quietly fail. The agent hits a null field, and the model, wanting to be helpful, fills the gap with a plausible assumption. Prevent that by writing the fallback into the row.

Use a small controlled vocabulary so fallbacks are auditable. Four values cover most cases:

  • ask_customer: request the missing fact in one specific question, then re-evaluate.
  • use_proxy: substitute a documented proxy field and flag the result for review.
  • escalate_role: route to a named role with the evidence pack attached.
  • decline_for_now: hold the request, tell the customer what is being checked and by when.

Anything routed to escalate_role needs a target and a service level. "Escalate to legal" is not a fallback; "route to billing operations queue with a 1 business day response standard, and send the customer a holding message with the case number" is. Approval workflow design treats this as the difference between supervised autonomy and an unowned queue per StackAI.

Two more authoring rules earn their keep. First, never let the agent negotiate an exception it is not authorized to grant: list the exceptions it may offer and the ones it must route. Second, cap the loop. If the agent has asked the customer twice for a missing field and still does not have it, escalate rather than asking a third time.

Data portability clauses are a useful stress test for your fallback design, because exit obligations are frequently vague about format and timing, and vague wording is exactly what breaks an automated check per the SaaS exit clause analysis. If your cancellation policy covers a data export before deletion, write a row that names the export format, the delivery channel and the deletion date, and give the agent a fallback for customers whose export fails. Vendor lock-in questions about who holds the credential mapping and whether it survives a switch show the same pattern: a clause that does not name the mechanism cannot be executed by anyone, human or machine per Payments Therapist.

Step 6: Test, version and monitor the policy

Treat the table like code. Keep it in version control, review changes with the same sign-off as the customer-facing terms, and ship a diff with every release so support can see what moved.

Test with cases, not vibes. Build a fixture set of customer records that covers the boundaries: cancellation on the last day of the window, the first day after, a weekend or holiday boundary, a missing signature date, a negotiated contract with a shorter window than the standard one, and a customer in a jurisdiction whose statutory window is longer than the contract allows. For each fixture, record the expected row and outcome before you run the agent, then compare. Boundary tests find more defects than volume tests, because the errors live at the edges.

Monitor in production with three metrics: the share of requests that resolve to C4 (the catch-all), the share of requests that needed an escalation, and the rate at which agents and humans disagree on the same case. A rising catch-all share usually means the field inventory is drifting, and a rising disagreement rate usually means the table has grown a gap.

Keep the customer-facing prose in sync. The table is the source of truth for the agent, and the legal text is the source of truth for customers; a mismatch between them is a compliance problem, not just a support annoyance. Generate the customer-facing summary from the table where you can, and have legal review both in the same change.

If you are running this across several document types or several channels and want one place to route the extraction and the conversation without wiring a provider per model, Quanta Inference offers text, image, video, audio and embedding models through one OpenAI-compatible API key, prepaid and priced in US dollars. For teams that want the policy built and reviewed by specialists rather than drafted in-house, the experts at Quanta read your contracts and deliver the finished rule set, and a free discovery call is available if you would rather scope it with someone first.

FAQ

FAQ

How many rows should a cancellation policy have?

Most SaaS and services policies land between eight and twenty rows once statutory schemes, standard terms, negotiated variants, trial and pre-delivery cases are separated. If you are past roughly thirty rows, you probably have two policies that should be split by product or region rather than one table with many conditions.

Should the agent read the legal text at all?

Give it the table as the authority and the cited sentence as the explanation. Retrieval over raw prose is useful for answering "why" questions in the customer's words, but it should never be the basis for the decision, because retrieval surfaces conflicting passages without any notion of precedence.

What do I do when a field is simply not stored anywhere?

Either create the field or route the case to a human, and say which in the row. The worst option is letting the model infer the fact from the conversation, because a customer's recollection of their signup date is not the contract record and the difference decides boundary cases.

How do statutory cooling-off windows interact with my own terms?

Statutory rights generally sit above contract language and cannot be shortened by it, so they get their own rows and run first. Federal and state schemes differ in scope, length and how days are counted, so cite the specific scheme in the row and have legal confirm the list of jurisdictions you support.

How do I know the agent applies the policy correctly?

Run a fixed fixture set at every policy change, including last-day, first-day-after and holiday boundaries, and compare the agent's chosen row to the expected one. Then watch the production share of catch-all resolutions and human-versus-agent disagreements, which surface gaps faster than manual spot checks.

Sources

Sources

  1. Transforming legal texts into computational logic
  2. How to Automate Contract Data Extraction Without Losing ...
  3. Buyer's Remorse: The FTC's Cooling-Off Rule May Help
  4. Cancellation Rights of Consumers - Ohio Attorney General
  5. How to Protect Yourself: The Cooling-Off Rule
  6. cooling-off rule | Wex | US Law | LII / Legal Information Institute
  7. Cancellation Rights | Washington State
  8. Human-in-the-Loop AI Agents: How to Design Approval ...
  9. Merchant of Record vs Payment Facilitator: A Guide For Business
  10. Payfac vs Merchant of Record - Paddle
  11. SaaS Vendor Lock-In: Exit Clauses and Data Portability ...
  12. Everybody Loves Tokenization Until They Try to Leave ...
About the author

About the author

Antonio Evans
Antonio Evans

Antonio Evans is the founder of Quanta Intelligence and a fractional CTO who builds HIPAA-ready AI systems for health and life-science companies. Before that he was technical co-founder of FriendsEAT for twenty years, CEO of Socialdraft, and a data engineer at IBM. Antonio lives with his dog Santino in Lisbon, Portugal.

All articles