Skip to main content

Services

Drop External Services

Source: src/drop-app/src/lib/services/

Overview

Drop uses a PSD2 pass-through model — it never holds customer money. AISP reads bank balances via Open Banking, PISP initiates payments from the user's own bank account.

Drop integrates with three external service providers. AllEach areservice currentlyhas a different readiness level — see status tags below.

mock implementationsLegend: for[PRODUCTION] development= andreal testing.SDK, Productionproduction-ready. implementations[MOCK/DEV] require replacing= mock filesonly, withNOT connected to real SDKAPIs. integrations.[PLANNED] = future roadmap. [DEPRECATED] = no longer the chosen provider.

Service mode is controlled by NEXT_PUBLIC_SERVICE_MODE env var (default: mock).

Source: services/index.ts:21-30

export const config = {
  mode: (process.env.NEXT_PUBLIC_SERVICE_MODE || "mock") as "mock" | "production",
  endpoints: {
    swan: process.env.SWAN_API_URL || "https://api.swan.io",
    stripe: process.env.STRIPE_API_URL || "https://api.stripe.com",
    sumsub: process.env.SUMSUB_API_URL || "https://api.sumsub.com",
  },
};

Note on Swan: Swan was previously listed as the Open Banking provider but has been deprecated. The pass-through PSD2 model will use a different AISP/PISP provider (TBD).

Note on Stripe: Card issuing is a future feature gated behind feature flags. No Stripe SDK is integrated — only a mock file exists.

Note on Vipps/Nets: Sometimes mentioned in business discussions but have ZERO code in the codebase.


Swan — Open Banking / PSD2 Provider (FUTURE)[DEPRECATED]

Note:⚠️ InDEPRECATED: Swan is no longer the pass-throughplanned model,Open SwanBanking (orprovider. similarMock provider)code wouldremains servebut aswill thebe PSD2 AISP/PISP integration — reading bank balances and initiating payments from the user's own bank account. Drop does NOT use Swan for IBAN generation or balance management (no wallet model).removed.

File: services/mock-swan.ts Production docs: https://docs.swan.io/ Purpose:Status: FUTUREDEPRECATED mockOpenno Bankingproduction AISPintegration, (balanceno read)contract, +no PISPAPI (payment initiation). Currently mocked.keys.

Interfaces

Interface Description
SwanAccount Bank account with IBAN, BIC, balance, status
SwanTransaction SEPA credit/debit with status tracking

Functions

Function Signature Description
createAccount (userId) → SwanAccount Create new bank account with IBAN
getAccount (accountId) → SwanAccount | null Retrieve account details
getBalance (accountId) → {available, pending} Get balance breakdown
initiateTransfer ({fromAccountId, toIban, amount, ...}) → SwanTransaction Initiate SEPA credit transfer
simulateIncoming ({toAccountId, amount, fromIban}) → SwanTransaction Simulate incoming transfer
getTransactions (accountId, limit?) → SwanTransaction[] List recent transactions
onWebhook (callback) → void Register webhook listener

Mock Behavior

  • 200-800ms simulated latency per call
  • IBAN generated in BA format (Bosnia mock)
  • Transfers start as Pending, settle to Booked after 2 seconds
  • State persisted to localStorage (browser) or in-memory (server)
  • _testHelpers.reset() clears all mock data

Account Statuses

Opened | Closing | Closed

Transaction Types

SepaCredit | SepaDebit | CardTransaction

Transaction Statuses

Pending | Booked | Rejected


Stripe — Card Issuing (FUTURE — feature-flagged)[MOCK/DEV]

Note:⚠️ CardsMOCK areONLY: aNo FUTUREStripe feature,SDK gatedinstalled. behindMock featurefile flagsfor (allUI defaultdevelopment to false). Requires a card issuing partner before activation.only.

File: services/mock-stripe.ts Production docs: https://stripe.com/docs/issuing Purpose:Status: FUTUREMock implementation onlyVirtualno andreal physicalStripe cardAPI management,calls, authorizationno processingSDK, no API keys.

Interfaces

Interface Description
StripeCard Card with type, brand, status, spending limits
StripeCardDetails Full card number, CVC, expiry (virtual only)
StripeAuthorization Card authorization with merchant info

Functions

Function Signature Description
createVirtualCard ({cardholderName, spendingLimit?}) → StripeCard Issue virtual Visa card
orderPhysicalCard ({cardholderName, shippingAddress}) → StripeCard Order physical card
getCardDetails (cardId) → StripeCardDetails Get full card details (virtual only)
setCardStatus (cardId, active) → StripeCard Freeze/unfreeze card
updateSpendingLimit (cardId, limit) → StripeCard Update spending limit
getCards () → StripeCard[] List all cards
simulateAuthorization ({cardId, amount, merchant}) → StripeAuthorization Simulate card purchase
getAuthorizations (cardId?) → StripeAuthorization[] List authorizations

Mock Behavior

  • Virtual cards created instantly with active status, expire in 3 years
  • Physical cards start as pending, activate after 5 seconds (simulating shipping)
  • Default spending limit: 5,000 (virtual), 10,000 (physical)
  • Authorization declined if: card not active OR spending limit exceeded
  • Brand is always Visa
  • Mock card numbers: 4242 4242 4242 {last4}

Card Statuses

active | inactive | canceled | pending

Authorization Statuses

pending | approved | declined


Sumsub — KYC/Identity Verification [PRODUCTION]

✅ PRODUCTION-READY: Sumsub is the only external service with real production API integration.

File: services/mock-sumsub.ts Production docs: https://docs.sumsub.com/ Purpose:Status: UserProduction-ready identity verification,real documentAPI submission,calls, livenessWebSDK checksintegration, webhook handling.

Interfaces

Interface Description
SumsubApplicant KYC applicant with review status
SumsubDocument Identity document (passport, ID card, etc.)
SumsubVerificationResult Verification outcome with per-check breakdown

Functions

Function Signature Description
createApplicant ({externalUserId, email?, phone?}) → SumsubApplicant Create KYC applicant
getAccessToken (applicantId) → {token, expiresAt} Get WebSDK token (30min)
submitDocument (applicantId, document) → void Submit ID document
submitSelfie (applicantId, selfieData) → void Submit selfie for liveness
getApplicantStatus (applicantId) → SumsubApplicant Check applicant status
getVerificationResult (applicantId) → SumsubVerificationResult Get verification details
forceApprove (applicantId) → void Force approve (testing only)
onWebhook (callback) → void Register webhook listener

Mock Behavior

  • Verification completes after 3-second delay
  • 90% approval rate in mock mode
  • Risk score: 15 (approved) or 85 (rejected)
  • Rejected with label DOCUMENT_UNREADABLE, type RETRY

Applicant Statuses

init | pending | queued | completed | onHold

Review Answers

GREEN (approved) | RED (rejected) | RETRY

Verification Checks

Check Description
documentAuthenticity Document is genuine
livenessCheck Selfie is a real person
facematch Selfie matches document photo
sanctionsCheck Not on sanctions lists
pepCheck Not a politically exposed person

Document Types

PASSPORT | ID_CARD | DRIVERS | RESIDENCE_PERMIT


Service Initialization

Source: services/index.ts:36-48

// Call on app startup
await initializeServices();

// Reset all mocks (testing)
resetMockServices();

Service Status Summary

ServiceStatusDescription
Sumsub[PRODUCTION]Real API integration, WebSDK, webhook handling — READY
Stripe[MOCK/DEV]Mock file only for UI development — NO SDK, NO API keys
Swan[DEPRECATED]No longer the planned Open Banking provider — mock will be removed
Vipps[PLANNED]Future consideration — ZERO code currently
Nets[PLANNED]Future consideration — ZERO code currently

Important Notes

  1. AllSumsub is the ONLY production-ready service files are marked @deprecatedtheyall mustothers beare replacedmocks withor real SDK implementations before production.deprecated.
  2. Console warnings are emitted on module load for mock services to make mock usage visible.
  3. Mock state uses localStorage in browser, in-memory on server — resets on server restart.
  4. Production API endpoints are configurable via environment variables.
  5. The current backend API routes do NOT call these service modules directly — they use the database layer (db.ts) for all operations. The services are available for future integration when real providers are connected.