عاملها، حاکمیت، حقوق و صورتحساب · فصل ۳ — Invoice، Subscription، Self-hosted و SaaS · 290
Billing Adapter & External Invoice/Payment References
Design a bounded billing adapter that keeps MAKNOW business state canonical, maps internal billing entities to external invoice/payment references, records provider lifecycle evidence without granting it product authority, deduplicates and reconciles asynchronous events, preserves ambiguous or failed states, and escalates mismatches instead of silently overwriting canonical state. میتواند برای «Billing Adapter و External Invoice/Payment References» authority، memory/failure boundary و escalation/evidence را در یک agent محدود تعریف کند.
Billing Adapter و External Invoice/Payment References — fa-IR
Lesson summary
Design a bounded billing adapter that keeps MAKNOW business state canonical, maps internal billing entities to external invoice/payment references, records provider lifecycle evidence without granting it product authority, deduplicates and reconciles asynchronous events, preserves ambiguous or failed states, and escalates mismatches instead of silently overwriting canonical state.
میتواند برای «Billing Adapter و External Invoice/Payment References» authority، memory/failure boundary و escalation/evidence را در یک agent محدود تعریف کند.
This lesson produces
میتواند برای «Billing Adapter و External Invoice/Payment References» authority، memory/failure boundary و escalation/evidence را در یک agent محدود تعریف کند.
Who it is for
Foundation
Use a field map, one worked scenario and explicit state vocabulary before independent construction.
Repair
Identify the failed evidence dimension, use the smallest mutated fixture and rerun only the affected gate.
Experienced
Compress definitions; require trade-off defense, counterexample analysis and changed-context transfer.
Prerequisites
A provider object is evidence, not your product ledger
A SaaS order is internally BILLING_PENDING. The provider creates an invoice, delivers a payment event twice, then later reports a successful payment. One earlier event was interpreted under an older mapping version. If the adapter lets invoice/payment status overwrite product state directly, duplicate delivery, provider migration, stale mappings and partial failures become invisible. This lesson builds Billing Adapter Canonical-to-Provider Reference & Reconciliation Ledger v1 so canonical business identity/state, provider references, event evidence and reconciliation remain separate and auditable.
Lesson boundary and decision route
AGN-012 owns the billing-adapter boundary: internal invoice/payment identity, external references, event dedupe, mapping version, amount/currency checks, reconciliation and review. AGN-011 owns exit/export/deletion; AGN-013 owns subscription grace/retry/dunning. Start with internal canonical IDs and the local source-of-truth rule, attach provider references, classify the event, deduplicate it, map provider status through a versioned mapping, reconcile amount/currency/reference integrity, then either apply a bounded internal transition or preserve REVIEW/HOLD.
Mental model: four records that must not collapse
Keep four things distinct: canonical business record, provider invoice reference, provider payment reference, and event/reconciliation evidence. A provider invoice can be paid without proving why MAKNOW should grant entitlement; Stripe even documents cases where an invoice becomes paid without an associated PaymentIntent success. Likewise a succeeded PaymentIntent proves a provider payment flow completed, not that every internal invoice mapping, currency, policy or entitlement condition is correct.
Ledger foundation
The contract requires 20 visible dimensions: billing_adapter_id, provider_id, internal_invoice_id, provider_invoice_id, internal_payment_id, provider_payment_ref, business_state, provider_invoice_status, provider_payment_status, event_id, idempotency_key, dedupe_state, mapping_version, amount_expected, amount_observed, currency, reconciliation_state, reconciliation_reason, manual_review_required, audit_ref. Auxiliary lab fields make the hidden shortcuts testable: provider API version, event timestamps, current mapping version, internal targets for external references, provider-neutral status semantics, canonical-state authority, duplicate/replay flags, observed currency, stale-event evidence, entitlement/refund/error references, and transfer recomputation flags. The learner never needs a live API key.
Reconciliation is stronger than status copying
Current Stripe invoice documentation exposes a provider invoice lifecycle (draft, open, paid, void, uncollectible) and says subscriptions generate invoices each billing cycle. Stripe also documents PaymentIntent lifecycle states including requires_payment_method, requires_action, processing, succeeded, and canceled. These are provider facts. MAKNOW design authority begins when the adapter asks: does this external reference still map to the intended internal record, was the event already processed, which mapping version interpreted the status, do amount and currency agree, and is the local business transition allowed? Only a versioned reconciliation rule can answer those questions.
Baseline: duplicates plus a stale mapping event
INV-INT-1001 maps to provider invoice in_9001, and PAY-INT-1001 maps to provider payment pi_7001. The observed amount and currency match. A succeeded event is delivered twice, so the second delivery must be DUPLICATE_IGNORED and must not apply a second state transition. A separate older event used mapping MAP-STRIPE-v1 while the current map is MAP-STRIPE-v2; that stale event is retained as review evidence. The bounded result is RECONCILIATION_REVIEW_REQUIRED, not an automatic product success.
Mutation: keep reconciliation_state=MATCHED but remap provider_invoice_id to another internal invoice. The evaluator must return HOLD_INVOICE_MAPPING_CONFLICT. If the observed currency changes while amount remains equal, HOLD_CURRENCY_MISMATCH is required. If an old mapping version directly activates entitlement, the result is HOLD_STALE_MAPPING_ENTITLEMENT_SHORTCUT.
Important failure modes
- Provider status becomes canonical authority — reject the shortcut.
- Duplicate replay marked NEW — event delivery is not a new business fact.
- Duplicate still applies a state transition — idempotency failed.
- Provider invoice points at the wrong internal invoice —
MATCHEDis impossible. - Provider payment points at the wrong internal payment — identity conflict.
- Amount or currency mismatch hidden by
MATCHED— hold. - Stale mapping interpreted as current — require review/recompute.
- Provider status mapping unverified — status labels cannot be trusted across providers/API versions.
- Transfer copies the first provider's status map — provider-neutral reconstruction did not happen.
- Missing audit/reconciliation reason — the business transition cannot be reconstructed.
Matched, duplicate-ignored, review-required or mismatch
A clean, current, unique event with valid reference mapping and matching amount/currency can become RECONCILIATION_MATCHED_REVIEW_READY. A genuine replay can become DUPLICATE_IGNORED_REVIEW_READY only when no second state transition occurs. Stale mapping evidence, ambiguity or unexplained status semantics remains RECONCILIATION_REVIEW_REQUIRED. Identity, amount or currency conflicts are HOLD conditions. The adapter should prefer a visible non-success state over silently overwriting canonical state.
Experienced bridge: migrations, API versions and out-of-band payment
Provider migration is where accidental coupling becomes expensive. Do not encode “paid means paid” as an unversioned universal mapping. Provider A may report invoice and payment lifecycle separately; Provider B may use SETTLED/CAPTURED or other semantics. Even within one provider, API versions can change field or status meaning. Store provider/API identity, mapping version and a provider-neutral semantic interpretation. Also remember that a paid invoice can sometimes be reached outside a successful PaymentIntent path, so the invoice record and payment-flow record must remain distinguishable.
Guided and independent practice
Run the baseline and explain why duplicate delivery is ignored while stale mapping remains review evidence. Then mutate invoice mapping, payment mapping, amount, currency and source-of-truth authority one at a time; name the first failing gate. Independently create a valid replay that is deduplicated without a state transition. Finally rebuild the transfer case for Provider B without reusing Stripe-specific status labels.
What must be reconstructable?
A reviewer must be able to answer: which internal invoice/payment is canonical, which external references were observed, which event/idempotency key produced the evidence, whether it was duplicate, which mapping version interpreted provider statuses, whether amount/currency agree, why reconciliation is MATCHED/REVIEW_REQUIRED/MISMATCH, whether manual review is required, and which audit record supports the decision. “Provider says paid” is never sufficient by itself.
Transfer: different provider, different lifecycle semantics
Provider B supplies invoice BILL-44 and payment CAP-88; its provider-native statuses are SETTLED and CAPTURED, not Stripe's paid and succeeded. Rebuild the mapping from provider-neutral semantics, verify identity/amount/currency, use a new mapping version and recompute the internal decision. Copying the baseline decision or Stripe status map must fail. With complete evidence, the changed fixture can reach TRANSFER_RECONCILIATION_REVIEW_READY.
Fact / Inference / Design and freshness
FACT: current Stripe documentation describes invoice lifecycle states and says subscriptions automatically generate invoices for each billing cycle. FACT: current Stripe documentation describes PaymentIntent lifecycle states and currently recommends Checkout Sessions for most new integrations while retaining PaymentIntent as the lower-level payment-flow object. INFERENCE: separating canonical business state from provider references improves deduplication, migration and reconciliation auditability. DESIGN: MAKNOW owns source-of-truth, mapping-version, reconciliation, entitlement-effect and escalation policy.
Provider semantics are practice-evolving. Recheck by 2027-01-01 or earlier after a material provider/API lifecycle change.
Assessment
There is no answer key in this lesson pack; answer it yourself and mark honestly. "Needs review" sends the lesson to your review queue.
AGN-012-S1 retrieval
Explain why an external invoice/payment status cannot directly become MAKNOW canonical business state.
AGN-012-S2 application
Build the baseline reconciliation ledger with duplicate delivery and stale mapping evidence.
AGN-012-S3 diagnosis
Keep reconciliation_state=MATCHED while the provider invoice maps to another internal invoice.
AGN-012-S4 transfer
Rebuild the ledger for Provider B with SETTLED/CAPTURED semantics without copying Stripe mapping.
Assessment rubric
A sufficient submission preserves the AGN-012 boundary, completes all 20 evidence dimensions, keeps internal canonical identity/state separate from provider references, deduplicates replays without a second transition, verifies mapping version and reference integrity, reconciles amount/currency with typed states, preserves stale/ambiguous evidence for review, and recomputes the second-provider transfer from provider-neutral semantics. Provider-status overwrite, hidden mismatch, stale mapping entitlement shortcut, or copied baseline/provider mapping is insufficient.
References & freshness
Case studies
Lab files
در همین پوشه python -B run_checks.py را اجرا کنید. همه رکوردها synthetic هستند؛ هیچ Provider واقعی فراخوانی نمیشود، هیچ پرداخت/Refund/Entitlement تغییر نمیکند و هیچ credential تولیدی استفاده نمیشود.