4. API Design
Medusa v2 provides 48+ native endpoints for products, carts, orders, customers, and auth. The following 12 custom endpoints extend that functionality.
4.1 Custom Endpoints
File Management
Admin only — requires admin JWT
| Method | Path | Description |
|---|---|---|
POST | /admin/products/:id/files | Upload ZIP to Cloudflare R2 |
GET | /admin/products/:id/files | List file metadata for a product |
DELETE | /admin/products/:id/files/:fileId | Remove file from R2 and database |
Downloads
Customer — requires store JWT
| Method | Path | Description |
|---|---|---|
GET | /store/downloads/:token | Validate token → return R2 presigned URL (15 min) |
POST | /store/downloads/:token/redeem | Increment download count post-download |
GET | /store/customers/me/downloads | List all download links for customer |
Invite System
| Method | Path | Auth | Description |
|---|---|---|---|
POST | /admin/invites | Admin | Create invite + trigger Resend email |
GET | /admin/invites | Admin | List all invites with status |
DELETE | /admin/invites/:id | Admin | Revoke an invite |
GET | /store/invites/:token | Public | Validate token — returns email + expires_at |
POST | /store/invites/:token/accept | Public | Accept invite — creates customer account |
Webhooks
| Method | Path | Description |
|---|---|---|
POST | /webhooks/stripe | Handle payment_intent.succeeded + charge.refunded |
POST | /webhooks/gelato | Gelato POD fulfilment status updates (Phase 2) |
4.2 Authentication
| Route type | Auth method |
|---|---|
| Store routes | Authorization: Bearer <JWT> header |
| Admin routes | Medusa admin JWT (separate auth flow) |
| Webhook routes | Stripe-Signature header (HMAC SHA-256) |
| Download routes | Token in URL path, validated against customer JWT |
4.3 Error Response Format
All custom endpoints return errors in this format:
{
"type": "error",
"message": "Human readable message",
"code": "MACHINE_READABLE_CODE"
}| HTTP Code | Meaning | Example |
|---|---|---|
400 | Bad Request | Validation failure, missing fields |
401 | Unauthorized | Missing or expired JWT |
403 | Forbidden | Not owner of resource (IDOR prevention) |
404 | Not Found | Resource does not exist |
409 | Conflict | Duplicate email, already accepted invite |
410 | Gone | Expired token, exhausted download limit |
429 | Too Many Requests | Rate limit exceeded |
500 | Internal Server Error | Unexpected backend failure |
4.4 Example Requests
curl -X POST https://api.shop.vespertene.com/admin/products/prod_123/files \
-H "Authorization: Bearer <admin_jwt>" \
-H "Content-Type: multipart/form-data" \
-F "file=@wallpack-sydney.zip"⚠️
The Stripe webhook endpoint validates Stripe-Signature on every request. Requests without a valid signature return 403 immediately — before any business logic runs.