API Client

The application makes almost no hand-written HTTP calls. Backend access goes through @payability/pyb-ng2-api, a private package published to GitHub Packages that ships typed services, DTOs, models and enums for the Payability APIs.

Package

@payability/pyb-ng2-api

Registry

GitHub Packages (@payability scope — needs a token, see Local Setup)

Module

PybApiModule.forRoot(config)

Surface

~44 service files under lib/services/, plus dto/, models/, enums/, params/, responses/, headers/, interfaces/, tokens/

Because it is a separate package, its internals are documented by its own component in the central Antora site. This page documents how this application consumes it.

Registration

AppModule configures the client once, from the generated environment:

PybApiModule.forRoot({
    baseUrl:                    environment.apiUrl,
    marketplaceUrl:             environment.marketplaceUrl,
    frontendActionsToolsApiUrl: environment.frontendActionsToolsApiUrl,
    b2bDocumentUrl:             environment.b2bDocumentUrl,
    gci:                        environment.gci,
    frontendTaskManager:        environment.frontendTaskManager,
    documentsApiUrl:            environment.apiUrl,      (1)
}),
1 Documents share the main API host; the config field exists so they can be split later.

The config shape is ApiServiceConfig:

export interface ApiServiceConfig {
    baseUrl: string;
    marketplaceUrl: string;
    frontendActionsToolsApiUrl: string;
    b2bDocumentUrl: string;
    documentsApiUrl?: string;
    frontendTaskManager: string;
    gci: string;
    cloudWatchApiUrl?: string;
}

Each value becomes a DI token that the generated services inject:

BASE_URL_TOKEN

The main supplier API.

MARKETPLACE_URL_TOKEN

Marketplace web API — connection health, invites, credentials.

ACTION_TOOLS_API_URL_TOKEN

Frontend actions tools.

B2B_DOCUMENTS_API_URL_TOKEN / DOCUMENTS_API_URL_TOKEN

Document upload and retrieval.

B2B_TASK_MANAGER_API_URL_TOKEN

Task manager.

MASK_MANAGER_GCI_TOKEN

The gci value — a per-environment identifier derived from a SHA-1 of ENV_NAME.

CLOUD_WATCH_API_URL_TOKEN

Metrics endpoint. Not passed here; CloudWatchModule supplies it separately.

cloudWatchApiUrl is deliberately absent

PybApiModule.forRoot() accepts cloudWatchApiUrl but this app does not pass it. CloudWatch is wired through the in-repo vendors/cloud-watch/ module with its own token instead. See Observability.

PybApiModule exports HttpClientModule, so AppModule gets HttpClient from the API module rather than importing it directly. That is also why the interceptors registered in CoreModule apply to generated-client calls — they all share one HttpClient.

EnvironmentService

src/environments/environment.service.ts is the type for the generated environment object, and is also provided so it can be injected:

@Injectable()
export class EnvironmentService {
    env?: string;
    version?: string;
    buildTime?: string;
    production: boolean;
    isMockEnabled: boolean;
    authTokenKey: string;
    airwalexBaseUrl: string;
    apiUrl: string;
    authUrl: string;
    gci: string;
    frontendTaskManager: string;
    marketplaceUrl: string;
    frontendActionsToolsApiUrl: string;
    b2bDocumentUrl: string;
    tabapayUrl: string;
    agGridLicenseKey: string;
    segmentKey: string;
    referralUrl: string;
    marquetaSandbox: boolean;
    plaidSandbox: boolean;
    cloudWatchApiUrl: string;
    zendeskWidgetUrl: string;
    zendeskWidgetKey: string;
    recaptchaKey: string;
    smartLookKey: string;
}

Injecting EnvironmentService is preferred over importing the environment constant, because it is mockable in tests. Roughly two dozen services do so.

Adding a setting means touching four places, or the build breaks or silently ships an empty string:

  1. config/config.js — the per-environment value

  2. config/environment.template — the EJS line that emits it

  3. src/environments/environment.service.ts — the field declaration

  4. src/environments/environment.prod.ts — if production differs

environment.ts itself is generated. See Local Setup.

authUrl and airwalexBaseUrl are not passed to PybApiModule — they are used directly by AuthService and AirwallexCardService, which build their own requests.

Service catalog

The generated services this application actually imports, grouped by area. Names are the exported classes; files live in lib/services/.

Supplier and account

SuppliersService

Supplier details, status, account creation, available payment methods. The most-used service in the app.

OnboardingService

Pre-activation status, submitApplication().

PreSubmissionStepsStatusService

Pre-submission step state.

BusinessOwnersService, BusinessTypesService

Business profile reference data.

ShippingAddressService

Shipping address for physical cards.

CountriesService, StatesService

Geographic reference data.

ComplianceActionsService

Compliance records and required actions.

DocumentsService

Document upload, listing, retrieval.

LoginsService

Login history.

ChangePasswordService

Authenticated password change.

DashboardMessageService

The server-driven announcement banner.

NewSdFeedbackService, OldSdSwitchService

Dashboard-version feedback and switching.

CancellationSurveyService, CancellationWorkflowApiService

Deactivation. Cancellation & Reactivation

Money and products

BalanceService

Available balance.

AdvanceLineService

Advance Line summary, offers, withdrawals. Advance Line

CrossSellService

Product offering availability. Product Offerings

ProductSummaryService

The dashboard product summary.

PaymentMethodService, PaymentFlowsService

Payout methods (services/payments/) and repayment flows.

TransferFundsService

Transfer requests.

FeeScheduleService

The fee schedule behind the fees slice.

RebatePunchCardService

Punch-card rewards.

OpenInvoicesService

Open invoices.

MonthEndCloseService

Month-end close state.

SendMoneyService

Vendor Pay outgoing payments. Vendor Pay

Cards and banking

MarqetaService

Seller Card issuance, activation, reveal. Marqeta & Airwallex

CardTransactionService

Card transaction report.

PlaidService

Link token exchange. Plaid

SwiftService

Routing/SWIFT verification — used as an async validator. Forms, Fields and Validation

Marketplaces

MarketplacesService

Supplier marketplaces, invites, credentials.

AmazonService

Amazon-specific connection operations. Marketplace API Connectors

Contracts

DocuSignService

One URL-generating method per flow — getOnboardingActivationDocuSignUrl(), and the Advance Line, Instant Advance, LTC and re-sign equivalents. DocuSign Contract Flows

Reports

DailySummaryReportService

Daily summary.

TransferReportService

Transfers.

MarketplacePaymentService

Marketplace payments and transaction details.

FeeReportService

Fees.

InstantAdvanceReportService

Advance report.

ReconciliationViewService

Reconciliation view.

ContractsOverviewReportService

Commitment overview.

ExportCSVService, PybStatementService

Export and statement generation.

Report data is consumed through the datasource layer rather than called directly from components — see Reports.

Infrastructure

B2bTaskManagerService

Task manager operations.

NotificationsService

Dashboard notification operations, under services/action-tools/ and served by frontendActionsToolsApiUrl.

B2bDocumentService

B2B document API.

SegmentService

Server-side Segment helpers. The client uses EventLoggerService instead. Event Logger

CloudWatchService

Present in the package, but the app uses its own vendors/cloud-watch/ implementation.

Full local service inventory: Service Catalog.

Request lifecycle

Every generated-service call goes through the same chain, because there is one HttpClient:

SomeApiService.method(args)
  → HttpClient
      → AuthInterceptor              adds Authorization / session headers
      → UnauthorizedInterceptor      401 → logout + redirect
      → HttpErrorHandlerInterceptor  toasts, special-cases ACCOUNT_LOCKED
  → response (typed DTO)

Details in HTTP Interceptors. The practical consequence: never add auth headers or error toasts at the call site. The interceptors already did it.

Calls that bypass the generated client

Twelve services build requests with HttpClient directly. They are not mistakes in every case, but each is a place where a URL is assembled by hand:

Service Why

AuthService (core/auth/_services/)

Targets authUrl, not baseUrl, and needs Basic auth plus a recaptcha header. Authentication

AirwallexCardService

Targets airwalexBaseUrl. Marqeta & Airwallex

EntrustIdentityService

Entrust session creation. Entrust Identity

CloudWatchService (vendors/cloud-watch/)

Own module and own URL token. Observability

BlogService

CMS endpoint, outside the supplier API.

EmailPreferenceService

Email preference endpoints not yet in the package.

ProductSummaryService (core/pyb/services/widgets/)

Predates ProductSummaryService in the package.

ProductOfferingService (views/onboarding/product-offering/)

GET /suppliers/{id}/approved_products, POST /suppliers/{id}/accept_products. Onboarding Pages

TransferService (your-account-widget/)

Widget-local transfer call.

OutstandingBalanceService, and the two VendorpayReportsService implementations

Report endpoints assembled locally alongside their column configs.

When to add a raw call

Prefer extending @payability/pyb-ng2-api — a typed method there is reusable and versioned. Reach for HttpClient only when the endpoint lives on a host the package does not know about, or when you are prototyping against an endpoint that is not yet in the contract. If you do, inject EnvironmentService for the host rather than hardcoding it, and let the interceptors handle auth and errors.

Mocking in tests

Generated services are mocked like any other provider, following the <Resource>ServiceMock convention. See Testing.