HTTP Endpoint Extension Files and Code

An HTTP endpoint is a single TypeScript file that exports a handler for each HTTP method it supports. Wix finds the file from its location, so the file's path sets the route.

Unlike other extension types, an HTTP endpoint has no configuration file. It isn't registered in extensions.ts, and it doesn't appear in a list of extensions.

File location

The folder, the route prefix, and the handler type's package depend on the project. The following table shows where an endpoint named orders goes:

ProjectFileRouteAPIRoute import
Studio Two sitesrc/api/orders.tsorders@wix/custom-extensions/types
Wix CLI app or Wix-managed headless projectsrc/pages/api/orders.tsapi/ordersastro

The route is the path that follows the base URL your endpoints are served from.

Change the folder in a Studio Two site

To serve endpoints from a different folder, set apiDir on app() in src/extensions.ts. The path is relative to src/:

Copy

The folder you set replaces src/api/. Wix doesn't serve endpoints from src/api/ when apiDir points elsewhere.

Routes in a Studio Two site

Every .ts or .js file in the endpoints folder, except .d.ts files, becomes a route, including a file that holds only shared helper code.

The route is the file's path in the folder, without the file extension. A file named index.ts serves the route of its folder. The following table shows how file paths map to routes:

FileRoute
src/api/reviews.tsreviews
src/api/reviews/index.tsreviews
src/api/reviews/summary.tsreviews/summary
src/api/reviews/[reviewId].tsreviews/<any value>, such as reviews/abc-123
src/api/catalog/[...slug].tscatalog/<one or more segments>, such as catalog/shoes/red

A segment in square brackets is dynamic. The handler reads its value from params, using the name inside the brackets. For example, a request to reviews/abc-123, handled by [reviewId].ts, has params.reviewId set to abc-123. A rest segment, such as [...slug], captures the rest of the path, so catalog/shoes/red sets params.slug to shoes/red.

Route rules:

  • Each route can belong to only one file. For example, src/api/reviews.ts and src/api/reviews/index.ts can't both exist. If two files resolve to the same route, the build fails.
  • Routes that start with _wix are reserved for Wix. A file that resolves to one fails the build.

Routes in a Wix CLI app or Wix-managed headless project

A Wix CLI app and a headless project use Astro's file-based routing, so an endpoint file in src/pages/api/ follows Astro's routing rules, including dynamic and rest segments in square brackets. The route always starts with api/.

In a headless project, the Astro integration registers some routes of its own, such as /api/auth/login. Don't add an endpoint at one of those paths. For the full list, see Reserved URL Paths for the Astro Integration.

Handler

Each handler is an exported constant named for the HTTP method it handles, such as GET, POST, PUT, or DELETE, and typed as APIRoute. A handler receives a context object and returns a standard Response, or a promise that resolves to one.

Import APIRoute from the package your project uses:

Copy
Copy

A generated endpoint file exports a GET handler that returns a JSON message and a POST handler that returns the JSON body it receives:

Copy

Handler context

The context object includes these properties in every project:

PropertyTypeDescription
requestRequestThe incoming request. Read a JSON body with await request.json(), and headers with request.headers.
urlURLThe request URL. Read query parameters with url.searchParams.
paramsobjectThe values of the route's dynamic segments, keyed by the names inside the square brackets.

In a Wix CLI app or a headless project, the context is Astro's APIContext, which has more properties, such as cookies and redirect().

Responses and errors in a Studio Two site

A handler sets its own status codes. Wix returns these responses without running your handler, or in place of its response:

StatusWhen
401The request has no access token.
404No file serves the route. The body is empty.
500The handler throws an error that it doesn't catch. The body is Internal Server Error, and the error message stays on the server.

See also

Last updated: 2 November 2026

Did this help?