Skip to main content

Features, Merchants & Rates

Drop — Merchant, Recipients & Rates

Note (2026-02-14): This document predates the current architecture. Drop now uses a pass-through PSD2 model (PISP/AISP) — Drop NEVER holds customer money. Some sections below reference wallet/balance concepts from the earlier BaaS design. The current architecture is defined in architecture-document.md and Drop CLAUDE.md.

1. Recipients

Data Model

interface Contact {
  id: string;
  name: string;
  iban: string;
  avatar: string;  // 2-char initials
}

Current Implementation

Sample contacts (hardcoded in src/app/send/page.tsx):

Name IBAN Country
Sara M. DE89370400440532013000 Germany
Amir K. FR7630006000011234567890189 France
Lejla H. AT611904300234573201 Austria

Mock contacts (src/lib/mockData.ts):

Name IBAN Country
John Doe DE89 3704 0044 0532 0130 00 Germany
Jane Smith FR76 3000 6000 0112 3456 7890 189 France
Mike Wilson GB29 NWBK 6016 1331 9268 19 UK

RecipientStep UI (src/app/send/page.tsx)

  • Search bar (filters by name or IBAN)
  • Contact list with avatar, name, truncated IBAN
  • "Add new recipient" button (placeholder — not wired)
  • Click to select → moves to AmountStep

Send Money Flow (6 steps)

RecipientStep → AmountStep → ConfirmStep → Processing → Success/Error
  1. Recipient — select from contacts or search
  2. Amount — input + quick buttons (€10, €50, €100, €200) + optional note
  3. Confirm — review: amount, recipient, IBAN, note, fee (Free)
  4. Processing — loading animation
  5. Success — confirmation with amount and name
  6. Error — message + retry

API: Send Money

POST /api/transactions
Authorization: Bearer <jwt>
Body: { toIban: string, amount: number, reference?: string }

Validations:

  • Required: toIban, amount
  • amount > 0
  • Balance sufficient
  • Creates SepaCredit transaction with direction Debit
  • Updates account balance atomically

Future (not yet implemented)

  • Add/edit/delete saved recipients
  • Favorite/frequent contacts
  • Import from phone contacts (mobile app)
  • Recipient groups

2. Merchant Payments

Current State: Demo Only

Merchant payments exist as:

  • CardTransaction type in schema
  • simulatePurchase() method in AppContext (no-op, logs to console)
  • Demo buttons on dashboard: "Netflix €9.99", "Groceries €45"

Transaction Types

Type Direction Use Case
SepaCredit Debit Outgoing SEPA transfer
SepaDebit Credit Incoming SEPA transfer
CardTransaction Debit Card purchase at merchant

AppContext Method

const simulatePurchase = async (amount: number, merchant: string) => {
  // No-op — no API route for card purchases yet
  console.log("[AppContext] simulatePurchase not implemented:", { amount, merchant });
  return { id: 'demo_auth', amount, merchant };
};

Stripe Issuing Mock (src/lib/services/mock-stripe.ts)

Card authorization logic:

  • Checks card status (active)
  • Checks spending limit (spending_limit vs spent_this_month + amount)
  • Returns approved/declined
  • Physical card ordering supported

Transaction Display (src/components/TransactionItem.tsx)

Shows for each transaction:

  • Icon (emoji for type)
  • Description (merchant name or counterparty)
  • Date (formatted)
  • Amount (green for incoming, gray for outgoing)

Future (post-MVP)

  • Merchant directory/discovery
  • Bill pay integration
  • Recurring payments to merchants
  • Purchase categorization (AI)
  • Merchant notifications

3. Rates, Fees & Limits

Currency

MVP: EUR only (single account)

Formatting (src/lib/mockData.ts):

formatCurrency(amount, currency = "EUR")
// Uses Intl.NumberFormat("de-DE") → "€1.234,56"

Fees

Transaction Type Fee
SEPA transfer Free
Card top-up Free
Card payment Free (interchange 0.2-0.3% from merchant)

All transfers show "Free" in the UI confirmation step.

Transfer Limits (from MVP spec)

Type Daily Monthly
Internal P2P €5,000 €20,000
SEPA €2,000 €10,000

Top-up Limits

Parameter Value
Minimum €5
Maximum €10,000
Preset options €20, €50, €100, €200, €500

Card Spending

Parameter Value
Monthly limit (default) €5,000
Tracked via spent_this_month column

Revenue Model (post-MVP)

Stream Rate
Interchange fees 0.2-0.3% of card transactions
FX markup 0.5-2% on currency conversion
Premium subscription €5-15/month
Interest income On deposits
Lending Personal loans, BNPL, overdrafts

Multi-Currency (Future)

  • Additional currency accounts (GBP, USD, etc.)
  • Real-time FX rates display
  • FX conversion with 0.5-2% markup
  • Currency selection at transfer time

4. Database Schema Reference

transactions

CREATE TABLE transactions (
  id TEXT PRIMARY KEY,
  account_id TEXT NOT NULL REFERENCES accounts(id),
  type TEXT NOT NULL,        -- SepaCredit | SepaDebit | CardTransaction
  amount REAL NOT NULL,
  currency TEXT DEFAULT 'EUR',
  direction TEXT NOT NULL,   -- Credit | Debit
  status TEXT DEFAULT 'Pending',  -- Pending | Booked | Rejected
  counterparty TEXT,         -- Recipient IBAN or merchant name
  reference TEXT,            -- Payment note
  created_at TEXT DEFAULT (datetime('now'))
);

accounts

CREATE TABLE accounts (
  id TEXT PRIMARY KEY,
  user_id TEXT NOT NULL REFERENCES users(id),
  iban TEXT UNIQUE NOT NULL,   -- Format: BA393912XXXXXXXX
  bic TEXT DEFAULT 'FONLBA22',
  currency TEXT DEFAULT 'EUR',
  balance REAL DEFAULT 0,
  status TEXT DEFAULT 'Opened',
  created_at TEXT DEFAULT (datetime('now'))
);

cards

CREATE TABLE cards (
  id TEXT PRIMARY KEY,
  user_id TEXT NOT NULL REFERENCES users(id),
  type TEXT NOT NULL DEFAULT 'virtual',
  brand TEXT DEFAULT 'Visa',
  last4 TEXT NOT NULL,
  exp_month INTEGER NOT NULL,
  exp_year INTEGER NOT NULL,
  status TEXT DEFAULT 'active',
  spending_limit REAL DEFAULT 5000,
  spent_this_month REAL DEFAULT 0,
  cardholder_name TEXT,
  created_at TEXT DEFAULT (datetime('now'))
);

5. Open Tasks (Related)

Task Priority Description
#191 HIGH Wire /send page to /api/transactions/remittance
#192 HIGH Wire /scan page to /api/transactions/qr-payment
#193 HIGH Wire /merchant page to real APIs
#198 LOW Delete mock-data.ts and orphaned components