/** * Scaffolded PayPal OpenAPI clients (dependency-free ESM). * * Sources (@kody/api-research scaffold-client, auth kind: none — bearer injected by package auth layer): * - https://raw.githubusercontent.com/paypal/paypal-rest-api-specifications/main/openapi/invoicing_v2.json * slugs: invoices_list, invoices_get, invoices_search_invoices, invoices_create, invoices_send * - https://raw.githubusercontent.com/paypal/paypal-rest-api-specifications/main/openapi/reporting_transactions_v1.json * slugs: search_get, balances_get * - https://raw.githubusercontent.com/paypal/paypal-rest-api-specifications/main/openapi/payments_payouts_batch_v1.json * slugs: payouts_create, payouts_get, payouts_item_get * * Host approval stays in the account security UI; the OpenAPI spec never widens it. */ export type QueryValue = string | number | boolean | null | undefined export type QueryInput = Record export type ScaffoldInput = { params?: Record query?: QueryInput headers?: Record body?: unknown } export type ScaffoldOptions = { fetchImpl?: typeof fetch /** Override the default live API base (e.g. sandbox). */ apiBaseUrl?: string } const DEFAULT_API_BASE_URL = 'https://api-m.paypal.com' function resolveApiBaseUrl(options: ScaffoldOptions = {}): string { const base = options.apiBaseUrl ?? DEFAULT_API_BASE_URL return String(base).replace(/\/+$/, '') } export function buildUrl( pathTemplate: string, params: Record = {}, apiBaseUrl: string = DEFAULT_API_BASE_URL, ): string { return apiBaseUrl + pathTemplate.replace(/\{([^}]+)\}/g, (_match, name: string) => { const value = params[name] if (value === undefined || value === null) { throw new Error(`Missing required path parameter: ${name}`) } return encodeURIComponent(String(value)) }) } export function appendQuery(url: string, query: QueryInput = {}): string { const search = new URLSearchParams() for (const [key, value] of Object.entries(query)) { if (value === undefined || value === null || value === '') continue if (Array.isArray(value)) { for (const item of value) { if (item === undefined || item === null || item === '') continue search.append(key, String(item)) } continue } search.append(key, String(value)) } const qs = search.toString() return qs ? `${url}?${qs}` : url } function mergeHeaders( userHeaders: Record | undefined, authHeaders: Record, ): Record { const merged: Record = { ...(userHeaders ?? {}) } for (const [key, value] of Object.entries(authHeaders)) { const lower = key.toLowerCase() for (const existing of Object.keys(merged)) { if (existing.toLowerCase() === lower) delete merged[existing] } merged[key] = value } return merged } function hasHeader(headers: Record, name: string): boolean { const lower = name.toLowerCase() return Object.keys(headers).some((key) => key.toLowerCase() === lower) } async function resolveFetch(fetchImpl?: typeof fetch): Promise { return fetchImpl ?? fetch } /** Scaffold auth kind was `none`; callers inject Authorization via input.headers. */ function authHeaders(): Record { return {} } async function request( method: string, pathTemplate: string, input: ScaffoldInput = {}, options: ScaffoldOptions = {}, ): Promise { const params = input.params ?? {} const apiBaseUrl = resolveApiBaseUrl(options) const url = appendQuery(buildUrl(pathTemplate, params, apiBaseUrl), input.query) let body: string | undefined const headers = mergeHeaders(input.headers, authHeaders()) if (input.body !== undefined) { body = JSON.stringify(input.body) if (!hasHeader(headers, 'content-type')) { headers['content-type'] = 'application/json' } } const fetchImpl = await resolveFetch(options.fetchImpl) return fetchImpl(url, { method, headers, body }) } /** GET /v2/invoicing/invoices — List invoices */ export async function invoicesList(input: ScaffoldInput = {}, options: ScaffoldOptions = {}): Promise { return request('GET', '/v2/invoicing/invoices', input, options) } /** GET /v2/invoicing/invoices/{invoice_id} — Show invoice details */ export async function invoicesGet(input: ScaffoldInput = {}, options: ScaffoldOptions = {}): Promise { const params = input.params ?? {} if (params.invoice_id === undefined || params.invoice_id === null) { throw new Error('Missing required path parameter: invoice_id') } return request('GET', '/v2/invoicing/invoices/{invoice_id}', input, options) } /** POST /v2/invoicing/search-invoices — Search for invoices (read-only search) */ export async function invoicesSearchInvoices( input: ScaffoldInput = {}, options: ScaffoldOptions = {}, ): Promise { return request('POST', '/v2/invoicing/search-invoices', input, options) } /** POST /v2/invoicing/invoices — Create draft invoice */ export async function invoicesCreate(input: ScaffoldInput = {}, options: ScaffoldOptions = {}): Promise { return request('POST', '/v2/invoicing/invoices', input, options) } /** POST /v2/invoicing/invoices/{invoice_id}/send — Send an invoice */ export async function invoicesSend(input: ScaffoldInput = {}, options: ScaffoldOptions = {}): Promise { const params = input.params ?? {} if (params.invoice_id === undefined || params.invoice_id === null) { throw new Error('Missing required path parameter: invoice_id') } return request('POST', '/v2/invoicing/invoices/{invoice_id}/send', input, options) } /** GET /v1/reporting/transactions — List transactions */ export async function searchGet(input: ScaffoldInput = {}, options: ScaffoldOptions = {}): Promise { return request('GET', '/v1/reporting/transactions', input, options) } /** GET /v1/reporting/balances — List all balances */ export async function balancesGet(input: ScaffoldInput = {}, options: ScaffoldOptions = {}): Promise { return request('GET', '/v1/reporting/balances', input, options) } /** POST /v1/payments/payouts — Create a batch payout */ export async function payoutsCreate(input: ScaffoldInput = {}, options: ScaffoldOptions = {}): Promise { return request('POST', '/v1/payments/payouts', input, options) } /** GET /v1/payments/payouts/{payout_batch_id} — Show payout batch details */ export async function payoutsGet(input: ScaffoldInput = {}, options: ScaffoldOptions = {}): Promise { const params = input.params ?? {} if (params.payout_batch_id === undefined || params.payout_batch_id === null) { throw new Error('Missing required path parameter: payout_batch_id') } return request('GET', '/v1/payments/payouts/{payout_batch_id}', input, options) } /** GET /v1/payments/payouts-item/{payout_item_id} — Show payout item details */ export async function payoutsItemGet(input: ScaffoldInput = {}, options: ScaffoldOptions = {}): Promise { const params = input.params ?? {} if (params.payout_item_id === undefined || params.payout_item_id === null) { throw new Error('Missing required path parameter: payout_item_id') } return request('GET', '/v1/payments/payouts-item/{payout_item_id}', input, options) }