> ## Documentation Index
> Fetch the complete documentation index at: https://docs.corsair.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Mapbox plugin

> Geocode addresses and coordinates, get routes, travel-time matrices, isochrones and optimized trips, and query vector tilesets with Mapbox.

Use **Mapbox** through Corsair: one client, typed API calls.

Mapbox authenticates with an `access_token` query parameter. Create a token
at [account.mapbox.com/access-tokens](https://account.mapbox.com/access-tokens/)
(a default public `pk.` token works for every operation here), then save it for
the `mapbox` integration. A call with no saved token throws `AuthMissingError`.
The plugin never copies the token into an error. Mapbox has a free tier
(see its pricing page for the allowance per API), so the plugin is cheap to
try. Mapbox's terms allow geocoding responses to be used only together with a
Mapbox map, and the plugin uses temporary geocoding, whose results must not
be cached or stored for later use.

Every operation is a read. Things to know:

* **Longitude comes first.** Coordinates are `{ longitude, latitude }`
  objects, and the plugin writes them into URLs as `longitude,latitude` as
  Mapbox expects. A latitude outside -90 to 90 or a longitude outside -180 to
  180 is rejected before a request is sent.
* **Profiles** are `mapbox/driving-traffic`, `mapbox/driving`,
  `mapbox/walking` and `mapbox/cycling`, with the `mapbox/` prefix.
* **No match is not an error for geocoding.** A query with no result is a
  successful answer with an empty `features` list.
* **No route is an error for routing.** Directions, matrix and trip calls
  that Mapbox answers with HTTP 200 and `code: 'NoRoute'`, `'NoSegment'` or
  `'NotImplemented'` throw a `MapboxAPIError` carrying that code, rather than
  returning an empty `routes` list.
* **Mapbox silently ignores some bad values**, so the plugin rejects them
  first: a geocoding `limit` above 10 (above 5 for reverse), isochrone contours
  that are not strictly increasing, `annotations` without `overview: 'full'`,
  `language` without `steps: true`, and `exclude` values the profile does not
  support.
* **Reverse geocoding** needs exactly one entry in `types` when `limit` is
  above 1.
* **Limits** are per product and per minute, and Mapbox reports yours in
  `x-rate-limit-limit`; a default token showed 1,000 for geocoding v6, 300 for
  directions and isochrone, 60 for matrix and 50 for tilequery. A 429 is
  retried twice, waiting for `x-rate-limit-reset`, or 60 seconds when Mapbox
  sends no timing header.
* **Left out.** The Static Images API returns PNG bytes, which the shared HTTP
  client cannot return intact. Optimization v2 (`/optimized-trips/v2`, async
  jobs) answered 403 `Account does not have access to this service` on a
  default token, so only Optimization v1, which answers immediately, is
  wrapped as `trips.optimize`. Geocoding's `permanent` storage flag, batch
  geocoding and structured input are not wrapped.
* **Webhooks.** Mapbox sends none for these APIs, so the plugin handles none.

**What you get:**

* 7 typed API operations

## Setup

**1. Install**

```bash npm theme={null}
npm install corsair @corsair-dev/mapbox better-sqlite3
npm install --save-dev @types/better-sqlite3
```

```bash yarn theme={null}
yarn add corsair @corsair-dev/mapbox better-sqlite3
yarn add --dev @types/better-sqlite3
```

```bash pnpm theme={null}
pnpm install corsair @corsair-dev/mapbox better-sqlite3
pnpm install --save-dev @types/better-sqlite3
```

```bash bun theme={null}
bun add corsair @corsair-dev/mapbox better-sqlite3
bun add --dev @types/better-sqlite3
```

**2. Add the plugin**

```ts corsair.ts theme={null}
import Database from 'better-sqlite3';
import { createCorsair } from 'corsair';
import { mapbox } from '@corsair-dev/mapbox';

export const corsair = createCorsair({
	plugins: [
		mapbox(),
	],
	database: new Database('corsair.db'),
	kek: process.env.CORSAIR_KEK!,
	multiTenancy: true,
	hub: {
		projectApiKey: process.env.CORSAIR_API_KEY!,
		signingSecret: process.env.CORSAIR_SIGNING_SECRET!,
	},
});
```

With `multiTenancy: true`, scope calls with `corsair.withTenant(id)`. See [Quick start](https://docs.corsair.dev/quick-start.md) for KEK + Hub keys, and [Multi-tenancy](https://docs.corsair.dev/concepts/multi-tenancy.md) for account isolation.

**3. Choose authentication**

> [tab] API Key (Recommended)
>
> No setup required yet. When you make your first request as a tenant, Corsair prompts for the API key.
>
> ```ts theme={null}
> mapbox()
> ```
>
> More: [API Key](https://docs.corsair.dev/concepts/api-key)

**4. Connect a tenant**

Mint a connect link and send the tenant to it. Hub hosts the page and delivers the result to your app — see [Connect / OAuth](https://docs.corsair.dev/management/connect).

```ts theme={null}
const { connectUrl } = await corsair.manage.connect.createLink({
	plugin: 'mapbox',
	tenantId: 'acme',
});
// redirect the user's browser to connectUrl
```

## Example API calls

**Find a place by name**

```ts theme={null}
const tenant = corsair.withTenant('acme');
await tenant.mapbox.api.geocoding.forward({ q: 'Paris', limit: 3 });
```

**Write**

*No write-style endpoint inferred; pick any operation from the [API](https://docs.corsair.dev/plugins/mapbox/api.md) reference.*

See the full list on the [API](https://docs.corsair.dev/plugins/mapbox/api.md) page.

## What's next

> [card] [API reference](https://docs.corsair.dev/plugins/mapbox/api.md)
>
> Every `mapbox.api.*` operation with input and output types.

> [card] [Connect / OAuth](https://docs.corsair.dev/management/connect)
>
> createLink, Hub delivery, and tenant connect flows.

> [card] [Use with agents](https://docs.corsair.dev/mcp-adapters/mcp-adapters)
>
> Expose this plugin's operations as MCP tools.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.