Specification
4. API Design

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

MethodPathDescription
POST/admin/products/:id/filesUpload ZIP to Cloudflare R2
GET/admin/products/:id/filesList file metadata for a product
DELETE/admin/products/:id/files/:fileIdRemove file from R2 and database

Downloads

Customer — requires store JWT

MethodPathDescription
GET/store/downloads/:tokenValidate token → return R2 presigned URL (15 min)
POST/store/downloads/:token/redeemIncrement download count post-download
GET/store/customers/me/downloadsList all download links for customer

Invite System

MethodPathAuthDescription
POST/admin/invitesAdminCreate invite + trigger Resend email
GET/admin/invitesAdminList all invites with status
DELETE/admin/invites/:idAdminRevoke an invite
GET/store/invites/:tokenPublicValidate token — returns email + expires_at
POST/store/invites/:token/acceptPublicAccept invite — creates customer account

Webhooks

MethodPathDescription
POST/webhooks/stripeHandle payment_intent.succeeded + charge.refunded
POST/webhooks/gelatoGelato POD fulfilment status updates (Phase 2)

4.2 Authentication

Route typeAuth method
Store routesAuthorization: Bearer <JWT> header
Admin routesMedusa admin JWT (separate auth flow)
Webhook routesStripe-Signature header (HMAC SHA-256)
Download routesToken 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 CodeMeaningExample
400Bad RequestValidation failure, missing fields
401UnauthorizedMissing or expired JWT
403ForbiddenNot owner of resource (IDOR prevention)
404Not FoundResource does not exist
409ConflictDuplicate email, already accepted invite
410GoneExpired token, exhausted download limit
429Too Many RequestsRate limit exceeded
500Internal Server ErrorUnexpected 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.