Skip to main content
When you create a Better Auth instance it exposes an api object that mirrors every HTTP endpoint — including endpoints added by plugins. You can call these as regular TypeScript functions on the server, or hit them as HTTP endpoints from any client.

Base path

All endpoints are mounted under /api/auth by default. You can change this with the basePath option.
EndpointMethodDescription
/api/auth/sign-up/emailPOSTRegister with email & password
/api/auth/sign-in/emailPOSTSign in with email & password
/api/auth/sign-outPOSTInvalidate the current session
/api/auth/get-sessionGETReturn the current session
/api/auth/sign-in/socialPOSTInitiate social OAuth flow
/api/auth/callback/:providerGETOAuth callback handler
/api/auth/verify-emailGETVerify email with token
/api/auth/forget-passwordPOSTRequest a password-reset email
/api/auth/reset-passwordPOSTComplete password reset
/api/auth/change-passwordPOSTChange password (authenticated)
/api/auth/change-emailPOSTChange email (authenticated)
/api/auth/delete-userPOSTDelete the authenticated user
/api/auth/list-sessionsGETList sessions for the current user
/api/auth/revoke-sessionPOSTRevoke a specific session
/api/auth/revoke-other-sessionsPOSTRevoke all sessions except current
Plugins register additional endpoints under the same base path. All plugin endpoints are automatically available on the api object.

Calling endpoints server-side

Import your auth instance and call endpoints directly as functions. This skips HTTP entirely — useful in server components, API routes, and middleware.
server.ts
import { auth } from "@/lib/auth";
import { headers } from "next/headers";

// get the current session
const session = await auth.api.getSession({
  headers: await headers(),
});

// sign in a user
const result = await auth.api.signInEmail({
  body: {
    email: "user@example.com",
    password: "password",
  },
});

Body, headers, and query parameters

Unlike the browser client, the server API accepts values as a plain object:
KeyPurpose
bodyRequest body (POST/PUT payloads)
headersRequest headers (required for session lookup)
queryURL query parameters
server.ts
import { auth } from "@/lib/auth";

// body
await auth.api.signInEmail({
  body: { email: "john@doe.com", password: "password" },
});

// headers
await auth.api.getSession({
  headers: await headers(),
});

// query
await auth.api.verifyEmail({
  query: { token: "my_token" },
});
Better Auth’s API layer is built on better-call, a tiny web framework that lets REST endpoints be called as regular TypeScript functions with full type inference.

Retrieving response headers

Use returnHeaders: true to get back the response Headers object alongside the data. This is useful when you need Set-Cookie headers.
server.ts
const { headers, response } = await auth.api.signUpEmail({
  returnHeaders: true,
  body: {
    email: "john@doe.com",
    password: "password",
    name: "John Doe",
  },
});

// extract cookies
const cookies = headers.getSetCookie();

Retrieving the raw Response object

Pass asResponse: true to receive a standard Response instead of the deserialised data.
server.ts
const response = await auth.api.signInEmail({
  asResponse: true,
  body: { email: "", password: "" },
});

Error handling

Server-side API calls throw an APIError on failure. Use isAPIError to narrow the error type.
server.ts
import { APIError, isAPIError } from "better-auth/api";

try {
  await auth.api.signInEmail({
    body: { email: "", password: "" },
  });
} catch (error) {
  if (isAPIError(error)) {
    console.log(error.message); // human-readable message
    console.log(error.status);  // HTTP status code string, e.g. "UNAUTHORIZED"
  }
}

Calling endpoints via HTTP

You can also call Better Auth endpoints with any HTTP client.
curl -X POST https://example.com/api/auth/sign-up/email \
  -H "Content-Type: application/json" \
  -d '{"email":"user@example.com","password":"password","name":"Alice"}'

Response format

All endpoints return JSON. Successful responses use HTTP 2xx status codes. Error responses follow this shape:
{
  "message": "Invalid email or password",
  "code": "INVALID_EMAIL_OR_PASSWORD",
  "status": 401
}