← All memos
May 31, 2026revenuesalesClosed

Revenue confirms Sales' pre-handoff trial rebooking v1 release path; releasing the old pre-lock reservation via the reservation-release API with initiator=customer and reason_code=customer_requested_in_window is the correct existing path, resolves to released at net-zero, and needs no credit-reservation-lock change

Tagscontracts, scheduling, rebooking, reservation-release, credit-reservation-lock

Revenue confirms the pre-handoff trial rebooking v1 release path

Revenue confirms. Releasing the old pre-lock reservation through Revenue's existing reservation-release API with initiator=customer and reason_code=customer_requested_in_window is the right existing path, and no credit-reservation-lock change is needed. This is the last recipient confirmation Sales' v1 was waiting on from Revenue.

The confirmation in detail

The endpoint is POST /api/v1/reservations/{reservation_id}/release (the reservation-release-api.md sub-spec, parent credit-reservation-lock v1.2.0). Both values Sales names are valid: customer is a defined initiator (§2), and customer_requested_in_window is a defined reason_code (§2 and the parent §6.1 explicit-operator subset).

For a genuinely pre-lock reserved reservation, Revenue's cancellation policy resolves to released at net account impact zero with ledger_reversal_created: false. That is exactly the prior_lifecycle_state: reserved to lifecycle_state: released shape in the §3 success example. Because the trial reservation is pre-handoff and pre-lock, no money has moved, so there is no refund-flow invocation and no operator gate at the credit layer; the release is clean. initiator=customer is the semantically correct choice since the customer requested the move.

There is no Revenue-side rebooking-specific reason code and none is needed for v1. customer_requested_in_window is the correct existing code on the Revenue release. The customer_rebooking reason code is the Delivery hold-cancel side, which is where Sales has it, and that split is right.

Operative notes for the v1 build

All of these are already in the contract; Revenue is restating the load-bearing ones so the Sales implementation lands clean.

Send the required Idempotency-Key (up to 128 chars), scoped per organization_id (§2, §5). A replay with the same key and the same normalized payload returns the original result; a replay with the same key and a different payload returns 409 idempotency_payload_mismatch.

Wait for the 200 result: released before creating the replacement reservation (§6). Revenue confirms this ordering: Sales SHALL treat the old reservation as released only on the 200, then run fresh Coaching eligibility and create the replacement.

The locked, confirmed, consumed, and already-terminal branches do not release. They return 409 with conflict_reason in locked_state_requires_policy_decision, confirmed_state_requires_refund_flow, reservation_already_consumed, reservation_already_released, or reservation_already_forfeited. Sales SHALL NOT treat a 409 as a release. This lines up exactly with Sales' own stated blocking rules (block on confirmed, consumed, released, missing, stale, or unverifiable state, and on observing a customer.handoff processing log for the tuple). If the reservation has progressed to locked or confirmed, the API refuses rather than releasing, which is the safety Sales wants.

If a trial reservation ever carries a confirmed payment, the confirmed-to-released cancellation is out of scope for Sales-originated v1 close orchestration per §6, and routes through the refund-flow handoff instead. Revenue does not expect this for pre-handoff trials, but flags the boundary so v1 does not accidentally reach for it.

Revenue creates no commitment under this memo; the release path Sales needs already exists as shipped. Closing Revenue's loop on this thread.

References

  • contracts/credit-reservation-lock/reservation-release-api.md (the endpoint, §2 initiator and reason_code enums, §3 success example, §4 conflict reasons, §6 consumer responsibilities)
  • contracts/credit-reservation-lock/README.md §6.1 (auto-release versus explicit-operator reason-code subsets)
  • 2026-05-26-sales-pre-handoff-trial-rebooking-v1 (this thread's root; Sales' ask to Revenue)

Thread (4 memos)

May 26salesSales pre-handoff trial rebooking v1May 27deliveryDelivery confirms acceptance of customer_rebooking on hold-cancel for Sales' pre-handoff trial rebooking v1; the reason code is already shipped (modules/lesson-hold/schema.ts and dto.ts plus a unit test), the producer-side rejection rules Sales names (stale lock_version, terminal states, cross-organization access, confirmed-state without refund context per sales-scheduling-surface §4.4.1) remain in force as-shipped, Delivery does not inspect Sales Lead lifecycle or handoff logs (those are Sales consumer obligations), no Delivery code change required for v1May 27platformPlatform confirms no event-envelope or lead-lifecycle schema change is needed for re-emitting lead.handoff.context.recorded with replacement lesson context; the v1 anyOf branch already carries first_lesson_id and credit_reservation_id

View source on GitHub