Class: PaymentService
Defined in: server/checkout/payment-service.ts:255
The payment ledger's service surface (proposal §Tender creation is two-phase, §Services). Money-moving ops never hold a database transaction across provider I/O:
- TX1 (short): lock the order row → split-tender guard → insert the
paymentsrow (pending, intendedamountCents,idempotencyKey,requestHash) → commit. The tender row is durable BEFORE any provider call: a webhook can never arrive before the row exists, and a crash after the provider call leaves a locatable row, not an orphan. - Provider call with no transaction open. This discipline ("never hold
a row lock across provider I/O") is structural, not asserted: the call
simply sits between the two
this.transaction(...)blocks. A caller that wraps these ops in its own ambient transaction silently defeats it — don't. The one documented exception isrecordManualPayment, whose ManualProvidercaptureruns INSIDE TX2 so the synchronousbalanceLedger.debitcommits/rolls back atomically with the txn row. - TX2 (short): lock order → payment (the global lock order, proposal
principle 7) → ingest the op result's
CanonicalTxns through therecord()dedupe upsert → persist the clientAction/provider-id facts → recompute tender + order → write buckets → append domain events → commit.
A crash/timeout between TX1 and TX2 leaves the tender pending with no
provider id — reconciled by the consumer's stale-tender sweep
(findStaleTenders → reconcilePayment/cancelTender, stage 5.5) or by
the provider's webhook for the object (locatable via the
merchant-reference echo = payments.id).
Extends
BaseCheckoutService
Constructors
Constructor
new PaymentService(deps: CheckoutFeatureDeps): PaymentService;Defined in: server/checkout/base-checkout-service.ts:43
Parameters
| Parameter | Type |
|---|---|
deps | CheckoutFeatureDeps |
Returns
PaymentService
Inherited from
BaseCheckoutService.constructorProperties
deps
protected readonly deps: CheckoutFeatureDeps;Defined in: server/checkout/base-checkout-service.ts:43
Inherited from
BaseCheckoutService.depsAccessors
actorId
Get Signature
get protected actorId(): string | null;Defined in: server/checkout/base-checkout-service.ts:45
Returns
string | null
Inherited from
BaseCheckoutService.actorIdMethods
authorize()
authorize(orderId: string, input: AuthorizeTenderInput): Promise<TenderOpResult>;Defined in: server/checkout/payment-service.ts:275
Two-phase tender creation against a registered provider (proposal
§Tender creation is two-phase). The capability gate
(supportsAuthorization) runs BEFORE TX1; the adapter receives
payments.id as paymentId — the merchant reference it MUST echo
(Correlation rule).
Idempotent replay: a key hit with an equal requestHash returns the
existing tender with NO provider call; a differing hash throws
IdempotencyConflictError (proposal §Idempotency & errors).
Parameters
| Parameter | Type |
|---|---|
orderId | string |
input | AuthorizeTenderInput |
Returns
Promise<TenderOpResult>
cancelTender()
cancelTender(paymentId: string, opts?: CancelTenderOptions): Promise<BigIntsAsNumbers<{
amountCents: bigint;
applicationFeeCents: bigint | null;
authorizedCents: bigint;
canceledAt: Date | null;
capturedCents: bigint;
clientActionRequired: boolean;
clientActionRequiredAt: Date | null;
createdAt: Date;
createdBy: string | null;
currencyCode: string;
disputedCents: bigint;
disputeFeeCents: bigint | null;
expiresAt: Date | null;
feeBorneBy: FeeBorneBy | null;
id: string;
idempotencyKey: string | null;
orderId: string;
organizationId: string;
payerServiceFeeCents: bigint | null;
payerServiceFeeRefundedCents: bigint | null;
processingFeeCents: bigint | null;
provider: string;
providerAccountRef: string | null;
providerPaymentId: string | null;
refundedCents: bigint;
requestHash: string | null;
status: PaymentStatus;
tenderMethod: string;
updatedAt: Date;
updatedBy: string | null;
}>>;Defined in: server/checkout/payment-service.ts:808
Cancel a tender (proposal §Tender cancellation & abandonment): "lock
order → payment; assert no success capture txns (else
TenderNotCancelableError); if an uncaptured authorization exists, call
provider.void and ingest the void txn; set canceledAt; recompute."
A canceled tender contributes 0 to in-flight, so an abandoned
hosted-checkout/SCA tender no longer wedges the order — the split-tender
guard reopens. Reached from three abandonment sources: adapter expiry
events (ParsedWebhook.cancelsTender — handled in handleWebhook), the
consumer's stale-tender sweep (findStaleTenders → here), and direct
operator calls.
Two-phase like capture/void — never hold a lock across provider I/O:
- Phase A (one transaction): lock order → payment, re-read the
ledger. A success
capturetxn →TenderNotCancelableError(money moved). AlreadycanceledAt→ return the row AS-IS (idempotent — sweep passes and redelivered expiry events retry harmlessly; the first detection timestamp survives). Then decide: an uncaptured authorization exists (success auth Σ − void Σ > 0, the recompute fold semantics) AND a provider object exists → a provider void is needed; otherwise setcanceledAt(markTenderCanceled) + run the standard ingestion with zero txns (the recompute drops in-flight and reopens the guard) and return INSIDE this transaction. - Provider void (no transaction open) when needed. Phase A commits
WITHOUT setting
canceledAtfirst: a crash before the void must leave the tender live so the sweep retries — canceling first would strand an un-voided auth behind a "terminal" tender. TheidempotencyKeydefaults to the derivedcancel:{paymentId}(seeCancelTenderOptions). - Phase B (one transaction): re-lock, re-read,
markTenderCanceled, ingest the void op result's txns through the standard dedupe upsert.
Caution (proposal): canceling a tender whose hosted session may
still be live re-opens the guard; where the provider supports it the
ADAPTER must expire the provider-side session in its void (Stripe:
expire the Checkout Session) so a stale tab cannot complete later. And
if one completes anyway, "a success capture arriving on a canceled
tender … is recorded, never rejected" — the capture supersedes the
cancellation in the projection, the over-collection surfaces through
charge_status = overcharged, and inFlightCents stays 0 either way
(markTenderCanceled + recompute.ts both encode the rule).
Parameters
| Parameter | Type |
|---|---|
paymentId | string |
opts | CancelTenderOptions |
Returns
Promise<BigIntsAsNumbers<{
amountCents: bigint;
applicationFeeCents: bigint | null;
authorizedCents: bigint;
canceledAt: Date | null;
capturedCents: bigint;
clientActionRequired: boolean;
clientActionRequiredAt: Date | null;
createdAt: Date;
createdBy: string | null;
currencyCode: string;
disputedCents: bigint;
disputeFeeCents: bigint | null;
expiresAt: Date | null;
feeBorneBy: FeeBorneBy | null;
id: string;
idempotencyKey: string | null;
orderId: string;
organizationId: string;
payerServiceFeeCents: bigint | null;
payerServiceFeeRefundedCents: bigint | null;
processingFeeCents: bigint | null;
provider: string;
providerAccountRef: string | null;
providerPaymentId: string | null;
refundedCents: bigint;
requestHash: string | null;
status: PaymentStatus;
tenderMethod: string;
updatedAt: Date;
updatedBy: string | null;
}>>
capture()
capture(paymentId: string, opts?: CaptureTenderOptions): Promise<BigIntsAsNumbers<{
amountCents: bigint;
applicationFeeCents: bigint | null;
authorizedCents: bigint;
canceledAt: Date | null;
capturedCents: bigint;
clientActionRequired: boolean;
clientActionRequiredAt: Date | null;
createdAt: Date;
createdBy: string | null;
currencyCode: string;
disputedCents: bigint;
disputeFeeCents: bigint | null;
expiresAt: Date | null;
feeBorneBy: FeeBorneBy | null;
id: string;
idempotencyKey: string | null;
orderId: string;
organizationId: string;
payerServiceFeeCents: bigint | null;
payerServiceFeeRefundedCents: bigint | null;
processingFeeCents: bigint | null;
provider: string;
providerAccountRef: string | null;
providerPaymentId: string | null;
refundedCents: bigint;
requestHash: string | null;
status: PaymentStatus;
tenderMethod: string;
updatedAt: Date;
updatedBy: string | null;
}>>;Defined in: server/checkout/payment-service.ts:364
Capture a previously authorized tender, full or partial. The amount
defaults to the remaining intended amount
(payment.amountCents − payment.capturedCents). Requires a
providerPaymentId (the provider object must exist) — its absence is an
internal UnknownProviderPaymentError, not a domain condition.
Concurrent/retry capture caveat: the default amount is computed from a
point-in-time pre-lock read; the provider call happens outside any lock by
design, so two concurrent default-amount captures can both send the full
remainder to the provider. The provider-level idempotencyKey is the real
guard — callers retrying or racing captures MUST pass opts.idempotencyKey;
the default amount is computed from a snapshot read.
Parameters
| Parameter | Type |
|---|---|
paymentId | string |
opts | CaptureTenderOptions |
Returns
Promise<BigIntsAsNumbers<{
amountCents: bigint;
applicationFeeCents: bigint | null;
authorizedCents: bigint;
canceledAt: Date | null;
capturedCents: bigint;
clientActionRequired: boolean;
clientActionRequiredAt: Date | null;
createdAt: Date;
createdBy: string | null;
currencyCode: string;
disputedCents: bigint;
disputeFeeCents: bigint | null;
expiresAt: Date | null;
feeBorneBy: FeeBorneBy | null;
id: string;
idempotencyKey: string | null;
orderId: string;
organizationId: string;
payerServiceFeeCents: bigint | null;
payerServiceFeeRefundedCents: bigint | null;
processingFeeCents: bigint | null;
provider: string;
providerAccountRef: string | null;
providerPaymentId: string | null;
refundedCents: bigint;
requestHash: string | null;
status: PaymentStatus;
tenderMethod: string;
updatedAt: Date;
updatedBy: string | null;
}>>
confirm()
confirm(paymentId: string, returnPayload: unknown): Promise<TenderOpResult>;Defined in: server/checkout/payment-service.ts:410
Resume a server-orchestrated flow after a clientAction lands back on the
consumer's returnUrl/postback (proposal §The PaymentProvider port). The
adapter may return ANOTHER clientAction (Worldpay 3DS is up to two
rounds) — it is re-set; or none, in which case the flag is cleared when
an auth/capture txn landed (the action was consumed).
Parameters
| Parameter | Type |
|---|---|
paymentId | string |
returnPayload | unknown |
Returns
Promise<TenderOpResult>
findStaleTenders()
findStaleTenders(before: Date): Promise<BigIntsAsNumbers<{
amountCents: bigint;
applicationFeeCents: bigint | null;
authorizedCents: bigint;
canceledAt: Date | null;
capturedCents: bigint;
clientActionRequired: boolean;
clientActionRequiredAt: Date | null;
createdAt: Date;
createdBy: string | null;
currencyCode: string;
disputedCents: bigint;
disputeFeeCents: bigint | null;
expiresAt: Date | null;
feeBorneBy: FeeBorneBy | null;
id: string;
idempotencyKey: string | null;
orderId: string;
organizationId: string;
payerServiceFeeCents: bigint | null;
payerServiceFeeRefundedCents: bigint | null;
processingFeeCents: bigint | null;
provider: string;
providerAccountRef: string | null;
providerPaymentId: string | null;
refundedCents: bigint;
requestHash: string | null;
status: PaymentStatus;
tenderMethod: string;
updatedAt: Date;
updatedBy: string | null;
}>[]>;Defined in: server/checkout/payment-service.ts:761
Thin delegation (proposal §Tender cancellation & abandonment): tenders
non-terminal past expires_at, or past before when unset. The
consumer's scheduled sweep feeds these to reconcilePayment /
cancelTender (stage 5.5) — including any tender stranded pending by a
crash between TX1 and TX2.
Parameters
| Parameter | Type |
|---|---|
before | Date |
Returns
Promise<BigIntsAsNumbers<{
amountCents: bigint;
applicationFeeCents: bigint | null;
authorizedCents: bigint;
canceledAt: Date | null;
capturedCents: bigint;
clientActionRequired: boolean;
clientActionRequiredAt: Date | null;
createdAt: Date;
createdBy: string | null;
currencyCode: string;
disputedCents: bigint;
disputeFeeCents: bigint | null;
expiresAt: Date | null;
feeBorneBy: FeeBorneBy | null;
id: string;
idempotencyKey: string | null;
orderId: string;
organizationId: string;
payerServiceFeeCents: bigint | null;
payerServiceFeeRefundedCents: bigint | null;
processingFeeCents: bigint | null;
provider: string;
providerAccountRef: string | null;
providerPaymentId: string | null;
refundedCents: bigint;
requestHash: string | null;
status: PaymentStatus;
tenderMethod: string;
updatedAt: Date;
updatedBy: string | null;
}>[]>
getDispute()
getDispute(disputeId: string): Promise<
| BigIntsAsNumbers<{
amountCents: bigint;
closedAt: Date | null;
createdAt: Date;
createdBy: string | null;
evidenceDueBy: Date | null;
id: string;
openedAt: Date;
orderId: string;
organizationId: string;
paymentId: string;
provider: string;
providerAccountRef: string;
providerDisputeId: string;
reason: string | null;
status: DisputeStatus;
statusOccurredAt: Date | null;
updatedAt: Date;
updatedBy: string | null;
}>
| null>;Defined in: server/checkout/payment-service.ts:1319
Dispute reads exposed on PaymentService (DisputeService folded in).
Parameters
| Parameter | Type |
|---|---|
disputeId | string |
Returns
Promise<
| BigIntsAsNumbers<{
amountCents: bigint;
closedAt: Date | null;
createdAt: Date;
createdBy: string | null;
evidenceDueBy: Date | null;
id: string;
openedAt: Date;
orderId: string;
organizationId: string;
paymentId: string;
provider: string;
providerAccountRef: string;
providerDisputeId: string;
reason: string | null;
status: DisputeStatus;
statusOccurredAt: Date | null;
updatedAt: Date;
updatedBy: string | null;
}>
| null>
handleWebhook()
handleWebhook(provider: string, req: WebhookRequest): Promise<HandleWebhookResult>;Defined in: server/checkout/payment-service.ts:609
Idempotent webhook ingestion (proposal §Idempotent webhook ingestion) —
the only path provider state mutates the ledger; every reporting channel
normalizes to CanonicalTxns through the same dedupe upsert, so replays
and out-of-order delivery converge (recompute() is a pure sum over the
full event set).
Flow: parseWebhook runs OUTSIDE any transaction — signature
verification is CPU/IO that must never sit under a row lock, and a
forged signature is an adapter EXCEPTION (propagates), not a routing
result. The tender is then located with plain reads — the
merchant-reference echo (parsed.merchantReference = payments.id,
the port's Correlation rule) first, the (provider, provider_payment_id)
fallback second — and ingestion happens in ONE transaction: lock order →
payment (the global lock order, principle 7), re-read under the locks,
upsert txns, recompute both levels, write buckets, append events, commit.
Routing results (never thrown):
foreign— no echo and no fallback match: not ours; ack upstream so mixed-traffic provider accounts don't accumulate failures and get the endpoint disabled. One edge is foreign BY CONSTRUCTION (accepted by the proposal): an event carrying no echo for a tender whoseprovider_payment_idis still NULL (TX2 crashed before ingesting the op result) cannot match — and is acked, because redelivery would not help; no future delivery carries more information. The stale-tender sweep (findStaleTenders→reconcilePayment, task 5.5) is the backstop. Also foreign (defensive): an echo-located row whoseprovidercolumn ≠ this endpoint'sproviderargument — another provider's tender is not ours to mutate via this endpoint. And amerchantReferencethat is not UUID-shaped (seeUUID_RE): only "a taproot-shaped reference" can be apayments.id, so a junk echo classifies as the no-echo path instead of unknown_payment (redelivery of garbage never helps) — or a Postgres uuid cast error.unknown_payment— a taproot-shaped echo with no row: a transient race or an orphaned provider object; respond non-2xx so the provider redelivers. The result'sproviderPaymentIdisparsed.providerPaymentId ?? parsed.merchantReference— when the event carries no provider object id, the merchant reference is the only identifying handle to report.
provider_payment_id refine-once (adjudicated mechanism for the port's
"a hosted flow that reveals its durable object id late refines
provider_payment_id once — the only permitted update to that column"):
a NULL column is always written (TX2-crash recovery — not a
"refinement"); a non-null DIFFERING value is overwritten only when the
event was located by the merchant-reference ECHO and the tender has
no success txn of ANY kind yet — evaluated BEFORE this event's txns are
recorded, because the completion webhook that reveals the durable id is
also the one carrying the first money facts. Any success fact
(authorization, capture, refund, dispute, …) anchors the id: once one
exists the stored id is durable and any differing id is ignored;
fallback-located events match the stored id by definition (no-op).
parsed.cancelsTender (session/auth expiry carrying no money movement)
routes through markTenderCanceled inside the same locked transaction;
the (usually empty) txn list still flows through ingestIntoLedger so
the recompute drops the tender's in-flight and reopens the split-tender
guard.
req.rawBody is persisted onto newly recorded txns as the event-level
rawPayload (see webhookRawPayload); scrubbing is task 5.5's
scrubRawPayloads.
Ingestion is hook-free by design: the domain_events appended in this
transaction ARE the consumer decoupling; delivery is stage 8's outbox
dispatcher.
Parameters
| Parameter | Type |
|---|---|
provider | string |
req | WebhookRequest |
Returns
Promise<HandleWebhookResult>
listDisputesForOrder()
listDisputesForOrder(orderId: string): Promise<BigIntsAsNumbers<{
amountCents: bigint;
closedAt: Date | null;
createdAt: Date;
createdBy: string | null;
evidenceDueBy: Date | null;
id: string;
openedAt: Date;
orderId: string;
organizationId: string;
paymentId: string;
provider: string;
providerAccountRef: string;
providerDisputeId: string;
reason: string | null;
status: DisputeStatus;
statusOccurredAt: Date | null;
updatedAt: Date;
updatedBy: string | null;
}>[]>;Defined in: server/checkout/payment-service.ts:1323
Parameters
| Parameter | Type |
|---|---|
orderId | string |
Returns
Promise<BigIntsAsNumbers<{
amountCents: bigint;
closedAt: Date | null;
createdAt: Date;
createdBy: string | null;
evidenceDueBy: Date | null;
id: string;
openedAt: Date;
orderId: string;
organizationId: string;
paymentId: string;
provider: string;
providerAccountRef: string;
providerDisputeId: string;
reason: string | null;
status: DisputeStatus;
statusOccurredAt: Date | null;
updatedAt: Date;
updatedBy: string | null;
}>[]>
recomputeTenderFromLedger()
protected recomputeTenderFromLedger(
repos: CheckoutRepositories,
payment: PaymentRow,
overrides?: Partial<Pick<TenderFacts, "clientActionRequired" | "clientActionRequiredAt">>
): Promise<{
fold: TenderComputation;
patch: TenderBucketPatch;
}>;Defined in: server/checkout/base-checkout-service.ts:94
Re-project a tender from its persisted ledger without writing it.
Explicit clientActionRequiredAt: null clears the stored timestamp.
Parameters
| Parameter | Type |
|---|---|
repos | CheckoutRepositories |
payment | PaymentRow |
overrides? | Partial<Pick<TenderFacts, "clientActionRequired" | "clientActionRequiredAt">> |
Returns
Promise<{
fold: TenderComputation;
patch: TenderBucketPatch;
}>
Inherited from
BaseCheckoutService.recomputeTenderFromLedgerreconcileClosedAt()
protected reconcileClosedAt(
repos: CheckoutRepositories,
order: OrderRow,
now: Date
): Promise<void>;Defined in: server/checkout/base-checkout-service.ts:121
Reconcile closedAt and the once-per-order order.paid event after a
money write. The caller must hold the order lock in an ambient transaction.
Parameters
| Parameter | Type |
|---|---|
repos | CheckoutRepositories |
order | OrderRow |
now | Date |
Returns
Promise<void>
Inherited from
BaseCheckoutService.reconcileClosedAtreconcilePayment()
reconcilePayment(paymentId: string): Promise<BigIntsAsNumbers<{
amountCents: bigint;
applicationFeeCents: bigint | null;
authorizedCents: bigint;
canceledAt: Date | null;
capturedCents: bigint;
clientActionRequired: boolean;
clientActionRequiredAt: Date | null;
createdAt: Date;
createdBy: string | null;
currencyCode: string;
disputedCents: bigint;
disputeFeeCents: bigint | null;
expiresAt: Date | null;
feeBorneBy: FeeBorneBy | null;
id: string;
idempotencyKey: string | null;
orderId: string;
organizationId: string;
payerServiceFeeCents: bigint | null;
payerServiceFeeRefundedCents: bigint | null;
processingFeeCents: bigint | null;
provider: string;
providerAccountRef: string | null;
providerPaymentId: string | null;
refundedCents: bigint;
requestHash: string | null;
status: PaymentStatus;
tenderMethod: string;
updatedAt: Date;
updatedBy: string | null;
}>>;Defined in: server/checkout/payment-service.ts:949
Poll-truth reconciliation (proposal §The PaymentProvider port:
fetchPaymentState "feeds the SAME dedupe ingestion"; §Tender
cancellation & abandonment: the sweep "calls reconcilePayment first
where the provider supports fetchPaymentState — the truth may simply
be late, including a TX2 that crashed after the provider call
succeeded"; §Operational checklist items 3–4). The provider call runs
OUTSIDE any transaction; the returned CanonicalTxns then ingest in one
locked transaction exactly like a webhook's — so reconcile converges
with whatever webhooks already wrote (same dedupe keys → no duplicate
rows, no duplicate events). No provider_payment_id refinement and no
rawPayload (a poll is our own question, not provider evidence worth
retaining).
Internal-misuse errors (the routing-result leniency is handleWebhook's
alone): a provider without fetchPaymentState →
UnsupportedCapabilityError; a tender with no provider object →
UnknownProviderPaymentError (there is nothing to query — the sweep
cancels those instead).
Parameters
| Parameter | Type |
|---|---|
paymentId | string |
Returns
Promise<BigIntsAsNumbers<{
amountCents: bigint;
applicationFeeCents: bigint | null;
authorizedCents: bigint;
canceledAt: Date | null;
capturedCents: bigint;
clientActionRequired: boolean;
clientActionRequiredAt: Date | null;
createdAt: Date;
createdBy: string | null;
currencyCode: string;
disputedCents: bigint;
disputeFeeCents: bigint | null;
expiresAt: Date | null;
feeBorneBy: FeeBorneBy | null;
id: string;
idempotencyKey: string | null;
orderId: string;
organizationId: string;
payerServiceFeeCents: bigint | null;
payerServiceFeeRefundedCents: bigint | null;
processingFeeCents: bigint | null;
provider: string;
providerAccountRef: string | null;
providerPaymentId: string | null;
refundedCents: bigint;
requestHash: string | null;
status: PaymentStatus;
tenderMethod: string;
updatedAt: Date;
updatedBy: string | null;
}>>
recordCanonicalTransactions()
protected recordCanonicalTransactions(
repos: CheckoutRepositories,
context: RecordTxnContext,
transactions: CanonicalTxn[]
): Promise<RecordedCanonicalTxn[]>;Defined in: server/checkout/base-checkout-service.ts:61
Record canonical transactions sequentially and identify both fresh inserts and pending rows resolved in place. Callers own the resulting side effects.
Parameters
| Parameter | Type |
|---|---|
repos | CheckoutRepositories |
context | RecordTxnContext |
transactions | CanonicalTxn[] |
Returns
Promise<RecordedCanonicalTxn[]>
Inherited from
BaseCheckoutService.recordCanonicalTransactionsrecordManualPayment()
recordManualPayment(orderId: string, input: RecordManualPaymentInput): Promise<BigIntsAsNumbers<{
amountCents: bigint;
applicationFeeCents: bigint | null;
authorizedCents: bigint;
canceledAt: Date | null;
capturedCents: bigint;
clientActionRequired: boolean;
clientActionRequiredAt: Date | null;
createdAt: Date;
createdBy: string | null;
currencyCode: string;
disputedCents: bigint;
disputeFeeCents: bigint | null;
expiresAt: Date | null;
feeBorneBy: FeeBorneBy | null;
id: string;
idempotencyKey: string | null;
orderId: string;
organizationId: string;
payerServiceFeeCents: bigint | null;
payerServiceFeeRefundedCents: bigint | null;
processingFeeCents: bigint | null;
provider: string;
providerAccountRef: string | null;
providerPaymentId: string | null;
refundedCents: bigint;
requestHash: string | null;
status: PaymentStatus;
tenderMethod: string;
updatedAt: Date;
updatedBy: string | null;
}>>;Defined in: server/checkout/payment-service.ts:478
Record a cash/check/gift-card/stored-balance payment through the built-in
ManualProvider (registry key "manual"). Same two-phase shape as
authorize with the ONE documented exception: the provider capture
runs INSIDE TX2 — balanceLedger.debit receives the ambient transaction
via TransactionManager.startOrUseTransaction, so the consumer's balance
fact and the success txn commit or roll back together (proposal §Stored
balances debit synchronously).
Parameters
| Parameter | Type |
|---|---|
orderId | string |
input | RecordManualPaymentInput |
Returns
Promise<BigIntsAsNumbers<{
amountCents: bigint;
applicationFeeCents: bigint | null;
authorizedCents: bigint;
canceledAt: Date | null;
capturedCents: bigint;
clientActionRequired: boolean;
clientActionRequiredAt: Date | null;
createdAt: Date;
createdBy: string | null;
currencyCode: string;
disputedCents: bigint;
disputeFeeCents: bigint | null;
expiresAt: Date | null;
feeBorneBy: FeeBorneBy | null;
id: string;
idempotencyKey: string | null;
orderId: string;
organizationId: string;
payerServiceFeeCents: bigint | null;
payerServiceFeeRefundedCents: bigint | null;
processingFeeCents: bigint | null;
provider: string;
providerAccountRef: string | null;
providerPaymentId: string | null;
refundedCents: bigint;
requestHash: string | null;
status: PaymentStatus;
tenderMethod: string;
updatedAt: Date;
updatedBy: string | null;
}>>
scrubRawPayloads()
scrubRawPayloads(before: Date): Promise<number>;Defined in: server/checkout/payment-service.ts:987
Records-retention scrub — thin delegation to the repository's bulk
statement (no transaction needed). Proposal §Operational checklist
item 8: "Retention — pruneDelivered(before) for processed events;
scrubRawPayloads(before) per your records-retention schedule"; the
repo method documents the append-only carve-out and the
storage-time-cutoff rationale.
Parameters
| Parameter | Type |
|---|---|
before | Date |
Returns
Promise<number>
transaction()
protected transaction<T>(fn: (deps: CheckoutFeatureDeps) => Promise<T>): Promise<T>;Defined in: server/checkout/base-checkout-service.ts:49
Type Parameters
| Type Parameter |
|---|
T |
Parameters
| Parameter | Type |
|---|---|
fn | (deps: CheckoutFeatureDeps) => Promise<T> |
Returns
Promise<T>
Inherited from
BaseCheckoutService.transactionvoid()
void(paymentId: string, opts?: VoidTenderOptions): Promise<BigIntsAsNumbers<{
amountCents: bigint;
applicationFeeCents: bigint | null;
authorizedCents: bigint;
canceledAt: Date | null;
capturedCents: bigint;
clientActionRequired: boolean;
clientActionRequiredAt: Date | null;
createdAt: Date;
createdBy: string | null;
currencyCode: string;
disputedCents: bigint;
disputeFeeCents: bigint | null;
expiresAt: Date | null;
feeBorneBy: FeeBorneBy | null;
id: string;
idempotencyKey: string | null;
orderId: string;
organizationId: string;
payerServiceFeeCents: bigint | null;
payerServiceFeeRefundedCents: bigint | null;
processingFeeCents: bigint | null;
provider: string;
providerAccountRef: string | null;
providerPaymentId: string | null;
refundedCents: bigint;
requestHash: string | null;
status: PaymentStatus;
tenderMethod: string;
updatedAt: Date;
updatedBy: string | null;
}>>;Defined in: server/checkout/payment-service.ts:437
Void an uncaptured authorization (pre-settlement cancel window).
Parameters
| Parameter | Type |
|---|---|
paymentId | string |
opts | VoidTenderOptions |
Returns
Promise<BigIntsAsNumbers<{
amountCents: bigint;
applicationFeeCents: bigint | null;
authorizedCents: bigint;
canceledAt: Date | null;
capturedCents: bigint;
clientActionRequired: boolean;
clientActionRequiredAt: Date | null;
createdAt: Date;
createdBy: string | null;
currencyCode: string;
disputedCents: bigint;
disputeFeeCents: bigint | null;
expiresAt: Date | null;
feeBorneBy: FeeBorneBy | null;
id: string;
idempotencyKey: string | null;
orderId: string;
organizationId: string;
payerServiceFeeCents: bigint | null;
payerServiceFeeRefundedCents: bigint | null;
processingFeeCents: bigint | null;
provider: string;
providerAccountRef: string | null;
providerPaymentId: string | null;
refundedCents: bigint;
requestHash: string | null;
status: PaymentStatus;
tenderMethod: string;
updatedAt: Date;
updatedBy: string | null;
}>>