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.