Marketplace Architecture
The PayPM Business Marketplace is a contract-backed value-chain execution layer. It is not a generic listing catalogue.
Two surfaces during the compatibility period
| Surface | Role |
|---|---|
| Compatibility Marketplace in the wallet backend | Authoritative customer-facing Plane A/B routes used by mobile and existing operator tools today (GET /marketplace/my, /internal/marketplace/*) |
| Standalone Marketplace API | Separate product service with its own PostgreSQL schema, Identity directory, and transactional outbox. Sandbox enrollment is internal-only (no public ingress) until parity, rollback, and cutover proof are complete |
Do not treat the standalone service as cut over while the compatibility backend still serves customer Marketplace traffic. Shadow comparison must exit non-zero on any customer-visible mismatch before cutover.
Ownership boundaries
| Owner | Owns |
|---|---|
ZITADEL (auth.paypm.net) | Subject authentication only |
| Identity product | Person, business, membership, OIDC subject link, optional wallet end-user reference |
| Standalone Marketplace | Programmes, opportunities, participation roles (supplier/operator), assignments, milestones, evidence, contract orchestration, outbox events |
| Wallet / ledger / providers | Balances, Blnk postings, signatures, notifications, settlement adapters |
Marketplace never derives participant authority from phone number or token profile
claims. Standalone /context and /my require an active Identity person/business
context and a Marketplace participant whose role matches
MARKETPLACE_REQUIRED_ROLE (default supplier).
Standalone Identity contract
Code
Sandbox Marketplace uses IDENTITY_DIRECTORY_MODE=http against the private
Identity ClusterIP with a ZITADEL service JWT. Identity does not return product
roles. Compatibility mode remains available as a time-boxed adapter only.
See Identity (Account & Business) for bind and account read/update routes.
Compatibility mobile read
GET /api/v1/marketplace/my preserves the current mobile response contract: the
resolved participant, browseable open opportunities, and assignments with their
opportunity projection. It is read-only and tenant-scoped.
Marketplace SPA OIDC
The standalone web client uses a dedicated public SPA OIDC application against
ZITADEL (authorization code + PKCE). Deployment-time public config carries only
issuer, client ID, redirect URI, and Marketplace API URL. The ZITADEL owner must
approve the exact redirect URI; the Identity owner must bind that subject to the
supplier tenant and marketplace:supplier role before the actor is live.
Compatibility backend bounded contexts
While the compatibility backend remains authoritative, operators continue to use the in-backend marketplace registry and Contract Vault spine:
| Context | Owns |
|---|---|
| Marketplace Registry | buyers, suppliers, contractors, verifiers, funders |
| Programmes | value-chain initiatives and opportunity groups |
| Opportunities | tenders, work packages, lots, eligibility |
| Contract Workspace | contract drafts, signed versions, hashes |
| Milestone Ledger | obligations, expected/completed counts, review state |
| Evidence Vault | photos, PDFs, reports, receipts, notes |
| Payment Controls | controlled release instructions into wallet/ledger |
| Payment Executions | provider-neutral gateway handoff attempts and settlement state |
Core flow
Code
Standalone Contract Vault read BFF
The Marketplace product API now exposes OIDC-bound, fail-closed GETs for standalone Contract Vault records, versions, and commitments:
GET /api/v1/marketplace/contract-vault/recordsGET /api/v1/marketplace/contract-vault/:contractRef/versionsGET /api/v1/marketplace/contract-vault/:contractRef/versions/:versionNumberGET /api/v1/marketplace/contract-vault/:contractRef/commitmentsGET /api/v1/marketplace/contract-vault/:contractRef/commitments/:commitmentRef
These are Marketplace SPA OIDC session reads, scoped to tenant + linked
walletEndUserId. They are not on the wallet sandbox Plane A/B catalog
host, and the browser never uses Plane B credentials. Missing link or
store returns unavailable + empty. Writes, signatures, payments, and
evidence remain on wallet-backend.
Compatibility operator API surface
The first contract-vault spine plus marketplace registry path on the compatibility backend includes:
GET /marketplace/myfor the authenticated mobile user's open opportunities and wallet-linked assignmentsGET|POST /internal/marketplace/programmesGET|POST /internal/marketplace/opportunitiesGET|POST /internal/marketplace/participantsGET|POST /internal/marketplace/assignmentsGET|POST /internal/marketplace/milestonesGET|POST /internal/marketplace/evidenceGET|POST /internal/marketplace/payment-controlsGET|POST /internal/marketplace/payment-executionsPOST /internal/marketplace/payment-executions/provider-events- Contract Vault version, signature, commitment, extraction, and anchor-event
endpoints under
/internal/contract-vault/*
Operators can create programmes, opportunities, participants, and assignments in backoffice, then link contracts from Contract Vault. Approved evidence can link to payment-control instructions; approved controls can be followed by payment execution attempts. Provider callbacks or backoffice provider-event workflows reconcile gateway or signature receipts without locking the product to one vendor.
Cutover rule
Snapshots exported from the compatibility backend must carry Identity-owned
identityId values; importers never infer identity from phone or email. Replay
of the same snapshotId and content is idempotent; content drift under an
existing ID fails closed. Keep the compatibility API authoritative until shadow
comparison, observability, and rollback proof are complete.