VisitRomagna REST API — 60+ endpoints for the agritourism booking platform
Base URL: http://localhost:3000/api
Cookie-based session authentication via vr_session cookie. Obtain a session by calling POST /api/auth/login.
# Dev bypass (development mode only)
curl http://localhost:3000/api/admin/stats?dev=trueAll errors follow a consistent format:
{
"error": "Description of the error",
"code": "ERROR_CODE",
"details": {},
"requestId": "req_1234567890_1"
}| Code | HTTP Status | Description |
|---|---|---|
VALIDATION_ERROR |
400 | Request body/query failed Zod validation |
INVALID_JSON |
400 | Malformed JSON body |
AUTH_REQUIRED |
401 | No valid session cookie |
FORBIDDEN |
403 | Insufficient role permissions |
NOT_FOUND |
404 | Resource not found |
CONFLICT |
409 | Duplicate or state conflict |
RATE_LIMITED |
429 | Too many requests |
INTERNAL_ERROR |
500 | Unexpected server error |
Per-IP, per-endpoint limits. Responses include X-RateLimit-* headers when exceeded.
| Endpoint Group | Limit |
|---|---|
/api/auth/* |
10 req/min |
/api/experiences |
200 req/min |
/api/payments/webhook |
500 req/min |
/api/health |
1000 req/min |
| All other endpoints | 100 req/min |
Endpoints returning lists accept page and pageSize query parameters:
GET /api/bookings?page=2&pageSize=10
Response includes pagination metadata:
{
"data": [...],
"meta": {
"page": 2,
"pageSize": 10,
"total": 47,
"hasMore": true
}
}Register a new user account.
Body:
{
"email": "mario@example.com",
"name": "Mario Rossi",
"role": "tourist"
}Roles: tourist (default), host, admin
Response: 200 — Sets vr_session cookie
{
"user": { "id": "...", "email": "...", "name": "...", "role": "tourist" },
"message": "Registration successful"
}Authenticate by email (simplified — no password in dev mode).
Body:
{ "email": "mario@example.com" }Response: 200 — Sets vr_session cookie
End the current session.
Response: 200 — Clears vr_session cookie
Get the currently authenticated user.
Response: 200
{
"user": { "id": "...", "email": "...", "name": "...", "role": "host" }
}List experiences with optional filters.
Query Parameters:
| Param | Type | Description |
|---|---|---|
category |
string | Filter by category (e.g., "Vino & Vigneti") |
location |
string | Filter by location (e.g., "Bertinoro") |
maxPrice |
number | Maximum price filter |
Response: 200 — Array of experience objects
Get a single experience by ID.
Response: 200 — Full experience object with host profile, reviews, availability
Create a new experience. Auth: host, admin
Body (Zod-validated):
{
"title": "Degustazione Sangiovese al tramonto",
"shortDescription": "Wine tasting at sunset in Bertinoro",
"description": "Full description...",
"category": "Vino & Vigneti",
"location": "Bertinoro",
"priceValue": 45.00,
"priceLabel": "€45/persona",
"duration": "2 ore",
"hostName": "Marco Rossi",
"hostTitle": "Sommelier",
"hostBio": "Bio text...",
"included": ["Wine tasting", "Light snacks"],
"languages": ["Italiano", "English"],
"groupSize": "2-12 persone",
"meetingPoint": "Piazza della Libertà, Bertinoro"
}Categories: Vino & Vigneti, Corsi di Cucina, Agriturismi, Cicloturismo, Cultura, Natura & Benessere
Locations: Forlì, Bertinoro, Castrocaro, Predappio, Meldola, Premilcuore
List bookings. Auth: authenticated user
Query: status — Filter by booking status
Response: 200 — Array of booking objects
Create a new booking. Auth: authenticated user
Body (Zod-validated):
{
"experienceId": "exp_123",
"date": "2025-08-15",
"guests": 2,
"giftCardCode": "GIFT-ABC-123"
}Emits: booking.created domain event
Update booking status. Auth: host (own bookings), admin
Body:
{
"bookingId": "bk_123",
"status": "confirmed",
"reason": "Optional cancellation reason"
}Statuses: pending → confirmed → completed | cancelled
List reviews for an experience.
Query: experienceId — Required
Submit a review. Auth: authenticated user
Body (Zod-validated):
{
"experienceId": "exp_123",
"bookingId": "bk_456",
"rating": 5,
"comment": "Esperienza fantastica! Il Sangiovese era eccezionale.",
"photos": ["https://example.com/photo1.jpg"]
}Constraints: rating 1–5, comment 10–2000 chars, max 5 photos
Emits: review.submitted domain event
Add host response to a review. Auth: host, admin
Body:
{
"reviewId": "rev_123",
"response": "Grazie mille! Vi aspettiamo ancora."
}Get availability slots for an experience.
Query: month — Format: YYYY-MM
Response: 200 — Array of availability slots with dates, times, capacity
Calculate price for an experience.
Query:
| Param | Type | Description |
|---|---|---|
experienceId |
string | Experience ID |
date |
string | Booking date |
guests |
number | Number of guests |
Create a pricing rule. Auth: host, admin
Update a pricing rule.
Delete a pricing rule. Query: id
Pricing Rule Types: seasonal, day_of_week, early_bird, last_minute, group_discount
Stripe webhook handler. Processes payment lifecycle events.
Body: Stripe event payload
Headers: stripe-signature — Webhook signature (required in production)
Rate Limit: 500 req/min
List gift cards. Query: code (lookup by code), userId (by purchaser)
Purchase a gift card. Auth: authenticated user
Generate an AI-powered itinerary.
Body:
{
"message": "Weekend romantico con vino e cucina",
"days": 3,
"budget": "medium",
"interests": ["wine", "cooking", "nature"]
}Get itinerary cart. Query: userId, id, shareSlug
Create/update itinerary cart.
List conversations for a user. Query: userId
Create a new conversation.
List messages in a conversation. Query: conversationId
Send a message.
Mark messages as read.
List notifications for a user. Query: userId
Create a notification.
Mark notifications as read.
Open a Server-Sent Events stream.
Query: channel — Channel to subscribe to (e.g., user:abc123, host:xyz, admin)
Response: 200 — text/event-stream
Events:
| Event | Data | Trigger |
|---|---|---|
connected |
{ clientId, channel } |
On connection |
notification |
RealtimeNotification |
Booking, message, review, etc. |
availability |
{ date, availableSpots } |
Availability change |
Strava integration endpoints.
Query:
| Param | Description |
|---|---|
userId |
Get user's Strava connection |
routeId |
Get activity logs for a route |
type=challenges |
List cycling challenges |
Create activity log or connect Strava account.
List cycling activity logs.
List campaigns. Query: slug, status
Create a campaign. Auth: admin
Update campaign status.
List festivals. Query: category, slug, upcoming, links
Create a festival. Auth: admin
List group bookings. Query: id, organizerId, status
Submit a group booking inquiry.
Group Types: corporate, wedding, school, private
List B2B proposals. Auth: agent, admin. Query: orgId
Create a B2B proposal. Auth: agent, admin
Update proposal status.
List travel agents. Auth: agent, admin. Query: id, status, rates
Register a new agent.
Get referral info for a user. Query: userId
Create/redeem a referral.
Get loyalty tier/credits. Query: userId
Get CRM profiles and stats. Auth: admin
Query: profileId, segment, stats, events
Create/update CRM entry.
List distribution channels. Query: experienceId
Create a channel listing.
Update channel status/pricing.
Get channel performance analytics.
List media assets. Query: entityType, entityId
Upload media.
Delete media. Query: id
List calendar sync connections. Query: experienceId
Create calendar sync connection.
Remove calendar sync. Query: id
Get host financial profile. Auth: host, admin. Query: hostId, summary, taxProfile
Save tax profile/financial info.
List invoices. Query: recipientId, type
Generate an invoice (supports FatturaPA XML).
List host payouts.
List tax profiles.
Revenue insights. Auth: host, admin. Query: hostId
Revenue forecasts. Query: experienceId, days
Market benchmarks. Query: category, location
Yield pricing settings. Query: experienceId
Save yield pricing settings.
Platform-wide statistics. Auth: admin
Admin action log. Auth: admin. Query: limit
Record an admin action.
List disputes. Auth: admin. Query: status
Resolve a dispute.
List moderation queue. Auth: admin. Query: status
Apply moderation decision.
List A/B experiments. Auth: admin
Create experiment.
Update experiment (start, stop, declare winner).
List feature flags. Auth: admin
Toggle a feature flag.
Health check endpoint. No auth required.
Response: 200
{ "status": "ok", "timestamp": "...", "version": "0.1.0" }List observability logs. Auth: admin. Query: level, route, type
Record a log/event.
List incidents. Auth: admin. Query: experienceId, status
Report an incident.
Get safety ratings for an experience. Query: experienceId
Get trust/verification records. Query: userId, type
Create trust verification.
Get insurance policies. Query: coverageType
Get personalized recommendations. Query: userId
Record a recommendation interaction event.
List regions. Auth: admin. Query: slug, activeOnly, memberships
Create a region.
Transport options. Query: experienceId, from, to, location, hubs
List ride-share offers. Query: date, toLocation
Create a ride-share offer.
List QR placements. Query: partnerId, slug
Create a QR placement.
List partner locations. Query: id, status, stats, referrals
Create a partner location.
Demand signals dashboard. Auth: admin
Supply gap analysis.
List guest questions. Query: experienceId
Ask a question.
Answer a question.
List waitlist entries. Query: experienceId
Join a waitlist.
Host community forum. Auth: host, admin. Query: category
Create a forum post.
Host collaboration network. Auth: host, admin. Query: hostId
Send a connection request.
Accept/decline a connection.
List webhook subscriptions. Auth: host, admin
Create a webhook subscription.
Delete a webhook subscription. Query: id or subscriptionId
List API keys. Auth: agent, admin. Query: hostId
Create an API key.
Revoke an API key. Query: id
Accessibility profiles and filters. Query: experienceId, wheelchairOnly, minScore, dietary
Upsert accessibility profile.
List immersive (360°/VR) media. Query: experienceId
Upload immersive media.
Delete immersive media. Query: id
List experience bundles. Query: id, status
Create a bundle.
List travel journals. Query: id, limit
Create/update a journal.
List journal entries. Query: journalId
Create a journal entry.
List domain events. Query: entityId, eventType, limit
Record a domain event.
List moonshot features. Query: view
Get a specific moonshot. Query: view
API documentation endpoint.