Skip to content

Latest commit

 

History

History
638 lines (452 loc) · 16.6 KB

File metadata and controls

638 lines (452 loc) · 16.6 KB

🚀 PassItOn API Reference

📖 Overview

The PassItOn platform provides RESTful APIs for managing organizations, support tickets, and donation widgets. All APIs use JSON for request and response bodies and require proper authentication.

🔐 Authentication

🎯 Clerk Authentication

Most endpoints require authentication via Clerk. Include the session token in requests:

// Client-side with Clerk React
const { getToken } = useAuth();
const token = await getToken();

fetch('/api/endpoint', {
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  }
});

🎣 Webhook Authentication

Webhook endpoints use signature verification:

  • Stripe webhooks: Verify stripe-signature header
  • Clerk webhooks: Verify with WEBHOOK_SECRET

🛠 Core APIs

👥 User Management

🔍 GET /api/users/me

Get current user profile and organization memberships.

Response:

{
  "id": "user_123",
  "email": "user@example.com",
  "name": "John Doe",
  "role": "owner",
  "organizations": [
    {
      "id": "org_123",
      "name": "My Organization",
      "role": "owner"
    }
  ]
}

✏️ PUT /api/users/[userId]/role

Update user role (Super Admin only).

Request:

{
  "role": "super_admin",
  "reason": "Platform administrator"
}

Response:

{
  "success": true,
  "user": {
    "id": "user_123",
    "role": "super_admin",
    "updated_at": "2025-01-29T00:00:00Z"
  }
}

🏢 Organization Management

🔍 GET /api/organizations

List organizations (Admin: all organizations, User: own organization).

Response:

{
  "organizations": [
    {
      "id": "org_123",
      "name": "My Organization",
      "email": "contact@myorg.com",
      "display_name": "My Organization",
      "created_at": "2025-01-29T00:00:00Z",
      "stripe_account_id": "acct_123",
      "stripe_onboarding_complete": true
    }
  ]
}

➕ POST /api/organizations

Create new organization.

Request:

{
  "name": "My Organization",
  "email": "contact@myorg.com",
  "display_name": "My Organization",
  "legal_name": "My Organization LLC",
  "terms_of_service_url": "https://myorg.com/terms"
}

Response:

{
  "id": "org_123",
  "name": "My Organization",
  "email": "contact@myorg.com",
  "display_name": "My Organization",
  "created_at": "2025-01-29T00:00:00Z"
}

🔍 GET /api/organizations/[orgId]

Get organization details.

✏️ PUT /api/organizations/[orgId]

Update organization details.

Request:

{
  "display_name": "Updated Organization Name",
  "email": "newemail@myorg.com",
  "terms_of_service_url": "https://myorg.com/terms"
}

🎨 Widget Management

🔍 GET /api/widgets

List widgets for organization.

Response:

{
  "widgets": [
    {
      "id": "widget_123",
      "name": "Main Donation Widget",
      "slug": "main-widget",
      "organization_id": "org_123",
      "is_active": true,
      "customization": {
        "primary_color": "#3b82f6",
        "button_text": "Donate Now"
      },
      "created_at": "2025-01-29T00:00:00Z"
    }
  ]
}

➕ POST /api/widgets

Create new widget.

Request:

{
  "name": "Main Donation Widget",
  "slug": "main-widget",
  "is_active": true,
  "customization": {
    "primary_color": "#3b82f6",
    "button_text": "Donate Now"
  }
}

🔍 GET /api/widgets/[widgetId]

Get widget details.

✏️ PUT /api/widgets/[widgetId]

Update widget.

🗑 DELETE /api/widgets/[widgetId]

Delete widget.

🎧 Support System

📧 POST /api/support/notify

Send support notification email.

Request:

{
  "organizationId": "org_123",
  "type": "technical_issue",
  "message": "Widget not loading on website",
  "userEmail": "user@example.com",
  "priority": "high"
}

🎣 Webhook Endpoints

💳 POST /api/webhooks/stripe

Handle Stripe webhook events.

Supported Events:

  • payment_intent.succeeded - Donation completed
  • checkout.session.completed - Checkout completed

Headers Required:

  • stripe-signature: Stripe webhook signature

👤 POST /api/webhooks/clerk

Handle Clerk user events.

Supported Events:

  • user.created - New user registered
  • user.updated - User profile updated
  • user.deleted - User account deleted

Headers Required:

  • svix-id, svix-timestamp, svix-signature: Clerk webhook headers

❌ Error Handling

📋 Error Response Format

{
  "error": "Error message",
  "code": "ERROR_CODE",
  "details": {
    "field": "validation error details"
  }
}

📊 Common HTTP Status Codes

  • 200 - Success
  • 201 - Created
  • 400 - Bad Request
  • 401 - Unauthorized
  • 403 - Forbidden
  • 404 - Not Found
  • 422 - Validation Error
  • 500 - Internal Server Error

🚨 Common Error Codes

  • INVALID_REQUEST - Request validation failed
  • UNAUTHORIZED - Authentication required
  • FORBIDDEN - Insufficient permissions
  • NOT_FOUND - Resource not found
  • VALIDATION_ERROR - Input validation failed
  • RATE_LIMITED - Too many requests

⚡ Rate Limiting

API endpoints are rate limited to ensure fair usage:

  • Authentication endpoints: 5 requests per minute
  • CRUD operations: 100 requests per minute
  • Webhook endpoints: 1000 requests per minute
  • Public widget endpoints: 10000 requests per minute

Rate limit headers are included in responses:

  • X-RateLimit-Limit: Maximum requests allowed
  • X-RateLimit-Remaining: Requests remaining in window
  • X-RateLimit-Reset: Time when limit resets (Unix timestamp)

📊 Data Models

🏢 Organization

interface Organization {
  id: string;
  name: string;
  display_name: string;
  legal_name?: string;
  email: string;
  stripe_account_id?: string;
  stripe_onboarding_complete: boolean;
  terms_of_service_url?: string;
  created_at: string;
  updated_at: string;
}

🎨 Widget

interface Widget {
  id: string;
  organization_id: string;
  name: string;
  slug: string;
  is_active: boolean;
  customization: {
    primary_color: string;
    button_text: string;
    // ... other customization options
  };
  created_at: string;
  updated_at: string;
}

🎧 Support Ticket

interface SupportTicket {
  id: string;
  organization_id: string;
  subject: string;
  description: string;
  category: 'technical' | 'general' | 'bug_report' | 'feature_request';
  priority: 'low' | 'medium' | 'high' | 'urgent';
  status: 'open' | 'in_progress' | 'waiting_response' | 'resolved' | 'closed';
  user_email: string;
  user_name: string;
  admin_response?: string;
  admin_user_id?: string;
  resolved_at?: string;
  created_at: string;
  updated_at: string;
}

💰 Donation

interface Donation {
  id: string;
  organization_id: string;
  widget_id: string;
  donor_name?: string;
  donor_email?: string;
  amount: number;
  currency: string;
  status: 'pending' | 'succeeded' | 'failed';
  stripe_payment_intent_id: string;
  message?: string;
  created_at: string;
  updated_at: string;
}

🔧 Integration Examples

🎨 Creating a Donation Widget

// 1. Create widget via API
const response = await fetch('/api/widgets', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    name: 'Main Donation Widget',
    slug: 'main-widget',
    is_active: true,
    customization: {
      primary_color: '#3b82f6',
      button_text: 'Donate Now'
    }
  })
});

const widget = await response.json();

// 2. Embed widget in website
const embedCode = `<script src="https://app.passiton.com/widget/${widget.slug}"></script>`;

💳 Processing Donation Webhooks

// Handle donation webhook
export async function POST(request) {
  const event = await stripe.webhooks.constructEvent(
    await request.text(),
    request.headers.get('stripe-signature'),
    process.env.STRIPE_WEBHOOK_SECRET
  );

  if (event.type === 'payment_intent.succeeded') {
    const paymentIntent = event.data.object;
    
    // Handle successful donation
    console.log('Payment succeeded:', paymentIntent.id);
  }

  return Response.json({ received: true });
}

🧪 Testing

📡 API Testing with curl

<div style="background: linear-gradient(135deg, #10b981 0%, #059669 100%); color: white; padding: 2rem; border-radius: 12px; margin-bottom: 2rem;">

<span style="font-size: 2.5rem; font-weight: 800;">📌 Get user organizations</span>

</div>
curl -X GET "http://localhost:3000/api/organizations" \
  -H "Authorization: Bearer $CLERK_TOKEN" \
  -H "Content-Type: application/json"

<div style="background: linear-gradient(135deg, #06b6d4 0%, #0891b2 100%); color: white; padding: 2rem; border-radius: 12px; margin-bottom: 2rem;">

<span style="font-size: 2.5rem; font-weight: 800;">💬 Create support ticket</span>

</div>
curl -X POST "http://localhost:3000/api/support/tickets" \
  -H "Authorization: Bearer $CLERK_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "subject": "Widget not loading",
    "description": "The donation widget is not appearing on our website",
    "category": "technical",
    "priority": "high"
  }'

🎣 Webhook Testing

<div style="background: linear-gradient(135deg, #8b5cf6 0%, #7c3aed 100%); color: white; padding: 2rem; border-radius: 12px; margin-bottom: 2rem;">

<span style="font-size: 2.5rem; font-weight: 800;">🧪 Test Stripe webhook locally</span>

</div>
stripe listen --forward-to localhost:3000/api/webhooks/stripe

<div style="background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%); color: white; padding: 2rem; border-radius: 12px; margin-bottom: 2rem;">

<span style="font-size: 2.5rem; font-weight: 800;">🧪 Trigger test events</span>

</div>
stripe trigger payment_intent.succeeded
stripe trigger checkout.session.completed

This API reference is automatically updated with each release. For the latest version, check the developer documentation at `/docs/future-developers/`.