API — Lantern (Draft)
This document defines the initial API endpoints, authentication patterns, error codes, and examples to support merchant features, offers, check-ins, redemptions, and the Wave-to-Meet social features.
Authentication
- Use
Authorization: Bearer <token>(JWT) for user and merchant auth. - Admin endpoints require an admin-scoped token and MFA-enforced account.
Rate limits
- Standard endpoints: 100 req/min per token
- Check-in & redemption endpoints: 30 req/min per token (higher scrutiny)
- Wave endpoints: 20 req/min per token (prevent spam)
Error codes (sample)
- 400 — Bad Request (invalid payload)
- 401 — Unauthorized (invalid/expired token)
- 403 — Forbidden (insufficient scope)
- 404 — Not Found (resource missing)
- 409 — Conflict (e.g., offer limit reached)
- 429 — Too Many Requests (rate limit)
- 500 — Internal Server Error
Endpoints (examples)
Merchant & Offers
POST /merchant/offers
- Auth: merchant
- Body:
{ title, description, start_time, end_time, geofence, per_user_limit, max_redemptions } - Responses:
201 { id, status }|400/401/403
GET /places/:place_id/offers
- Auth: public (no auth required)
- Responses:
200 { offers: [ ... ] }
POST /places/:place_id/checkin
- Auth: user
- Body:
{ user_id, lat, lon } - Response:
200 { eligible_offers: [...], checkin_id } - Security: verify geo-fence server-side and return only eligible offers
POST /offers/:id/redeem
- Auth: user
- Body:
{ checkin_id } - Response:
200 { redeemed: true, redeem_code }|409if already redeemed or limits hit - Security: validate checkin timestamp and that checkin_id maps to a real check-in within the campaign window
GET /merchant/reports?campaign=offer_id
- Auth: merchant
- Response: metrics + CSV link
Wave-to-Meet Endpoints (NEW)
Send Wave
POST /api/waves
- Auth: user
- Body:
{ targetLanternId: string, senderLanternId: string } - Response:
201 { waveId: string, status: "sent" } - Security: Verify both lanterns are at same venue, rate-limit to prevent spam
Accept Wave
POST /api/waves/:waveId/accept
- Auth: user
- Body:
{ matchColor: string } - Response:
200 { connectionId: string, matchColor: string } - Security: Verify recipient owns the target lantern, generate connection
Decline Wave
POST /api/waves/:waveId/decline
- Auth: user
- Response:
200 { status: "declined" }
Get Pending Waves
GET /api/waves/pending
- Auth: user
- Response:
200 { waves: [{ id, interest, mood, venue, time, senderLanternId }] } - Note: Do not expose sender user identity, only lantern metadata
Real-time Wave Notifications
WebSocket /ws/waves
- Auth: user (via query param or initial message)
- Events:
wave_received: { type: "wave_received", wave: {...} }wave_accepted:wave_declined:
Send Chat Message
POST /api/messages
- Auth: user
- Body:
{ connectionId: string, text: string, timestamp: string } - Response:
201 { messageId: string } - Security: Verify user is part of connection, sanitize text
Get Chat Messages
GET /api/messages?connectionId={id}
- Auth: user
- Response:
200 { messages: [{ id, text, from: "me"|"them", timestamp }] } - Security: Verify user is part of connection, paginate for performance
Get Beacon Color
GET /api/connections/:connectionId/beacon
- Auth: user
- Response:
200 { matchColor: string, expiresAt: timestamp } - Security: Verify user is part of connection, return shared color
Close Connection
DELETE /api/connections/:connectionId
- Auth: user
- Response:
200 { status: "closed" } - Note: Clean up messages, mark connection as inactive
Webhooks (merchant optional)
- POST /webhooks/merchant/events
- Events: checkin_created, offer_redeemed, offer_expired
- Security: HMAC signature with merchant secret for verification
Notes & next steps
- Add full request/response schemas (JSON Schema / OpenAPI) and example curl commands.
- Implement WebSocket server for real-time wave notifications and chat
- Add message encryption for enhanced privacy (E2E encryption consideration)
- See WAVE_TO_MEET.md for detailed feature documentation
- Add pagination, query params for filter/sort, and expanded error details.
- Consider adding an SDK after API stabilizes.