Marketplaces and gateways

What it is

A marketplace is a sales channel Payability funds against — Amazon Seller Central, Amazon Vendor Central/Express, Walmart, Target, eBay, Shopify, Newegg, Volusion, MoreCommerce, Tophatter, PingPong — plus payment processors treated the same way (PayPal, Stripe, Payoneer, Authorize.net).

Two distinct things are easy to conflate:

The marketplace (marketplaceKey)

A catalogue entry, global across all suppliers. Maintained under /marketplaces.

The marketplace-supplier link (mpSupKey / mpSupplierKey)

One supplier’s account on one marketplace. Funding settings, opt-in periods, minimum-fee overrides, statements and gateway connections all attach here, not to the supplier.

Almost every funding-related bug traced to "the wrong marketplace" is actually a confusion between these two keys.

Where it lives

Concern Location

Catalogue routes

/marketplaces/{list,add,:marketplaceKey/edit} → marketplaces/marketplace-list/, marketplaces/marketplace/

Catalogue services

marketplaces/service/marketplace-repository.ts (implements MarketplacesAbstractService, with marketplace-repository-mock.ts), marketplaces/service/gateway.service.ts

Catalogue models

marketplaces/model/{marketplace-model,marketplace-list-model,marketplace-status.model,gateway.model}.ts

Catalogue store

marketplaces/store/ — the marketplace slice

Supplier link routes

/suppliers/:supplierKey/marketplaces/{list,edit/:mpSupplierKey} → suppliers/supplier/supplier-marketplaces/

Supplier link services

suppliers/services/supplier-marketplaces.service.ts plus the three pricing services (funding, min-fee overrides, opt-in periods) — see fees and reserves

Statements

/suppliers/:supplierKey/statements → suppliers/supplier/supplier-marketplace-statements/; shared/consts/available-statements.const.ts

The catalogue

MarketplaceRepository on internalApiUrl:

Endpoint Purpose

GET marketplaces

List all marketplaces.

GET marketplaces/:uuid

One marketplace.

POST marketplaces

Create.

PUT marketplaces/:uuid

Update.

GET marketplace_period_groups

Funding period groups — the settlement cadences a marketplace can use.

GET free_trials

Free-trial configurations.

There is no delete. A marketplace is retired by status, not removal.

MARKETPLACE (shared/enums/marketplace.enum.ts) enumerates only four names and carries a // TODO: should be extended comment:

export enum MARKETPLACE {
  AMAZON_SELLER_CENTRAL  = 'Amazon Seller Central',
  AMAZON_VENDOR_CENTRAL  = 'Amazon Vendor Central',
  AMAZON_VENDOR_EXPRESS  = 'Amazon Vendor Express',
  PAYABILITY             = 'Payability',
}

This enum is not the marketplace catalogue — it is a partial list of names used for Amazon-specific branching. The authoritative identifiers are the UUID constants in suppliers/supplier/supplier-onboarding/supplier-onboarding.service.ts (AMAZON_SELLER_CENTRAL_MARKETPLACE_KEY, TARGET_MARKETPLACE_KEY, WALLMART_MARKETPLACE_KEY and eleven more). Matching by name is fragile; matching by key is correct. SupplierDetailsModel.isAmazonVendor / isAmazonSeller unfortunately match by name.

Payment gateways

Some marketplaces settle through a payment gateway rather than paying Payability directly. GatewayService (which reads environment directly rather than through AppConfigService — legacy):

Endpoint Purpose

GET payment_gateways

The available gateways.

POST supplier/:marketplaceSupplierKey/create_and_connect/:gatewayKey

Connect a gateway to a marketplace link, with { bankAccountNumber }.

POST supplier/:marketplaceSupplierKey/disconnect/:gatewayKey

Disconnect.

POST supplier/:mpKey/update_payment_gateway_bank_account_number

Update the bank account on an existing connection (SupplierMarketplacesService).

Note the singular supplier/ prefix and that the path parameter is the marketplace-supplier key even though the segment reads supplier.

The marketplace store slice exists solely to hold the gateway list:

export interface IMarketplacesState { possiblePaymentGateways: IPaymentGateway[]; }
// single action: SET_POSSIBLE_GATEWAYS

It is a map-of-handlers reducer with no effects. Gateway connection changes on the supplier side dispatch ADD_PAYMENT_GATEWAY in the supplier slice — which, as noted in suppliers, resets that slice to initialState.

Linking gateways is gated by the MANAGE_LINKING_PAYMENT_GATEWAYS permission.

SupplierMarketplacesService:

Endpoint Base URL

Purpose

GET suppliers/:supplierKey/mp/:mpSupKey

internalApiUrl

The link’s details (SupplierMarketplaceDetailsModel).

PUT suppliers/:supplierKey/mp/:mpSupKey

internalApiUrl

Update the link.

PUT suppliers/:supplierKey/marketplace_suspend_reason

internalApiUrl

Record why a marketplace was suspended for this supplier.

POST supplier/:mpKey/update_payment_gateway_bank_account_number

internalApiUrl

Gateway bank account.

POST /platforms/:marketplaceKey/update_sales_data

marketplaceApiUrl

Refresh sales data — the only call in the app to the marketplace service.

This one service spans two backends. update_sales_data goes to marketplaceApiUrl, everything else to internalApiUrl. The URL is built as ${marketplaceApiUrl}/platforms/… — with a leading slash after a base that already ends in one, producing a double slash. It works, but do not copy the pattern.

Models

Model Contents

SupplierMarketplaceListModel

The summary shown on the supplier record: mpSupKey, marketplaceKey, marketplaceCode, marketplaceName, marketplaceType, externalSupplierId, estimatedMonthlyRevenue, fundingParticulars, draft, marketplaceStatus, paymentGateways, fundingPeriodGroupCode, mpPeriodGroupCode.

SupplierMarketplaceDetailsModel

The full link record (uses @inheritSerialization).

SupplierMarketplaceModel

An aggregate — details + funding + min-fee overrides + opt-in periods. Store-only, no serialisation decorators.

SupplierMarketplaceGatewayModel

A gateway connection on the link.

draft distinguishes a link that has been started but not completed — relevant during onboarding.

Amazon Seller Central links also show a Scraper card with one switch, Passkey Enroll (passkeyEnroll, GAR-2454). When it is on, the earnings scraper registers Payability’s passkey on the seller account at its next password sign-in. The card saves through the same PUT suppliers/:supplierKey/mp/:mpSupKey as the other cards; the backend writes the flag only when its value changed, so saving another card leaves it alone.

Store integration

Four actions in the supplier slice load link data:

Action Behaviour

FETCH_SUPPLIER_MARKETPLACES / _ERROR

Loads all links via SupplierMarketplacesService.prepareMarketplaceListObservable. If the supplier has no marketplaces on the details model, it short-circuits to an empty array without calling the API.

FETCH_SUPPLIER_MARKETPLACE / _SUCCESS / _ERROR

Loads one link. The request-phase reducer case does delete state.supplierModel.marketplaces — a direct mutation. _SUCCESS then either replaces the matching entry (found by mpSupKey) or sets the array to a single-element list.

FETCH_SUPPLIER_MARKETPLACE_DETAILS_PART / _ERROR

Loads a part of the link’s details for partial editing.

FETCH_SUPPLIER_MARKETPLACE_SUCCESS sets supplierModel.marketplaces = [model] when the key is not already present, replacing the whole array rather than appending. Loading a single link after loading the list therefore discards the list. Load order matters.

Marketplace statements

A statement is the marketplace’s periodic settlement report. Screens:

Surface Detail

/suppliers/:key/statements

SupplierMarketplaceStatementsComponent. Routed with RESTRICTED_UW_ACCESS_CONFIG_MARKETPLACE_STATEMENTS, which adds report metadata to data: reportName: 'mp_statements', reportConfigName: 'v_mp_statements', supplierKeyInQueryParamsNotNeeded: true. The tab is therefore rendered by the report machinery over a database view — see reports.

Actions ▸ Edit MP Statement

suppliers/supplier/edit-marketplace-statement/ (MP_STATEMENTS_MODIFY / MP_STATEMENTS_DELETE).

Actions ▸ Add MP Statement

suppliers/supplier/add-marketplace-statement/.

Actions ▸ Add / Add Zero MP Payment

add-marketplace-payment/, add-zero-marketplace-payment/ (INT_MP_PMTS).

Statement catalogue

shared/consts/available-statements.const.ts.

Supplier statements folder

suppliers/supplier/supplier-statements/.

Amazon lending

Amazon offers its own loans, which compete with a Payability advance. The app records them per supplier:

  • Routes /suppliers/:key/amazon-lending/{list,add-loan,loan/:loanKey}.

  • suppliers/supplier/supplier-amazon-lending/.

  • suppliers/services/marketplace-loans.service.ts (+ mock), suppliers/model/marketplace-loan.model.ts.

  • Add and edit are gated by SubPermissionsGuard on MP_LOANS_MODIFY / MP_LOANS_DELETE — the only routes in the app using that guard.

Existing Amazon loans also appear as a card in initial underwriting — see underwriting.

Marketplace access and permissions

Obtaining and maintaining access to a supplier’s marketplace account is an onboarding concern, implemented in the five marketplace-auth- folders and the two supplier-onboarding-marketplace- folders. See onboarding and KYC. suppliers/supplier/marketplace-access-details/ shows the current access state outside onboarding.

Gotchas

Issue Detail

Two keys, similar names

marketplaceKey (catalogue) vs mpSupKey / mpSupplierKey (link). The fees/reserve/edit/:marketplaceKey route takes the catalogue key while marketplaces/edit/:mpSupplierKey takes the link key.

Endpoint prefix supplier/ takes a link key

supplier/:marketplaceSupplierKey/create_and_connect/:gatewayKey.

MARKETPLACE enum is incomplete by design

Four entries with a TODO. Not a catalogue.

Name-based Amazon detection

isAmazonVendor / isAmazonSeller match display names.

Single-link load clobbers the list

See the warning above.

GatewayService bypasses AppConfigService

It imports environment directly. New services should not.