Tileset API
Estimated reading time: 10 minutesThe Tileset API lets you create and manage your own tilesets. A tileset is a collection of raster or vector tiles that can be displayed on a map. Each tileset can have an optional TileJSON descriptor and a Recipe that defines how its tiles are generated.
Tileset object
{
"id": "3c2de33f-7e88-4ecb-941c-0fece5ed0434",
"ownerId": "258728f5-cb37-491f-b345-eb2d6868cdd3",
"creationDate": "2024-01-15T10:30:00Z",
"createdBy": "258728f5-cb37-491f-b345-eb2d6868cdd3",
"lastUpdate": "2024-01-15T10:30:00Z",
"updatedBy": "258728f5-cb37-491f-b345-eb2d6868cdd3",
"private": true,
"ttl": null
}| Field | Type | Description |
|---|---|---|
id |
string | Unique identifier of the tileset. |
ownerId |
UUID | UUID of the account that owns the tileset. |
creationDate |
datetime | ISO 8601 timestamp of when the tileset was created. |
createdBy |
UUID | UUID of the identity that created the tileset. |
lastUpdate |
datetime | ISO 8601 timestamp of the last modification. |
updatedBy |
UUID | UUID of the identity that last modified the tileset. |
private |
boolean | Whether the tileset is private. |
ttl |
integer | Time To Live in seconds. After this delay the tileset and all its sub-resources are deleted automatically. null means no expiry. |
Access Token
Before accessing the Tileset API, you need a valid access token. You can get your access tokens in your Jawg App account.
All requests must include the access-token query parameter:
https://api.jawg.io/tilesets?access-token={your-access-token}Create a tileset
Creates a new tileset and returns it with its generated id.
POST https://api.jawg.io/tilesets?access-token={your-access-token}Request body
{
"id": "my-tileset", // optional — generated if absent
"ownerId": "258728f5-cb37-491f-b345-eb2d6868cdd3", // optional
"ttl": 3600 // optional — seconds until auto-deletion
}| Field | Type | Required | Description |
|---|---|---|---|
id |
string | No | Desired tileset identifier. A UUID is generated if absent. |
ownerId |
UUID | No | Owner of the tileset. Defaults to the authenticated user's account. |
ttl |
integer | No | Time To Live in seconds. The tileset and all its sub-resources are deleted after this delay. Useful for preview tilesets. |
Response
// HTTP 201 Created
// Location: /tilesets/3c2de33f-7e88-4ecb-941c-0fece5ed0434
{
"id": "3c2de33f-7e88-4ecb-941c-0fece5ed0434",
"ownerId": "258728f5-cb37-491f-b345-eb2d6868cdd3",
"creationDate": "2024-01-15T10:30:00Z",
"createdBy": "258728f5-cb37-491f-b345-eb2d6868cdd3",
"lastUpdate": "2024-01-15T10:30:00Z",
"updatedBy": "258728f5-cb37-491f-b345-eb2d6868cdd3",
"private": true,
"ttl": null
}Error codes
| HTTP | Description |
|---|---|
| 400 | The request body is invalid. |
| 403 | The authenticated identity does not have the required permission. |
Retrieve a tileset
Returns the tileset with the given id.
GET https://api.jawg.io/tilesets/{id}?access-token={your-access-token}Path parameters
idrequired: The unique identifier of the tileset.
Response
// HTTP 200 OK
{
"id": "3c2de33f-7e88-4ecb-941c-0fece5ed0434",
"ownerId": "258728f5-cb37-491f-b345-eb2d6868cdd3",
"creationDate": "2024-01-15T10:30:00Z",
"createdBy": "258728f5-cb37-491f-b345-eb2d6868cdd3",
"lastUpdate": "2024-01-15T10:30:00Z",
"updatedBy": "258728f5-cb37-491f-b345-eb2d6868cdd3",
"private": true,
"ttl": null
}Error codes
| HTTP | Description |
|---|---|
| 404 | No tileset found with the given id. |
Delete a tileset
Deletes the tileset with the given id. This also removes its associated TileJSON and Recipe.
DELETE https://api.jawg.io/tilesets/{id}?access-token={your-access-token}Path parameters
idrequired: The unique identifier of the tileset.
Response
HTTP 204 No ContentError codes
| HTTP | Description |
|---|---|
| 404 | No tileset found with the given id. |
TileJSON
A TileJSON is a JSON document that describes a tileset: its tile URL template, zoom range, bounds, and other metadata. It is the standard way to configure a tile source in MapLibre GL JS.
The TileJSON is optional. If no TileJSON has been set for a tileset, the endpoint returns HTTP 404 Not Found.
See the latest version of TileJSON specification for more details.
Retrieve the TileJSON
Returns the TileJSON descriptor for the tileset with the given id.
GET https://api.jawg.io/tilesets/{id}.json?access-token={your-access-token}Path parameters
idrequired: The unique identifier of the tileset.
The
idparameter can be a concatenation of multiple ids separated by a+character.
Query parameters
sizeoptional (integer): The size of the tiles in pixels. Mostly useful for raster tiles.scaleoptional (integer): The pixel density scale factor for the tiles. Useful for high-DPI displays with raster tiles. Valid values are1and2.formatoptional (string): The format of the tiles. Examples:pbf,png.langoptional (string): The language of the tile labels. Useful for raster tiles since vector tiles can choose the displayed language client-side. Valid values arede,en,es,fr,it,ja,ko,nl,ru,zh. Useintfor international labels.
Example request
GET https://api.jawg.io/tilesets/3c2de33f-7e88-4ecb-941c-0fece5ed0434.json?access-token={your-access-token}Response
// HTTP 200 OK
{
"tilejson": "3.0.0",
"name": "My tileset",
"description": "A description of my tileset",
"version": "1.0.0",
"attribution": "© Jawg",
"scheme": "xyz",
"tiles": [
"https://tile.jawg.io/3c2de33f-7e88-4ecb-941c-0fece5ed0434/{z}/{x}/{y}.pbf?access-token={your-access-token}"
],
"minzoom": 0,
"maxzoom": 14,
"bounds": [-180, -85.05113, 180, 85.05113],
"center": [0, 0, 2]
}Error codes
| HTTP | Description |
|---|---|
| 404 | No TileJSON has been set for this tileset. |
| 404 | No tileset found with the given id. |
Update the TileJSON
Creates or replaces the TileJSON descriptor for the tileset with the given id.
PUT https://api.jawg.io/tilesets/{id}.json?access-token={your-access-token}Path parameters
idrequired: The unique identifier of the tileset.
Request body
The body must be a valid TileJSON object.
{
"tilejson": "3.0.0",
"name": "My tileset",
"description": "A description of my tileset",
"version": "1.0.0",
"attribution": "© Jawg",
"scheme": "xyz",
"tiles": [
"https://tile.jawg.io/3c2de33f-7e88-4ecb-941c-0fece5ed0434/{z}/{x}/{y}.pbf?access-token={your-access-token}"
],
"minzoom": 0,
"maxzoom": 14,
"bounds": [-180, -85.05113, 180, 85.05113],
"center": [0, 0, 2]
}Response
// HTTP 200 OK
{
"tilejson": "3.0.0",
"name": "My tileset",
"description": "A description of my tileset",
"version": "1.0.0",
"attribution": "© Jawg",
"scheme": "xyz",
"tiles": [
"https://tile.jawg.io/3c2de33f-7e88-4ecb-941c-0fece5ed0434/{z}/{x}/{y}.pbf?access-token={your-access-token}"
],
"minzoom": 0,
"maxzoom": 14,
"bounds": [-180, -85.05113, 180, 85.05113],
"center": [0, 0, 2]
}Error codes
| HTTP | Description |
|---|---|
| 404 | No tileset found with the given id. |
Recipe
A Recipe is a JSON document that describes how a tileset's tiles are generated: the data sources, layers, zoom ranges, and rendering rules.
The Recipe is optional. If no recipe has been set for a tileset, the endpoint returns HTTP 404 Not Found.
Retrieve the recipe
Returns the recipe for the tileset with the given id.
GET https://api.jawg.io/tilesets/{id}/recipe?access-token={your-access-token}Path parameters
idrequired: The unique identifier of the tileset.
Response
// HTTP 200 OK
{
"version": "1",
"layers": {
"bus-stops": [
{
"sources": [ { "type": "fs2", "collectionId": "my-bus-stops" } ],
"minZoom": 12,
"maxZoom": 16
}
]
}
}Error codes
| HTTP | Description |
|---|---|
| 404 | No recipe has been set for this tileset. |
| 404 | No tileset found with the given id. |
Update the recipe
Creates or replaces the recipe for the tileset with the given id.
PUT https://api.jawg.io/tilesets/{id}/recipe?access-token={your-access-token}Path parameters
idrequired: The unique identifier of the tileset.
Request body
The body must be a valid Recipe object. See the Recipe Specification for the full format.
{
"version": "1",
"layers": {
"bus-stops": [
{
"sources": [ { "type": "fs2", "collectionId": "my-bus-stops" } ],
"minZoom": 12,
"maxZoom": 16
}
]
}
}Response
// HTTP 200 OK
{
"version": "1",
"layers": {
"bus-stops": [
{
"sources": [ { "type": "fs2", "collectionId": "my-bus-stops" } ],
"minZoom": 12,
"maxZoom": 16
}
]
}
}Error codes
| HTTP | Description |
|---|---|
| 400 | The recipe body is invalid. |
| 404 | No tileset found with the given id. |
Delete the recipe
Removes the recipe from the tileset with the given id. The tileset itself is not deleted.
DELETE https://api.jawg.io/tilesets/{id}/recipe?access-token={your-access-token}Path parameters
idrequired: The unique identifier of the tileset.
Response
HTTP 204 No ContentError codes
| HTTP | Description |
|---|---|
| 404 | No tileset found with the given id. |
Recipe Specification
A Recipe is a JSON document that describes how to transform feature collections into vector tiles. It defines the layers of the output tileset, where features come from, how they are filtered and transformed, and how the tiles are built.
Top-level structure
| Field | Type | Description |
|---|---|---|
version |
string | Recipe schema version. Must be "1". |
layers |
object | Map of layer name → array of layer definitions. Keys become the vector tile layer names. |
{
"version": "1",
"layers": {
"bus-stops": [ ... ],
"train-stations": [ ... ]
}
}Layer
Each entry in layers is an array of layer definitions (a layer group). Using multiple definitions under the
same name lets you apply different rules at different zoom levels.
| Field | Type | Required | Description |
|---|---|---|---|
sources |
array | Yes | Feature sources to read from. |
minZoom |
integer | Yes | Minimum zoom level (inclusive) at which this layer is generated. |
maxZoom |
integer | Yes | Maximum zoom level (inclusive) at which this layer is generated. |
features |
object | No | Input feature configuration (filtering, property transforms, etc.). |
tiles |
object | No | Tile-level configuration (extent, buffer, density, aggregation, etc.). |
{
"sources": [ { "type": "fs2", "collectionId": "my-bus-stops" } ],
"minZoom": 9,
"maxZoom": 14,
"features": { ... },
"tiles": { ... }
}Layer group — different rules per zoom range
{
"version": "1",
"layers": {
"bus-stops": [
{
"sources": [ { "type": "fs2", "collectionId": "my-bus-stops" } ],
"minZoom": 8,
"maxZoom": 11
},
{
"sources": [ { "type": "fs2", "collectionId": "my-bus-stops" } ],
"minZoom": 12,
"maxZoom": 16,
"features": { ... },
"tiles": { ... }
}
]
}
}Source
A source defines where to read features from. Multiple sources can be listed in one layer and their features
are merged. Currently, only the fs2 (FeatureStorageService) sources are supported.
fs2 source — FeatureStorageService
Reads features from a Feature Collection.
| Field | Type | Description |
|---|---|---|
type |
string | Must be "fs2". |
collectionId |
string | Identifier of the feature collection to read. |
{ "type": "fs2", "collectionId": "my-bus-stops" }Feature configuration (features)
Controls how source features are processed before being added to tiles.
| Field | Type | Description |
|---|---|---|
filter |
expression | Filter which features are included. Must evaluate to a boolean. Features that evaluate to false are discarded. |
properties |
object | Controls how feature properties are modified. |
geometries |
array | Controls geometry transformations applied to features. |
simplification |
number | Distance tolerance for Douglas-Peucker simplification. Value is relative to the tile extent. |
limit |
integer | Maximum number of input features to process. |
Filter
The filter field is a MapLibre Expression that returns a boolean. Features where the expression evaluates to false are discarded.
{
"filter": [
"all",
["==", ["geometry-type"], "Point"],
["==", ["get", "type"], "shop"]
]
}Properties — put
The properties.put map adds or replaces feature properties using expressions. Keys are the property names to write,
values are literal values or MapLibre Expressions.
{
"put": {
"rank": ["match", ["get", "type"], "oak", 1, "birch", 1, "willow", 2, 4],
"count": 1
}
}Geometries — center transformation
The geometries array applies geometry transformations. The center transformation reduces any geometry to a single
representative point: unchanged for Point / MultiPoint, midpoint for LineString / MultiLineString, and a
point-on-surface for Polygon / MultiPolygon.
{
"geometries": [
{ "type": "center" }
]
}Tile configuration (tiles)
Controls how the vector tile is built from the processed features.
| Field | Type | Required | Description |
|---|---|---|---|
extent |
integer | Yes | Tile coordinate extent. Typical value: 4096. |
buffer |
number | Yes | Tile buffer as a percentage of the extent. Avoids labels and geometries clipping at tile edges. |
layerSize |
integer | Yes | Maximum layer size in bytes. |
limit |
integer | No | Maximum number of features in the tile. Features are dropped once the limit is reached. |
density |
object | No | Limits feature density by dividing the tile into a grid and capping features per cell. |
aggregate |
object | No | Aggregates features by merging their geometries and combining their properties. |
{
"extent": 4096,
"buffer": 10.0,
"layerSize": 500000,
"limit": 100000,
"density": { ... },
"aggregate": { ... }
}Density
Divides the tile into a grid and limits how many features can appear in each cell. Useful for thinning out point datasets at low zoom levels.
| Field | Type | Required | Description |
|---|---|---|---|
limit |
integer | Yes | Maximum number of features per grid cell. |
size |
integer | Yes | Grid cell size in tile extent units. A size of 32 over a 4096-extent tile creates a 128×128 grid. |
groupBy |
expression | No | Apply the density reduction per group. Typical use-case: group by level so features at different levels don't compete for the same cell. Default: no grouping. |
global |
boolean | No | If true, the density limit is shared across all layers in the tile. Default: false (limit is local to the layer). |
{
"limit": 256,
"size": 64,
"groupBy": ["get", "level"],
"global": true
}Aggregation
Merges features together before writing them to the tile. This is useful to cluster points or union geometries.
| Field | Type | Required | Description |
|---|---|---|---|
groupBy |
array | No | Property keys to group features by before aggregating. Features with the same values are merged. |
geometry |
object | Yes | Geometry aggregation definition. |
properties |
object | No | Property aggregation functions. Keys are property names, values are aggregation functions. |
Properties not listed in
groupBynor inpropertiesare removed from aggregated features.
Geometry aggregation — cluster
Merges nearby points into a single centroid and records the count.
| Field | Type | Description |
|---|---|---|
type |
string | Must be "cluster". |
size |
number | Size of one cluster cell, relative to the tile extent. |
property |
string | Name of the property that will hold the cluster count. |
{ "type": "cluster", "size": 512.0, "property": "count" }Geometry aggregation — union
Merges line and polygon geometries that are close to each other.
| Field | Type | Description |
|---|---|---|
type |
string | Must be "union". |
threshold |
number | Distance at which two geometries are considered touching. |
{ "type": "union", "threshold": 0.5 }Property aggregation functions
Valid values are sum, min, max, mean.
{
"price": "mean",
"length": "sum"
}Complete example
{
"version": "1",
"layers": {
"bus-stops": [
{
"sources": [ { "type": "fs2", "collectionId": "my-bus-stops" } ],
"minZoom": 9,
"maxZoom": 14,
"features": {
"filter": [
"all",
["==", ["geometry-type"], "Point"],
["match", ["get", "line_number"], ["80", "82", "84"], true, false]
],
"properties": {
"put": {
"rank": ["match", ["get", "speed"], "fast", 1, "medium", 2, "low", 3, 4],
"count": 1
}
},
"simplification": 4,
"limit": 100000
},
"tiles": {
"extent": 4096,
"buffer": 10.0,
"layerSize": 500000,
"limit": 100000,
"density": {
"limit": 256,
"size": 64
},
"aggregate": {
"groupBy": ["line_number"],
"geometry": {
"type": "cluster",
"size": 512.0,
"property": "count"
},
"properties": {
"price": "mean",
"length": "sum"
}
}
}
}
]
}
}