Skip to content

Latest commit

 

History

History
801 lines (521 loc) · 16.5 KB

File metadata and controls

801 lines (521 loc) · 16.5 KB

PiazzaViva API Reference

Base URL: https://piazzaviva.it (or http://localhost:3000 in development)

All API routes live under /api/. Responses are JSON unless otherwise noted. Error responses follow the shape { error: string }.


Table of Contents


Authentication

PiazzaViva uses two authentication mechanisms:

Method Header/Cookie Used By
Session cookie pv_session (httpOnly) Browser clients (pages, internal APIs)
API key X-API-Key header Public API, cron jobs
Admin API key X-API-Key header Admin endpoints

Session cookies are set automatically on login/register and expire after 30 days.


Public API

Read-only endpoints for external integrations. Require X-API-Key header. Rate limited at 1000 req/hour per key.

GET /api/public/events

List published events with filtering and pagination.

Parameter Type Default Description
city string Filter by city name
category string Filter by category slug
from ISO date Start date (inclusive)
to ISO date End date (inclusive)
limit number 20 Results per page (max 100)
offset number 0 Pagination offset

Response:

{
  "data": [
    {
      "id": "clx...",
      "title": "Jazz in Piazza",
      "description": "...",
      "startDate": "2025-07-15T20:00:00.000Z",
      "endDate": null,
      "venue": "Piazza Saffi",
      "address": "Piazza Saffi, Forlì",
      "city": "Forlì",
      "category": "musica",
      "organizer": "Comune di Forlì",
      "price": null,
      "imageUrl": "https://...",
      "latitude": 44.222,
      "longitude": 12.041,
      "capacity": 500,
      "url": "https://piazzaviva.it/events/clx..."
    }
  ],
  "pagination": {
    "total": 42,
    "limit": 20,
    "offset": 0,
    "hasMore": true
  }
}

GET /api/public/venues

List venues with optional city filter.

Parameter Type Default Description
city string Filter by city name

Events

GET /api/events

List all events with optional category/date filters.

Parameter Type Description
category string Category slug filter
date string Date filter

Response: { events: EventRecord[], total: number }

POST /api/events

Create a new event. Emits event.created domain event.

Body:

{
  "title": "Concerto Jazz",
  "description": "Una serata di jazz...",
  "startDate": "2025-07-20T20:00:00Z",
  "venue": "Teatro Diego Fabbri",
  "address": "Corso Diaz 47, Forlì",
  "city": "Forlì",
  "category": "musica",
  "organizer": "Jazz Club Forlì",
  "organizerInfo": "Dal 1985...",
  "price": 15,
  "image": "concerto-jazz.jpg",
  "capacity": 300
}

Response: 201 { event: EventRecord }

GET /api/events/[id]

Get a single event by ID with full details.

POST /api/events/[id]/edit

Update an event. Requires session (organizer or admin).

POST /api/events/[id]/cancel

Cancel an event. Sets status to "cancelled" and emits event.cancelled (notifies all attendees via email).

POST /api/events/[id]/duplicate

Duplicate an event with a new start date.

GET /api/events/[id]/attendees

Get event attendance counts and attendee list (visible only).

GET /api/events/[id]/export

Export event as .ics calendar file.

GET /api/events/[id]/live

Server-Sent Events (SSE) endpoint for real-time event updates.

GET /api/events/[id]/photos

Get community-submitted photos for an event.

POST /api/events/[id]/photos

Upload a photo for an event. Requires session.

GET /api/events/[id]/memory

Get or generate a post-event memory (summary, photo highlights, stats).

GET /api/events/search

Full-text search for events.

Parameter Type Description
q string Search query

POST /api/events/views

Track event view/impression for analytics.


Auth

POST /api/auth

Handles login, register, and logout via the action field.

Login:

{ "action": "login", "email": "user@example.com", "password": "secret123" }

Register:

{ "action": "register", "email": "user@example.com", "password": "secret123", "name": "Mario Rossi" }

Logout:

{ "action": "logout" }

Responses:

  • Login/Register: { user: { id, email, name } } (sets pv_session cookie)
  • Logout: { ok: true } (clears cookie)

GET /api/auth

Get the currently authenticated user. Returns { user: null } if not logged in.

Response:

{
  "user": {
    "id": "clx...",
    "email": "user@example.com",
    "name": "Mario Rossi",
    "role": "organizer",
    "interests": "musica,cultura",
    "bio": "..."
  }
}

Attendance

POST /api/attendance

Toggle attendance (going/interested) for an event. Requires session.

Body:

{
  "eventId": "clx...",
  "type": "going",
  "visible": true,
  "groupSize": 3
}
  • If the same type already exists, removes the attendance (toggle off)
  • visible enables "who's going" display (only for going type)
  • groupSize clamped to 1–12

Tickets & Checkout

POST /api/tickets

Create a ticket for an event. Checks capacity. Applies 20% student discount.

Body:

{
  "eventId": "clx...",
  "name": "Mario Rossi",
  "email": "mario@example.com",
  "type": "student"
}

Ticket types: general | student (20% off) | group

Response: { ticket: { id, qrCode, price, status } }

POST /api/checkout

Create a Stripe Checkout session for a paid ticket.

Body:

{
  "eventId": "clx...",
  "eventTitle": "Concerto Jazz",
  "name": "Mario Rossi",
  "email": "mario@example.com",
  "type": "general",
  "price": 15
}

Response: { sessionId: "cs_...", url: "https://checkout.stripe.com/..." }

GET /api/tickets

Get tickets for the current user. Requires session.


Comments

GET /api/comments?eventId=...

Get threaded comments for an event.

POST /api/comments

Add a comment or reply. Requires session.

Body:

{
  "eventId": "clx...",
  "text": "Evento fantastico!",
  "parentId": "clx..."
}

Comments support 1 level of threading via parentId.


Calendar

GET /api/calendar

Generate or retrieve the user's calendar feed token. Requires session.

GET /api/calendar/feed/[token]

iCal feed of user's "going" events. No auth required (token-based).

Content-Type: text/calendar

GET /api/calendar/event/[id]

Download a single event as .ics file. Returns Google Calendar and Outlook URLs.


Venues

GET /api/venues

List all venues with event counts.

Parameter Type Description
city string Filter by city

POST /api/venues

Create a new venue. Validates coordinates.

POST /api/venues/claim

Claim a venue (sets status to pending). Requires session.

GET /api/venues/match

Find venues matching criteria (category, capacity, city). Scored by analytics.

POST /api/venues/extract

Extract and normalize venues from existing events (admin operation).

GET /api/venues/[id]/availability

Get venue weekly availability matrix.

PUT /api/venues/[id]/availability

Update venue availability. Requires venue ownership.


AI

All AI endpoints gracefully fall back to heuristic methods when OPENAI_API_KEY is not set.

POST /api/ai/classify

Classify an event into a category using AI.

Body: { title: string, description: string }

Response: { category: EventCategory, confidence: number }

POST /api/ai/enhance

AI-enhance an event description (Italian, engaging, with emoji).

Body: { title: string, description: string, venue: string }

Response: { enhanced: string, tokens: number }

POST /api/ai/search

Natural language event search (Italian/English).

Body: { query: string }

Response: { events: EventRecord[], interpretation: string }

POST /api/ai/translate

Translate event content between Italian and English.

Body: { text: string, targetLang: "en" | "it" }

Response: { translated: string }

POST /api/ai/copilot

Conversational AI assistant for event discovery.


Analytics

POST /api/analytics/track

Track a funnel event (impression, detail_view, rsvp_intent, ticket_start, payment_complete, check_in).

Body:

{
  "eventId": "clx...",
  "sessionId": "browser-session-id",
  "action": "detail_view",
  "channel": "whatsapp"
}

GET /api/analytics/funnel?eventId=...

Get conversion funnel data for an event (counts, drop-off rates, conversion rates per stage).

GET /api/analytics/organizer

Get aggregate analytics for the current organizer's events. Requires session.


Notifications

GET /api/notifications

Get notifications for the current user. Requires session.

Parameter Type Default Description
unread boolean false Only unread notifications

POST /api/notifications

Mark notification(s) as read.

Body: { id: string } or { markAllRead: true }

GET /api/notifications/preferences

Get notification preferences for the current user.

PUT /api/notifications/preferences

Update a notification preference.

Body:

{
  "channel": "email",
  "category": "events",
  "enabled": false,
  "frequency": "weekly"
}

Channels: email | push | in_app Categories: events | tickets | social | digest | reminders


Social

POST /api/social/follow

Follow or unfollow a target. Requires session.

Body:

{
  "targetType": "organizer",
  "targetId": "clx...",
  "action": "follow"
}

Target types: user | organizer | venue

GET /api/social/feed

Get social feed based on followed users/organizers/venues.

POST /api/scraper/social

Ingest a social signal from Telegram/WhatsApp for AI event extraction.


Demand & Waitlist

POST /api/waitlist

Join or leave an event waitlist. Requires session.

Body: { eventId: string, action: "join" | "leave" | "claim" }

GET /api/waitlist?eventId=...

Get waitlist position and depth for an event.

POST /api/demand/requests

Create an event request (what the community wants).

Body:

{
  "category": "musica",
  "title": "Jazz Festival estivo",
  "description": "Un weekend di jazz...",
  "pledgeTarget": 500
}

GET /api/demand/requests

List open event requests, sorted by pledges and upvotes.

POST /api/demand/pledge

Pledge money toward an event request. Requires session.

Body: { requestId: string, amount: number }


Organizer & Connect

POST /api/connect/onboard

Start Stripe Connect onboarding. Returns onboarding URL. Requires session (organizer role).

GET /api/connect/status

Get Stripe Connect status for the current organizer.

Response:

{
  "accountId": "acct_...",
  "onboarded": true,
  "commissionRate": 0.03,
  "tier": "verified",
  "isLive": true
}

GET /api/connect/payouts

Get payout history for the current organizer.

GET /api/connect/commission

Get commission rate breakdown and platform revenue (admin only).

GET /api/onboarding

Get onboarding progress for the current user.

POST /api/onboarding

Advance onboarding step.

POST /api/onboarding/interests

Set user interest categories during onboarding.


Verification

POST /api/verification

Submit a verification request with documentation.

Body:

{
  "documentType": "partita_iva",
  "documentUrl": "https://...",
  "tier": "verified"
}

Document types: partita_iva | association | municipal_letter Tiers: verified (3% commission) | municipal_partner (2%) | featured_partner (2%)

GET /api/verification

Get verification status for the current user or list pending verifications (admin).


Admin

All admin endpoints require X-API-Key header matching ADMIN_API_KEY.

GET /api/admin/jobs

Get job queue statistics and recent jobs.

POST /api/admin/queue

Process next pending job or enqueue a new job.

GET /api/admin/users

List all users with roles and verification tiers.


System

GET /api/health

Health check endpoint. Returns service status and dependency checks.

Response:

{
  "status": "healthy",
  "checks": {
    "database": { "ok": true },
    "stripe": { "ok": true },
    "email": { "ok": false, "message": "Not configured" },
    "baseUrl": { "ok": true }
  },
  "timestamp": "2025-07-15T10:00:00.000Z"
}

Status codes: 200 = healthy, 503 = degraded

POST /api/cron

Hourly cron endpoint (called by Vercel Cron). Authenticated via CRON_SECRET.

Runs: scraper pipeline, job queue processing, recurring job scheduling, alert checks.

POST /api/scraper

Trigger a manual scraper run. Returns ingestion results per source.

GET /api/locale

Get/set user locale preference.

POST /api/upload

Upload a file (image). Returns URL.

POST /api/reports

Report an event for moderation.

Body: { eventId: string, category: "spam" | "misleading" | "inappropriate" | "other", reason?: string }

Auto-escalation: events with 3+ pending reports are auto-hidden.

GET /api/recommendations

Get personalized event recommendations for the current user (affinity-based with category diversity).

GET /api/profile

Get current user profile.

PUT /api/profile

Update current user profile (name, bio, interests).

GET /api/dashboard

Get organizer dashboard data (events, tickets, analytics).

POST /api/digest

Preview weekly digest content.

POST /api/digest/send

Trigger digest email send.

GET /api/cities

List all enabled cities.

GET /api/og

Generate Open Graph image for an event (dynamic).


Embed & OG

GET /api/embed

Returns an embeddable HTML page with event cards.

Parameter Type Default Description
city string Forlì City filter
limit number 5 Number of events
theme string light light or dark
category string Category filter

CORS enabled. X-Frame-Options: ALLOWALL for this endpoint.

GET /api/og

Dynamic OG image generation for social sharing.


Webhooks

POST /api/webhooks/stripe

Stripe webhook handler. Validates signature via STRIPE_WEBHOOK_SECRET.

Handled events:

  • checkout.session.completed → Activates ticket, emits ticket.paid domain event
  • checkout.session.expired → Cancels ticket
  • account.updated → Updates Connect onboarding status
  • transfer.created → Marks payout as completed
  • payout.paid / payout.failed → Logs for reconciliation

Rate Limits

Tier Window Max Requests Applied To
general 1 minute 100 Most endpoints
auth 1 minute 10 Login/register
payment 1 minute 5 Checkout/payment
upload 1 minute 10 File uploads
search 1 minute 30 Search endpoints
admin 1 minute 50 Admin endpoints
api 1 hour 1000 Public API

Rate limit headers are included in responses:

  • X-RateLimit-Remaining — Requests remaining in window
  • X-RateLimit-Reset — Window reset timestamp (ISO 8601)

When rate limited, the API returns 429 Too Many Requests:

{ "error": "Troppe richieste. Riprova tra poco." }

Error Responses

All errors follow this shape:

{
  "error": "Human-readable error message (Italian)"
}

Common status codes:

  • 400 — Validation error or bad request
  • 401 — Authentication required (missing session or API key)
  • 403 — Insufficient permissions
  • 404 — Resource not found
  • 429 — Rate limited
  • 500 — Internal server error