---
title: "Calling the API from a browser"
description: "Why calling Mailfully straight from your frontend exposes your API key, and the server-side proxy pattern that replaces it."
---

> **For AI agents:** the complete documentation index is at [llms.txt](/docs/llms.txt). Append `.md` to any page URL for its markdown version.

The Mailfully API is designed to be called from your server, not from your users' browsers. The reason is the key: anything your frontend can send with, your visitors can read.

## Why the key is the real problem

Any key shipped to a browser is readable by every visitor who opens developer tools, and a `send` key lets anyone who finds it send mail as your verified domain and burn your quota. That is true however the request itself is handled: the key sitting in the page's JavaScript is readable either way, so moving the call server-side is the fix rather than any adjustment to how the browser sends it.

## The pattern that works

Put a route on your own server that holds the key, validates its own input, and calls Mailfully. The browser calls your route; your route calls Mailfully.

```typescript
import { Mailfully } from "mailfully";

const mailfully = new Mailfully({ apiKey: process.env.MAILFULLY_API_KEY ?? "" });

export async function POST(request: Request) {
  const { email } = await request.json();

  if (typeof email !== "string" || !email.includes("@")) {
    return new Response("Invalid email", { status: 400 });
  }

  const { data, error } = await mailfully.emails.send({
    from: "orders@mail.acme.com",
    to: email,
    subject: "Your order shipped",
    text: "Order 4212 shipped.",
  });

  if (error !== null) {
    return new Response(error.message, { status: error.statusCode ?? 500 });
  }

  return Response.json(data);
}
```

## Scope the key down

Give the key your server route holds only the scopes it needs, rather than the default. Narrower scoping limits what's at risk if that server is ever compromised. See [API key security](/concepts/api-key-security) for how scopes are chosen and secrets are stored.

## If a key has already reached a browser

Treat it as leaked. See [A leaked API key](/troubleshooting/leaked-api-key) for how to rotate or revoke it and audit what it could reach.
