Skip to content
Back to skills

Medusa Api Routes

ASecurity

Create custom Medusa v2 API routes — file-based routing, HTTP method exports, middleware configuration, Zod validators, authentication middleware, and additional-data pattern. Use when adding REST endpoints.

  • 39 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added May 29, 2026
ai-agentstypescriptapidocumentation

Works with

  • cli
  • api

Security analysis

A100/100

Scanned May 29, 2026

npx -y skills add OrcaQubits/agentic-commerce-skills-plugins --skill medusa-api-routes --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Medusa Api Routes?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Medusa Api Routes
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/orcaqubits-medusa-api-routes/badge)](https://www.skillsdirectory.com/skills/orcaqubits-medusa-api-routes)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: medusa-api-routes
description: >
  Create custom Medusa v2 API routes — file-based routing, HTTP method exports,
  middleware configuration, Zod validators, authentication middleware, and
  additional-data pattern. Use when adding REST endpoints.
---

# Medusa v2 Custom API Routes

## Before writing code

**Fetch live docs**:
1. Fetch `https://docs.medusajs.com/learn/fundamentals/api-routes` for API route overview
2. Web-search `site:docs.medusajs.com custom API route file convention` for file-based routing
3. Web-search `site:docs.medusajs.com API route middleware` for middleware configuration
4. Web-search `site:docs.medusajs.com API route validation zod` for request validation
5. Web-search `site:docs.medusajs.com additional data API routes` for the additional-data pattern

## File-Based Routing

Medusa v2 uses a file-system router under `src/api/`:

| File Path | Resulting Endpoint |
|-----------|-------------------|
| `src/api/store/custom/route.ts` | `GET/POST /store/custom` |
| `src/api/admin/custom/route.ts` | `GET/POST /admin/custom` |
| `src/api/store/custom/[id]/route.ts` | `GET/POST /store/custom/:id` |
| `src/api/custom/route.ts` | `GET/POST /custom` (no auth prefix) |

### Conventions

- File must be named `route.ts` (not `index.ts`)
- Dynamic parameters use `[param]` folder syntax
- The `store/` prefix applies storefront authentication scope
- The `admin/` prefix applies admin authentication scope
- Routes outside these prefixes have no default authentication

## HTTP Method Exports

Each `route.ts` exports named functions matching HTTP methods:

| Export Name | HTTP Method |
|-------------|-------------|
| `GET` | GET |
| `POST` | POST |
| `PUT` | PUT |
| `PATCH` | PATCH |
| `DELETE` | DELETE |

### Route Handler Skeleton

```typescript
// src/api/store/custom/route.ts
// Fetch live docs for MedusaRequest/MedusaResponse types
import type { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"

export const GET = async (req: MedusaRequest, res: MedusaResponse) => {
  const service = req.scope.resolve("my-module")
  res.json({ items: await service.listMyEntities() })
}
```

### Route with Dynamic Parameter

```typescript
// src/api/store/custom/[id]/route.ts
// Fetch live docs for path parameter access
export const GET = async (req: MedusaRequest, res: MedusaResponse) => {
  const item = await req.scope.resolve("my-module").retrieveMyEntity(req.params.id)
  res.json({ item })
}
```

## Request Validation with Zod

Medusa v2 uses Zod schemas for request body and query parameter validation:

### Validation File Convention

| Validation Target | File |
|------------------|------|
| POST/PUT/PATCH body | `validators.ts` in same directory as `route.ts` |
| Query parameters | Same `validators.ts` file |

### Validator Skeleton

```typescript
// src/api/store/custom/validators.ts
// Fetch live docs for Zod schema integration
import { z } from "zod"

export const PostStoreCustom = z.object({
  name: z.string(),
  description: z.string().optional(),
})
```

Validators are linked to routes via middleware configuration.

## Middleware Configuration

All middleware is configured in `src/api/middlewares.ts`:

```typescript
// src/api/middlewares.ts — Fetch live docs for defineMiddlewares API
import { defineMiddlewares, validateAndTransformBody } from "@medusajs/framework/http"
import { PostStoreCustom } from "./store/custom/validators"

export default defineMiddlewares({
  routes: [{ matcher: "/store/custom", method: "POST",
    middlewares: [validateAndTransformBody(PostStoreCustom)] }],
})
```

### Built-in Middleware Utilities

| Utility | Purpose |
|---------|---------|
| `validateAndTransformBody(schema)` | Validate request body with Zod |
| `validateAndTransformQuery(schema)` | Validate query parameters |
| `authenticate("customer", ["session", "bearer"])` | Require customer auth |
| `authenticate("user", ["session", "bearer"])` | Require admin auth |

## Authentication Middleware

| Route Prefix | Default Auth | Custom Auth Override |
|-------------|-------------|---------------------|
| `/admin/*` | Admin user required | Can be loosened per route |
| `/store/*` | Optional customer auth | Can require auth per route |
| `/custom/*` | None | Must add explicitly |

### Requiring Customer Authentication

```typescript
// In middlewares.ts routes array
// Fetch live docs for authenticate() options
{
  matcher: "/store/custom/me",
  middlewares: [authenticate("customer", ["session", "bearer"])],
}
```

## Additional Data Pattern

Medusa v2 supports passing extra data through built-in API routes to workflow hooks:

- Client sends extra fields in the request body under `additional_data`
- Validated by defining an `additionalDataValidator` in middleware
- Received in workflow hooks as `additional_data`

This allows extending core commerce flows (e.g., adding custom fields to product creation) without overriding API routes.

## Error Handling

| Error Type | Recommended Approach |
|-----------|---------------------|
| Validation error | Handled automatically by Zod middleware (400) |
| Not found | Throw `MedusaError` with `NOT_FOUND` type |
| Unauthorized | Handled by auth middleware (401) |
| Business logic | Throw `MedusaError` with appropriate type |
| Unexpected | Let Medusa error handler return 500 |

## Best Practices

- Use file-based routing conventions -- do not register routes programmatically
- Always validate request bodies with Zod schemas via `validateAndTransformBody`
- Resolve services from `req.scope` -- never import services directly
- Use the `additional_data` pattern to extend core routes instead of overriding them
- Apply `authenticate()` middleware explicitly for routes requiring auth outside default scopes
- Return consistent response shapes: `{ item }` for single, `{ items, count, offset, limit }` for lists
- Keep route handlers thin -- delegate business logic to workflows or services

Fetch the Medusa API route documentation for exact file conventions, middleware utilities, and Zod integration patterns before implementing.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…