Files
nick-doc/02 - Data Models/Payment.md
Siavash Sameni 4cf5c49274 docs(audit): align documentation with post-remediation backend reality
- Update data model enums to match backend models
- Update API reference auth requirements
- Add dispute module references and warning blocks
- Add 2026-05-24 audit remediation callout to Overview
- Generate task breakdowns and audit artifacts
- Add doc alignment report (.taskmaster/reports/)
2026-05-24 11:16:29 +04:00

8.1 KiB

title, tags, aliases
title tags aliases
Payment
data-model
mongoose
Payment Record
Escrow
IPayment

Payment

Records every monetary movement in the marketplace: buyer pay-ins, seller payouts, and refunds. Designed around the SHKeeper crypto payment gateway with explicit fields for blockchain network, transaction hash, escrow state, and provider invoice ids. The provider and direction discriminators let one collection hold all four flow types (incoming buyer payment, outgoing seller payout, refund, and "other" provider integrations).

[!note] Source backend/src/models/Payment.ts:3 — schema definition backend/src/models/Payment.ts:257 — model export (default export)

[!warning] Mixed types purchaseRequestId, sellerOfferId, and sellerId use Schema.Types.Mixed. They are usually ObjectIds, but the template-checkout flow passes string ids that do not yet exist in the database, so the schema accepts both.

Schema

Field Type Required Default Validation Index Description
purchaseRequestId Mixed (ObjectId or String) yes yes (compound, partial) Linked PurchaseRequest id (or template id).
sellerOfferId Mixed (ObjectId or String) yes Linked SellerOffer id (or template offer ref).
buyerId ObjectId → User yes yes (compound) Buyer paying.
sellerId Mixed (ObjectId or String) yes yes (compound) Seller receiving (or template seller).
amount.amount Number yes Numeric amount.
amount.currency String yes USDT Settlement currency.
provider String no shkeeper enum: shkeeper / request.network / request-network / other yes (compound, partial) Payment processor.
direction String no in enum: in / out / refund yes (compound, partial) Flow direction.
blockchain.network String no Network identifier.
blockchain.transactionHash String no yes (sparse) On-chain tx hash.
blockchain.blockchain String no enum: ethereum / polygon / bsc / avalanche / solana / optimism / arbitrum / base / gnosis Chain.
blockchain.token String no Token symbol.
blockchain.sender String no Source address.
blockchain.receiver String no Destination address.
blockchain.confirmedAt Date no When tx confirmed.
blockchain.confirmations Number no 0 Confirmation count.
status String no pending enum: pending / processing / confirmed / completed / failed / cancelled / refunded yes (compound) Lifecycle status.
escrowState String no enum: funded / releasable / released / refunded / releasing / failed / cancelled / partial Escrow lifecycle.
providerPaymentId String no yes (sparse) External provider id for idempotency.
metadata.userAgent String no Browser UA.
metadata.ipAddress String no Client IP.
metadata.walletType String no Wallet category.
metadata.paymentMethod String no Payment method label.
metadata.shkeeperUrl String no Invoice URL.
metadata.shkeeperInvoiceId String no Invoice id.
metadata.shkeeperData Mixed no Raw provider payload.
metadata.shkeeperStatus String no Provider status string.
metadata.balanceFiat String no Fiat-equivalent balance.
metadata.balanceCrypto String no Crypto balance.
metadata.cryptoName String no Crypto label.
metadata.walletAddress String no Wallet address.
metadata.shkeeperTaskId String no Payout task id.
metadata.requestNetworkRequestId String no Request Network request id.
metadata.requestNetworkPaymentReference String no Request Network payment reference.
metadata.requestNetworkSecurePaymentUrl String no Request Network secure payment URL.
metadata.requestNetworkData Mixed no Raw Request Network payload.
metadata.lastWebhookAt Date no Last webhook timestamp.
metadata.webhookPayload Mixed no Last webhook body.
metadata.createdVia String no Origin marker.
metadata.payoutType String no Payout sub-type.
metadata.error String no Last error message.
metadata.failedAt Date no When it failed.
createdAt Date auto Date.now yes (compound) Mongoose timestamp.
processedAt Date no When processing started.
completedAt Date no When fully settled.
notes String no Free-form notes.
updatedAt Date auto Mongoose timestamp.

Virtuals

Virtual Returns Definition
paymentRef PAY-<LAST_8_OF_ID_UPPERCASE> backend/src/models/Payment.ts:191

The schema enables toJSON: { virtuals: true } and toObject: { virtuals: true } so the ref appears in API responses.

Indexes

Defined at backend/src/models/Payment.ts:174-188:

  • { status: 1, createdAt: -1 } — admin queues.
  • { buyerId: 1, status: 1 } — buyer dashboard.
  • { sellerId: 1, status: 1 } — seller dashboard.
  • { 'blockchain.transactionHash': 1 } (sparse) — webhook lookup by hash.
  • { providerPaymentId: 1 } (sparse) — provider idempotency.
  • { buyerId: 1, purchaseRequestId: 1, provider: 1, direction: 1 } (unique, partial: provider === 'shkeeper' && direction === 'in' && status === 'pending', name uniq_pending_shkeeper_by_buyer_session) — guards against duplicate pending invoices.

Pre/Post Hooks

None declared.

Instance Methods

None defined.

Static Methods

None defined.

Relationships

  • References: User (buyerId, sometimes sellerId), PurchaseRequest (purchaseRequestId), SellerOffer (sellerOfferId).
  • Referenced by: Indirectly through PurchaseRequest status transitions and Dispute resolution amounts; no model holds a direct foreign key back to Payment.

State Transitions

Payment status:

stateDiagram-v2
    [*] --> pending
    pending --> processing : webhook received
    processing --> confirmed : tx confirmed
    confirmed --> completed : escrow released / payout done
    pending --> cancelled : buyer aborts
    processing --> failed : provider error
    completed --> refunded : dispute resolved
    failed --> [*]
    cancelled --> [*]
    completed --> [*]
    refunded --> [*]

Escrow state (for direction: 'in'):

stateDiagram-v2
    [*] --> funded : buyer pays
    funded --> releasable : delivery confirmed
    releasable --> releasing : payout initiated
    releasing --> released : payout completed
    funded --> refunded : dispute refund
    releasing --> failed : payout error
    released --> [*]
    refunded --> [*]
    failed --> [*]

Common Queries

// Buyer history
Payment.find({ buyerId, direction: 'in' }).sort({ createdAt: -1 });

// Seller payouts
Payment.find({ sellerId, direction: 'out', status: 'completed' });

// Webhook lookup
Payment.findOne({ providerPaymentId });

// Pending escrows ready for release
Payment.find({ direction: 'in', escrowState: 'releasable' });

// Idempotent invoice creation (will fail by unique index if a pending one exists)
Payment.create({
  buyerId, purchaseRequestId, provider: 'shkeeper', direction: 'in', status: 'pending', ...
});

Related: PurchaseRequest, SellerOffer, User, Dispute.