type Environment = "sandbox" | "live"; type Status = "disconnected" | "pending" | "pending_credentials" | "connected" | "revoked"; declare const PayPalModuleService_base: import("@medusajs/framework/utils").MedusaServiceReturnType; environment: import("@medusajs/framework/utils").TextProperty; status: import("@medusajs/framework/utils").TextProperty; shared_id: import("@medusajs/framework/utils").NullableModifier; auth_code: import("@medusajs/framework/utils").NullableModifier; seller_client_id: import("@medusajs/framework/utils").NullableModifier; seller_client_secret: import("@medusajs/framework/utils").NullableModifier; seller_merchant_id: import("@medusajs/framework/utils").NullableModifier; seller_email: import("@medusajs/framework/utils").NullableModifier; app_access_token: import("@medusajs/framework/utils").NullableModifier; app_access_token_expires_at: import("@medusajs/framework/utils").NullableModifier; metadata: import("@medusajs/framework/utils").JSONProperty; }>, "paypal_connection">; readonly PayPalMetric: import("@medusajs/framework/utils").DmlEntity; name: import("@medusajs/framework/utils").TextProperty; data: import("@medusajs/framework/utils").JSONProperty; }>, "paypal_metric">; readonly PayPalSettings: import("@medusajs/framework/utils").DmlEntity; data: import("@medusajs/framework/utils").NullableModifier, import("@medusajs/framework/utils").JSONProperty>; }>, "paypal_settings">; readonly PayPalWebhookEvent: import("@medusajs/framework/utils").DmlEntity; event_id: import("@medusajs/framework/utils").TextProperty; event_type: import("@medusajs/framework/utils").TextProperty; event_version: import("@medusajs/framework/utils").NullableModifier; transmission_id: import("@medusajs/framework/utils").NullableModifier; transmission_time: import("@medusajs/framework/utils").NullableModifier; status: import("@medusajs/framework/utils").TextProperty; attempt_count: import("@medusajs/framework/utils").NumberProperty; next_retry_at: import("@medusajs/framework/utils").NullableModifier; processed_at: import("@medusajs/framework/utils").NullableModifier; last_error: import("@medusajs/framework/utils").NullableModifier; resource_id: import("@medusajs/framework/utils").NullableModifier; payload: import("@medusajs/framework/utils").JSONProperty; }>, "paypal_webhook_event">; }>>; /** * Application-container service for the PayPal module. * * Owns the merchant's PayPal connection (partner onboarding, seller * credentials, cached app access token), the plugin settings singleton, * webhook registration/event records, metrics, and audit logging. The payment * providers run in the isolated payment-module container and therefore read * the same tables through `PayPalCredentialResolver` instead of this service. */ declare class PayPalModuleService extends PayPalModuleService_base { protected cfg: import("./types/config").PayPalModuleConfig; private tokenRefreshPromise; private pgForMetrics; private webhookUrlMigrationChecked; private webhookHealScheduled; constructor(...args: any[]); private get bnCode(); private getSettingsData; private ensureSettingsDefaults; /** * Onboarding + API-detail settings with plugin defaults filled in (and * persisted) for any key that is still unset. */ getApiDetails(): Promise<{ onboarding: Record; apiDetails: Record; }>; private getAlertWebhookUrls; private getPartnerMerchantId; private getCurrentRow; private getCurrentEnvironment; private getEnvCreds; private extractSellerEmail; private fetchMerchantIntegrationDetails; private getAppAccessTokenForCredentials; private fetchSellerProfileFromDirectCredentials; private hydrateSellerMetadataFromCredentials; private syncRowFieldsFromMetadata; /** * Switch the active environment (`sandbox` | `live`). Credentials are stored * per environment, so switching never discards the other environment's * credentials — it only changes which set is active and clears the cached * app token. */ setEnvironment(env: Environment): Promise; /** * Request a PayPal partner-referral onboarding URL from the partner service. * Returns the URL to open in PayPal's mini-browser plus the `return_url` the * popup lands on afterwards. */ createOnboardingLink(input?: { email?: string; products?: string[]; env?: Environment; }): Promise<{ onboarding_url: string; return_url: string; }>; /** Mark the connection as onboarding-in-progress (creates the row if needed). */ startOnboarding(): Promise; /** Persist the `authCode`/`sharedId` PayPal hands back after onboarding. */ saveOnboardCallback(input: { authCode: string; sharedId: string; }): Promise<{ id: string; environment: string; status: string; shared_id: string | null; auth_code: string | null; seller_client_id: string | null; seller_client_secret: string | null; seller_merchant_id: string | null; seller_email: string | null; app_access_token: string | null; app_access_token_expires_at: Date | null; metadata: Record; created_at: Date; updated_at: Date; deleted_at: Date | null; }>; /** * Complete partner onboarding: exchange the single-use `authCode` for a * seller access token, fetch the seller's REST credentials, and store them. * Idempotent — a repeated exchange of an already-consumed code is a no-op * when credentials for that environment are already saved. */ exchangeAndSaveSellerCredentials(input: { authCode: string; sharedId: string; env?: "sandbox" | "live"; }): Promise; /** * Store seller REST credentials for an environment (encrypted at rest when * `PAYPAL_ENCRYPTION_KEY` is set) and make sure a webhook is registered. */ saveSellerCredentials(input: { clientId: string; clientSecret: string; sellerMerchantId?: string | null; sellerEmail?: string | null; environment?: Environment; }): Promise<{ id: string; environment: string; status: string; shared_id: string | null; auth_code: string | null; seller_client_id: string | null; seller_client_secret: string | null; seller_merchant_id: string | null; seller_email: string | null; app_access_token: string | null; app_access_token_expires_at: Date | null; metadata: Record; created_at: Date; updated_at: Date; deleted_at: Date | null; }>; /** * Save manually-entered credentials, then best-effort look up the seller's * merchant id / email from PayPal so the admin UI can display them. */ saveAndHydrateSellerCredentials(input: { clientId: string; clientSecret: string; environment?: Environment; }): Promise<{ environment: Environment; status: Status; seller_client_id_present: boolean; shared_id?: undefined; auth_code?: undefined; seller_client_id_masked?: undefined; seller_client_secret_masked?: undefined; seller_merchant_id?: undefined; seller_email?: undefined; updated_at?: undefined; } | { environment: Environment; status: Status; shared_id: any; auth_code: string | null; seller_client_id_present: boolean; seller_client_id_masked: string | null; seller_client_secret_masked: string | null; seller_merchant_id: string | null; seller_email: string | null; updated_at: any; }>; private resolveWebhookUrl; /** Legacy webhook path (blocked by Medusa's store publishable-key guard). */ private resolveLegacyWebhookUrl; private isLocalWebhookUrl; private migrateLegacyWebhookUrl; private ensureWebhookRegistration; private maskValue; /** * Report the current connection status. * * `hydrateMissingProfile` is opt-in and OFF by default: status is read on * `GET /admin/paypal/status` (and other read-only routes), where it must be a * safe, side-effect-free read. The seller-profile backfill makes an outbound * PayPal call and persists to the DB, so it only runs from write contexts * (e.g. saving credentials) that explicitly request it. */ getStatus(envOverride?: Environment, opts?: { hydrateMissingProfile?: boolean; }): Promise<{ environment: Environment; status: Status; seller_client_id_present: boolean; shared_id?: undefined; auth_code?: undefined; seller_client_id_masked?: undefined; seller_client_secret_masked?: undefined; seller_merchant_id?: undefined; seller_email?: undefined; updated_at?: undefined; } | { environment: Environment; status: Status; shared_id: any; auth_code: string | null; seller_client_id_present: boolean; seller_client_id_masked: string | null; seller_client_secret_masked: string | null; seller_merchant_id: string | null; seller_email: string | null; updated_at: any; }>; /** * Remove the active environment's credentials. The other environment (if * connected) is untouched, so the row stays "connected" when it still holds * a usable credential set. */ disconnect(): Promise; /** * Cached client-credentials access token for the active environment. * Refreshes single-flight when the stored token is within two minutes of * expiry so concurrent callers never race to mint duplicate tokens. */ getAppAccessToken(): Promise; private refreshAccessToken; /** Mint a browser `client_token` (required by the hosted card fields SDK). */ generateClientToken(opts?: { locale?: string; }): Promise; /** The plugin settings singleton (`{ data }`), never null. */ getSettings(): Promise<{ data: Record; }>; private deepMerge; /** Deep-merge `patch` into the settings singleton and return the result. */ saveSettings(patch: Record): Promise<{ data: Record; }>; /** Decrypted REST credentials for the active environment; throws if unset. */ getActiveCredentials(): Promise<{ environment: Environment; client_id: string; client_secret: string; }>; /** Fetch a PayPal order (`GET /v2/checkout/orders/{id}`). */ getOrderDetails(orderId: string): Promise; /** * Insert a webhook event row. Returns `{ created: false, event }` instead of * throwing when `event_id` already exists, so the webhook route can treat a * redelivery as a duplicate. */ createWebhookEventRecord(input: { event_id: string; event_type: string; resource_id?: string | null; payload?: Record; event_version?: string | null; transmission_id?: string | null; transmission_time?: Date | null; status?: string; attempt_count?: number; }): Promise<{ created: boolean; event: { id: string; event_id: string; event_type: string; event_version: string | null; transmission_id: string | null; transmission_time: Date | null; status: string; attempt_count: number; next_retry_at: Date | null; processed_at: Date | null; last_error: string | null; resource_id: string | null; payload: Record; created_at: Date; updated_at: Date; deleted_at: Date | null; }; }>; /** Update processing state on a webhook event row. */ updateWebhookEventRecord(input: { id: string; status?: string; attempt_count?: number; next_retry_at?: Date | null; processed_at?: Date | null; last_error?: string | null; resource_id?: string | null; }): Promise<{ id: string; event_id: string; event_type: string; event_version: string | null; transmission_id: string | null; transmission_time: Date | null; status: string; attempt_count: number; next_retry_at: Date | null; processed_at: Date | null; last_error: string | null; resource_id: string | null; payload: Record; created_at: Date; updated_at: Date; deleted_at: Date | null; }>; /** * Emit an audit event as a single structured log line. * * The dedicated audit-log table was removed; for high-volume/containerized * deployments the audit trail lives in aggregated stdout logs. This records a * greppable `paypal_audit` line (filter on `"log":"paypal_audit"`) with * sensitive keys redacted. It never throws — audit logging must not break the * caller's payment flow. */ recordAuditEvent(eventType: string, metadata?: Record): Promise; /** * Increment a named counter in `paypal_metric`, merging any metadata. * Best-effort — never throws. */ recordMetric(name: string, metadata?: Record): Promise<{ id: string; name: string; data: Record; created_at: Date; updated_at: Date; deleted_at: Date | null; } | null>; /** Audit-log a payment event under the `payment_` prefix. */ recordPaymentLog(eventType: string, metadata?: Record): Promise; /** * POST an operational alert to every configured `PAYPAL_ALERT_WEBHOOK_URLS` * endpoint. Delivery results are audit-logged; failures never throw. */ sendAlert(input: { type: string; message: string; metadata?: Record; }): Promise; } export default PayPalModuleService; //# sourceMappingURL=service.d.ts.map