Reels Endpoints
Vertical video feed + engagement + tagging + earnings attribution. See Reels feature for the conceptual model.
Browse + watchโ
GET /api/reelsโ
Paginated feed. Used by web /reels and mobile Reels tab.
Query: cursor?, limit=20, search?, category?
Response: { reels: Reel[], nextCursor } โ each reel includes consumer/seller, _count (likes, comments, views), tags (multi-tag carousel data)
GET /api/reels/[id]โ
Single reel detail (used by deep links, e.g., /reels?id=X).
DELETE /api/reels/[id] ๐โ
Owner deletes their own reel. Cascades to ReelLike/Comment/View/Tag.
Engagement (deduplicated by fingerprint)โ
GET /api/reels/[id]/like?fingerprint=...โ
Returns { liked: boolean, count: number }.
POST /api/reels/[id]/likeโ
Body: { fingerprint }
Toggles like. Same fingerprint can only like once.
GET /api/reels/[id]/commentsโ
Response: { comments: ReelComment[] }
POST /api/reels/[id]/comments ๐โ
Body: { text } (max 200 chars)
POST /api/reels/[id]/viewโ
Body: { fingerprint }
Tracks a view. Same fingerprint deduplicated within a window.
Tagging (gated by REELS_COMMERCE_ENABLED)โ
GET /api/reels/[id]/tagsโ
Public. Returns the tag carousel data.
Response: { tags: ReelTag[] } โ each with embedded product or menuItem info
PUT /api/reels/[id]/tags ๐โ
Replace tags for a reel. Owner only. Up to 5 tags.
Body: { tags: Array<{ productId? | menuItemId? }> }
Returns 503 when REELS_COMMERCE_ENABLED=false.
Earnings attributionโ
POST /api/reels/[id]/redirectโ
Tracks a tap on a tagged product (creator earnings attribution). Logs to ReelProductRedirect.
Body: { fingerprint, productId, menuItemId? }
When the linked product is later ordered (within 24h via REEL_ATTRIBUTION_WINDOW_MS), a ReelEarning row is created in pending. Confirmed on delivered / reversed on cancelled.
Uploadโ
Reels videos are uploaded to GCS via signed URL โ the API does NOT see the video bytes.
POST /api/upload-video ๐โ
Returns a signed PUT URL the client uploads directly to.
Body: { filename, contentType }
Response: { uploadUrl, finalUrl }
After upload completes, client calls:
POST /api/reelsโ
Body: { videoUrl, thumbnailUrl, caption, category, productId?, restaurantId?, tags? }
Response: { reel: Reel }
Common shapesโ
Reelโ
{
id: number;
consumerId: number | null; // creator (one of these is set)
sellerId: number | null;
videoUrl: string;
thumbnailUrl: string | null;
caption: string | null;
category: string | null;
productId: number | null; // legacy single-tag
restaurantId: number | null; // legacy single-tag
isHidden: boolean;
reportCount: number;
durationSeconds: number | null;
tags?: ReelTag[];
consumer?: Consumer;
seller?: Seller;
product?: Product; // legacy
restaurant?: Restaurant; // legacy (eats archived)
_count: { likes: number; comments: number; views: number };
createdAt: string;
}
ReelTagโ
{
id: number;
reelId: number;
productId: number | null;
menuItemId: number | null;
position: number; // ordering
product?: { id, title, price, images };
menuItem?: { id, name, price, imageUrl, restaurant: { id, name } };
}
Relatedโ
- Reels feature
REEL_*constants insrc/lib/constants.tstests/build-integrity.test.ts(Reels section)