Skip to content

Latest commit

 

History

History
711 lines (570 loc) · 14.4 KB

File metadata and controls

711 lines (570 loc) · 14.4 KB

PattPay API Endpoints Documentation

📋 Overview

This document outlines the essential API endpoints for PattPay's MVP backend implementation. The API serves a Web3 payment gateway built on Solana, enabling recurring payments and subscription management.

Target Customers

  • Content Creators: Manage fan subscriptions
  • Web3 SaaS Companies: Automate billing cycles
  • DAOs & Projects: Collect recurring contributions
  • Freelancers: Create payment links for services

🔐 Authentication & User Management

Dual Authentication System

PattPay supports two authentication methods that are mutually exclusive:

  • Traditional: Email/Password authentication
  • Web3: Solana wallet (Phantom) authentication

Users must choose one method during registration and cannot switch between them.

Authentication Endpoints

POST /api/auth/register
POST /api/auth/login
POST /api/auth/solana-signin-data
POST /api/auth/solana-verify
GET  /api/auth/me

Traditional Email/Password Authentication

User Registration (Email/Password)

POST /api/auth/register
Content-Type: application/json

{
  "authMethod": "email_password",
  "email": "user@example.com",
  "password": "securePassword123",
  "name": "John Doe"
}

Response: {
  "user": {
    "id": "uuid",
    "email": "user@example.com",
    "name": "John Doe",
    "authMethod": "email_password",
    "createdAt": "ISO8601"
  },
  "token": "jwt_token"
}

User Login (Email/Password)

POST /api/auth/login
Content-Type: application/json

{
  "authMethod": "email_password",
  "email": "user@example.com",
  "password": "securePassword123"
}

Response: {
  "user": User,
  "token": "jwt_token"
}

Web3 Solana Wallet Authentication (SIWS Standard)

Get Sign-In Data

POST /api/auth/solana-signin-data
Content-Type: application/json

{
  "walletAddress": "9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM"
}

Response: {
  "signInData": {
    "domain": "pattpay.com",
    "statement": "Please sign this message to authenticate with PattPay.",
    "version": "1",
    "nonce": "random_nonce_string",
    "chainId": "mainnet",
    "issuedAt": "2025-01-18T10:30:00.000Z",
    "resources": ["https://pattpay.com"]
  }
}

Verify Sign-In Output

POST /api/auth/solana-verify
Content-Type: application/json

{
  "signInData": {
    "domain": "pattpay.com",
    "statement": "Please sign this message to authenticate with PattPay.",
    "version": "1",
    "nonce": "random_nonce_string",
    "chainId": "mainnet",
    "issuedAt": "2025-01-18T10:30:00.000Z",
    "resources": ["https://pattpay.com"]
  },
  "signInOutput": {
    "account": {
      "address": "9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM",
      "publicKey": "base64_encoded_public_key"
    },
    "signature": "base64_encoded_signature"
  },
  "name": "John Doe" // Optional, for first-time users
}

Response: {
  "user": {
    "id": "uuid",
    "walletAddress": "9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM",
    "name": "John Doe",
    "authMethod": "solana_wallet",
    "createdAt": "ISO8601"
  },
  "token": "jwt_token"
}

Get Current User

GET /api/auth/me
Authorization: Bearer <token>

Response: {
  "user": {
    "id": "uuid",
    "email": "user@example.com", // Only for email_password users
    "walletAddress": "9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM", // Only for solana_wallet users
    "name": "John Doe",
    "authMethod": "email_password" | "solana_wallet",
    "createdAt": "ISO8601"
  }
}

Authentication Flow Examples

Email/Password Flow

  1. User fills registration form with email/password
  2. Backend creates user with authMethod: "email_password"
  3. User logs in with email/password
  4. Backend verifies credentials and issues JWT

Solana Wallet Flow (SIWS Standard)

  1. User connects Phantom wallet
  2. Frontend requests sign-in data from /api/auth/solana-signin-data
  3. User signs SIWS message with wallet using wallet.signIn(signInData)
  4. Frontend sends signInData and signInOutput to /api/auth/solana-verify
  5. Backend verifies using verifySignIn(signInData, signInOutput) and issues JWT

Security Considerations

  • Users cannot authenticate with different method than their registration method
  • Solana signatures are verified using @solana/wallet-standard-util with SIWS standard
  • Passwords are hashed using bcrypt with salt rounds
  • JWT tokens expire after 24 hours
  • Rate limiting: 5 attempts/minute per IP for auth endpoints
  • SIWS nonce prevents replay attacks
  • Domain validation ensures requests come from authorized sources

🔗 Payment Links Management (Core Feature)

Link Operations

GET    /api/links
POST   /api/links
GET    /api/links/:id
PUT    /api/links/:id
DELETE /api/links/:id

List Payment Links

GET /api/links?page=1&limit=20&status=active&isRecurring=all
Authorization: Bearer <token>

Query Parameters:
- page: number (default: 1)
- limit: number (default: 20, max: 100)
- status: 'active' | 'inactive' | 'all'
- isRecurring: boolean | 'all'
- search: string (name or URL)
- datePreset: 'last-7-days' | 'last-30-days' | 'last-90-days' | 'custom'

Response: {
  "links": CheckoutLink[],
  "pagination": {
    "page": number,
    "limit": number,
    "total": number,
    "totalPages": number
  },
  "stats": {
    "totalActive": number,
    "totalCreated": number,
    "averageConversion": number,
    "totalRevenue": number,
    "totalRevenueUSD": number
  }
}

Create Payment Link

POST /api/links
Authorization: Bearer <token>
Content-Type: application/json

{
  "name": "string",
  "description": "string?",
  "amount": number, // SOL
  "amountUSD": number,
  "isRecurring": boolean,
  "redirectUrl": "string?",
  "expiresAt": "ISO8601?",
  "maxUses": number?
}

Response: {
  "link": CheckoutLink,
  "url": "string" // Full checkout URL
}

Update Payment Link

PUT /api/links/:id
Authorization: Bearer <token>
Content-Type: application/json

{
  "name": "string?",
  "description": "string?",
  "amount": number?,
  "amountUSD": number?,
  "status": "active" | "inactive",
  "redirectUrl": "string?",
  "expiresAt": "ISO8601?",
  "maxUses": number?
}

Response: {
  "link": CheckoutLink
}

Delete Payment Link

DELETE /api/links/:id
Authorization: Bearer <token>

Response: {
  "success": true,
  "message": "Link deleted successfully"
}

💳 Payment Flows

PattPay supports two payment flows:

  1. Recurring Subscriptions - POST /api/subscribe
  2. One-Time Payments - POST /api/payment-executions

📖 For detailed implementation guide, see PAYMENT_FLOWS.md

Quick Reference

Recurring Subscription:

POST /api/subscribe (Public endpoint)

One-Time Payment:

POST /api/payment-executions (Public endpoint)

View Payment History (Merchant only):

GET /api/payment-executions (Authenticated)
GET /api/payment-executions/:id (Authenticated)

💳 Payments Management (Legacy)

Payment Operations

GET    /api/payments
GET    /api/payments/:id

List Payments

GET /api/payments?page=1&limit=20&status=success&datePreset=last-30-days
Authorization: Bearer <token>

Query Parameters:
- page: number (default: 1)
- limit: number (default: 20, max: 100)
- status: 'success' | 'pending' | 'failed' | 'all'
- datePreset: 'last-7-days' | 'last-30-days' | 'last-90-days' | 'custom'
- dateFrom: ISO8601 (if custom)
- dateTo: ISO8601 (if custom)
- amountMin: number
- amountMax: number
- search: string (hash or wallet)

Response: {
  "payments": Payment[],
  "pagination": {
    "page": number,
    "limit": number,
    "total": number,
    "totalPages": number
  },
  "stats": {
    "totalToday": number,
    "volumeToday": number,
    "volumeTodayUSD": number,
    "averageTicket": number,
    "averageTicketTrend": number
  }
}

Payment Details

GET /api/payments/:id
Authorization: Bearer <token>

Response: {
  "payment": Payment,
  "relatedTransactions": Transaction[],
  "link": CheckoutLink | null
}

🔄 Subscriptions Management

Subscription Operations

GET    /api/subscriptions
GET    /api/subscriptions/:id
PUT    /api/subscriptions/:id/cancel

List Subscriptions

GET /api/subscriptions?page=1&limit=20&status=active&datePreset=last-30-days
Authorization: Bearer <token>

Query Parameters:
- page: number (default: 1)
- limit: number (default: 20, max: 100)
- status: 'active' | 'cancelled' | 'expired' | 'all'
- datePreset: 'last-7-days' | 'last-30-days' | 'last-90-days' | 'custom'
- amountMin: number
- amountMax: number
- search: string (payer name, wallet, plan name)
- tokenMint: string (USDT, USDC, etc.)

Response: {
  "subscriptions": Subscription[],
  "pagination": {
    "page": number,
    "limit": number,
    "total": number,
    "totalPages": number
  },
  "stats": {
    "activeSubscriptions": number,
    "mrr": number,
    "mrrUSD": number,
    "arr": number,
    "arrUSD": number,
    "arrTrend": number,
    "newSubscriptions": number,
    "cancelledSubscriptions": number
  }
}

Subscription Details

GET /api/subscriptions/:id
Authorization: Bearer <token>

Response: {
  "subscription": Subscription,
  "plan": Plan,
  "payer": Payer,
  "paymentHistory": PaymentExecution[],
  "nextPayment": {
    "dueAt": "ISO8601",
    "amount": number,
    "amountUSD": number
  }
}

Cancel Subscription

PUT /api/subscriptions/:id/cancel
Authorization: Bearer <token>
Content-Type: application/json

{
  "reason": "string?" // Optional cancellation reason
}

Response: {
  "subscription": Subscription,
  "cancelledAt": "ISO8601"
}

🏠 Dashboard & Analytics

Dashboard Overview

GET /api/dashboard/overview
GET /api/dashboard/charts/transactions
GET /api/dashboard/charts/mrr

Dashboard Overview

GET /api/dashboard/overview
Authorization: Bearer <token>

Response: {
  "stats": {
    "activeSubscriptions": number,
    "totalRevenue": number, // SOL
    "totalRevenueUSD": number,
    "paymentsToday": number,
    "mrr": number, // Monthly Recurring Revenue
    "mrrUSD": number
  },
  "recentTransactions": Payment[],
  "activeLinks": CheckoutLink[]
}

Transaction Charts

GET /api/dashboard/charts/transactions?period=30d
Authorization: Bearer <token>

Response: {
  "data": [
    {
      "date": "YYYY-MM-DD",
      "volume": number, // SOL
      "volumeUSD": number,
      "count": number,
      "change": number // % change
    }
  ]
}

MRR Charts

GET /api/dashboard/charts/mrr?period=30d
Authorization: Bearer <token>

Response: {
  "data": [
    {
      "date": "YYYY-MM-DD",
      "mrr": number, // SOL
      "mrrUSD": number,
      "change": number // % change
    }
  ]
}

🔧 System & Health

System Operations

GET /api/health

Health Check

GET /api/health

Response: {
  "status": "healthy" | "degraded" | "unhealthy",
  "timestamp": "ISO8601",
  "services": {
    "database": "healthy" | "degraded" | "unhealthy",
    "solana": "healthy" | "degraded" | "unhealthy"
  },
  "version": "string"
}

📊 Data Types

Core Types

interface User {
  id: string;
  name: string;
  authMethod: "email_password" | "solana_wallet";
  email?: string; // Only for email_password users
  walletAddress?: string; // Only for solana_wallet users
  createdAt: string;
  updatedAt: string;
}

interface Payment {
  id: string;
  hash: string;
  amount: number; // SOL
  amountUSD: number;
  status: "success" | "pending" | "failed";
  from: string;
  to: string;
  linkId?: string;
  linkName?: string;
  block: number;
  confirmations: number;
  fee: number;
  createdAt: string;
  confirmedAt?: string;
}

interface CheckoutLink {
  id: string;
  name: string;
  amount: number; // SOL
  amountUSD: number;
  status: "active" | "inactive";
  url: string;
  isRecurring: boolean;
  redirectUrl?: string;
  description?: string;
  createdAt: string;
  totalPayments: number;
  conversions: number;
  views: number;
}

interface Subscription {
  id: string;
  planId: string;
  payerId: string;
  payerName: string;
  payerWallet: string;
  planName: string;
  planDescription?: string;
  tokenMint: string;
  tokenDecimals: number;
  amount: number;
  amountUSD: number;
  status: "active" | "cancelled" | "expired";
  nextDueAt: string;
  lastPaidAt: string;
  totalApprovedAmount: number;
  durationMonths: number;
  periodSeconds: number;
  createdAt: string;
  updatedAt: string;
}

interface Plan {
  id: string;
  receiverId: string;
  name: string;
  description?: string;
  durationMonths: number;
  periodSeconds: number;
  createdAt: string;
  updatedAt: string;
}

interface Receiver {
  id: string;
  walletAddress: string;
  name: string;
  description?: string;
  tokenAccountUSDT: string;
  tokenAccountUSDC: string;
  createdAt: string;
  updatedAt: string;
}

🔒 Security & Rate Limiting

Authentication

  • All endpoints (except health checks) require JWT authentication
  • JWT tokens expire after 24 hours
  • Wallet signature verification for registration/login

Rate Limiting

  • General API: 1000 requests/hour per user
  • Payment Operations: 100 requests/hour per user
  • Authentication: 5 attempts/minute per IP

CORS & Headers

Access-Control-Allow-Origin: https://pattpay.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: Authorization, Content-Type
Access-Control-Max-Age: 86400

🚀 Implementation Priority

Phase 1 (MVP Core - Week 1)

  1. Authentication - User registration/login with wallet
  2. Payment Links - CRUD operations for payment links
  3. Payments - List, filter, and view payment details

Phase 2 (Extended Features - Week 2)

  1. Subscriptions - Full subscription management
  2. Dashboard - Overview stats and charts
  3. Health - System monitoring endpoints

📝 Notes

  • All timestamps are in ISO 8601 format
  • All monetary amounts are in SOL (with USD equivalents)
  • Pagination uses page-based approach (not cursor-based)
  • All endpoints return consistent error format
  • Database uses PostgreSQL with Prisma ORM
  • Smart contracts are deployed on Solana mainnet/devnet
  • Rate limiting implemented with Redis

Next Steps: Begin implementation with Phase 1 endpoints, starting with authentication and payment links.