---
title: "Front an API you already run"
url: /data/front
---

# Front an API you already run

> Put an existing API behind a product: the gate keys, prices and meters each call, the origin answers it, and every reply carries its cost and a signed receipt.

A fronted origin is an API you already run, answering a product's Verbs after the gate has admitted, priced and metered each call.

**One call to a fronted Verb.** A call with a Key.

1. The gate: Key, plan, price. Or 402: with a cure.
2. Forward (admitted): to the origin.
3. Origin (signed): your own server. Or 502: free.
4. Metered (answered): once.
5. Reply (checked): cost and receipt.

The gate runs as on every product; only the answer comes from your origin.

## A lookup, fronted
A lookup by domain that already runs on its own server fronts it, priced per answer, keeping its old paths.

```ts title="definition.ts"
import { define, secret } from 'apis.dev'

/** Any company by its domain, with its headcount and sector, from the server that already answers it. */
export default define({
  name: 'companyfacts', domain: 'companyfacts.apis.dev',
  sources: {
    legacy: {
      origin: 'https://api.example.com', key: secret('LEGACY_KEY'),
      front: {
        'Company.get':    'GET /v2/companies/{domain}',
        'Company.search': 'GET /v2/companies',
      },
      paths: 'keep',                        // /v2/companies/acme.com still answers
    },
  },
  Company: { domain: 'url!#', employees: 'number?', sector: 'string?' },
  offer: {
    'Company.get': 0.002, 'Company.search': 0.005,
    free: { 'Company.get': 100 },
  },
})
```

The reply is the origin's body, checked against `Company`, with the product's headers on it.

```http title="Response"
HTTP/1.1 200 OK
Content-Type: application/json
X-Cost: price=0.002, currency="USD"
X-Receipt-Id: rcpt_9
X-Request-Id: req_1f7c3a9e0d28b56e4c19

{
  "domain": "acme.com",
  "employees": 240,
  "sector": "Software"
}
```

## Old callers change nothing
With `paths: 'keep'`, each fronted route also answers at its old path, beside the Verb's own address.

Imported [Keys](/reference/platform.md#key) keep working under their old prefix, as an [import](/lifecycle/import.md) leaves them. From Launch, the old hostname points at the product as one of your Domains, so an old client changes no line.

A refused call costs nothing and never reaches the origin. A call the origin fails, or does not answer in time, answers 502 [`origin_failed`](/reference.md#origin_failed) at no charge, and alerts your [on-call route](/trust/alerts.md).

## What the front adds, and what it leaves
The origin keeps its logic and its records. The product adds everything a seller needs around it.

| Before the call | After the call | Untouched |
| --- | --- | --- |
| The [Key](/reference/platform.md#key), the plan, `Max-Cost`, the 402 and its cure | `X-Cost`, the metered charge and the signed receipt | Your origin's code and its database |
| The brakes, the rate limits and the [fraud](/trust/fraud.md) checks | The [call record](/reference/platform.md#call-record), analytics and the alerts | Its own credentials, held as a secret |
| The mandate and payment checks for an agent | The reply's shape against the Noun, when the Noun types it | Its deploys, on its own schedule |

The origin receives the call with the [Source](/patterns/dataset-api.md#how-a-field-is-filled)'s credential and three headers: `Apis-Customer`, `Apis-Request-Id` and `Apis-Signature`. The signature lets the origin refuse any call that skipped the gate.

## Port one Verb at a time
To move a Verb off the origin, give its fields a `from` and a `map`, or a [Function](/patterns/function-api.md). Then remove its line from `front`.

Its address, its price and every Key stay as they were, so a Customer never sees the move. When `front` holds no line, the origin can stop.