encore-api

When creating API endpoints with Encore.ts, follow these patterns:

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "encore-api" with this command: npx skills add encoredev/skills/encoredev-skills-encore-api

Encore API Endpoints

Instructions

When creating API endpoints with Encore.ts, follow these patterns:

  1. Import the API module

import { api } from "encore.dev/api";

  1. Define typed request/response interfaces

Always define explicit TypeScript interfaces for request and response types:

interface CreateUserRequest { email: string; name: string; }

interface CreateUserResponse { id: string; email: string; name: string; }

  1. Create the endpoint

export const createUser = api( { method: "POST", path: "/users", expose: true }, async (req: CreateUserRequest): Promise<CreateUserResponse> => { // Implementation } );

API Options

Option Type Description

method

string HTTP method: GET, POST, PUT, PATCH, DELETE

path

string URL path, supports :param and *wildcard

expose

boolean If true, accessible from outside (default: false)

auth

boolean If true, requires authentication

sensitive

boolean If true, redacts request/response payloads from traces

Request/Response Patterns

Encore supports four endpoint configurations:

// Both request and response export const createUser = api( { method: "POST", path: "/users", expose: true }, async (req: CreateRequest): Promise<CreateResponse> => { ... } );

// Response only (no request body) export const listUsers = api( { method: "GET", path: "/users", expose: true }, async (): Promise<ListResponse> => { ... } );

// Request only (no response body) export const deleteUser = api( { method: "DELETE", path: "/users/:id", expose: true }, async (req: DeleteRequest): Promise<void> => { ... } );

// Neither request nor response export const ping = api( { method: "GET", path: "/ping", expose: true }, async (): Promise<void> => { ... } );

Custom HTTP Status Codes

Include an HttpStatus field in your response to return custom status codes:

import { api, HttpStatus } from "encore.dev/api";

interface CreateResponse { id: string; status: HttpStatus; }

export const create = api( { method: "POST", path: "/items", expose: true }, async (req: CreateRequest): Promise<CreateResponse> => { const item = await createItem(req); return { id: item.id, status: HttpStatus.Created }; // Returns 201 } );

Parameter Types

Path Parameters

// Path: "/users/:id" interface GetUserRequest { id: string; // Automatically mapped from :id }

Query Parameters

import { Query } from "encore.dev/api";

interface ListUsersRequest { limit?: Query<number>; offset?: Query<number>; }

Headers

import { Header } from "encore.dev/api";

interface WebhookRequest { signature: Header<"X-Webhook-Signature">; payload: string; }

Cookies

import { Cookie } from "encore.dev/api";

interface SessionRequest { session?: Cookie<"session">; settings?: Cookie<"user-settings">; }

Request Validation

Encore validates requests at runtime using TypeScript types. Add constraints for stricter validation:

import { api } from "encore.dev/api"; import { Min, Max, MinLen, MaxLen, IsEmail, IsURL } from "encore.dev/validate";

interface CreateUserRequest { email: string & IsEmail; // Must be valid email username: string & MinLen<3> & MaxLen<20>; // 3-20 characters age: number & Min<13> & Max<120>; // Between 13 and 120 website?: string & IsURL; // Optional, must be URL if provided }

Combining Validation Rules

Use & for AND logic (must pass all rules) and | for OR logic (must pass at least one):

import { IsEmail, IsURL, MinLen, MaxLen } from "encore.dev/validate";

interface ContactRequest { // Must be valid email OR valid URL contact: string & (IsEmail | IsURL); // Must be 5-100 chars AND be a valid URL website: string & MinLen<5> & MaxLen<100> & IsURL; }

Available Validators

Validator Applies To Example

Min<N>

number age: number & Min<18>

Max<N>

number count: number & Max<100>

MinLen<N>

string, array name: string & MinLen<1>

MaxLen<N>

string, array tags: string[] & MaxLen<10>

IsEmail

string email: string & IsEmail

IsURL

string link: string & IsURL

StartsWith<S>

string id: string & StartsWith<"usr_">

EndsWith<S>

string file: string & EndsWith<".json">

MatchesRegexp<R>

string code: string & MatchesRegexp<"^[A-Z]{3}$">

Validation Error Response

Invalid requests return 400 with details:

{ "code": "invalid_argument", "message": "validation failed", "details": { "field": "email", "error": "must be a valid email" } }

Raw Endpoints

Use api.raw for webhooks or when you need direct request/response access:

export const stripeWebhook = api.raw( { expose: true, path: "/webhooks/stripe", method: "POST" }, async (req, res) => { const sig = req.headers["stripe-signature"]; // Handle raw request... res.writeHead(200); res.end(); } );

Error Handling

Use APIError for proper HTTP error responses:

import { APIError, ErrCode } from "encore.dev/api";

// Throw with error code throw new APIError(ErrCode.NotFound, "user not found");

// Or use shorthand throw APIError.notFound("user not found"); throw APIError.invalidArgument("email is required"); throw APIError.unauthenticated("invalid token");

Common Error Codes

Code HTTP Status Usage

NotFound

404 Resource doesn't exist

InvalidArgument

400 Bad input

Unauthenticated

401 Missing/invalid auth

PermissionDenied

403 Not allowed

AlreadyExists

409 Duplicate resource

Static Assets

Serve static files (HTML, CSS, JS, images) with api.static :

import { api } from "encore.dev/api";

// Serve files from ./assets under /static/* export const assets = api.static( { expose: true, path: "/static/*path", dir: "./assets" } );

// Serve at root (use !path for fallback routing) export const frontend = api.static( { expose: true, path: "/!path", dir: "./dist" } );

// Custom 404 page export const app = api.static( { expose: true, path: "/!path", dir: "./public", notFound: "./404.html" } );

Path Syntax

  • *path

  • Standard wildcard: matches all paths under the prefix (e.g., /static/*path )

  • !path

  • Fallback routing: serves static files at domain root without conflicting with other API endpoints. Use this for SPAs where unmatched routes should serve index.html

Guidelines

  • Always use import not require

  • Define explicit interfaces for type safety

  • Use expose: true only for public endpoints

  • Use api.raw for webhooks, api for everything else

  • Throw APIError instead of returning error objects

  • Path parameters are automatically extracted from the path pattern

  • Use validation constraints (Min , MaxLen , etc.) for user input

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

encore-service

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

encore-code-review

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

encore-auth

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

encore-database

No summary provided by upstream source.

Repository SourceNeeds Review