NAV
cURL

Resource Watch API Reference

This section of the documentation contains technical reference information for each of the endpoints exposed by the RW API.

Back to the documentation homepage

Authentication

Most RW API endpoints are public, but some actions require user authentication. Each endpoint's documentation will specify whether authentication is required and under whate conditions.

The RW API uses JSON Web Tokens to authenticate requests. Check out the Quickstart Guide for instructions on how to create an account and generate a token.

Authentication is performed using bearer auth. For all authenticated requests, you must provide your JWT using the header Authorization: Bearer <your token>.

If you lose your JWT, or if it becomes invalidated (which happens whenever the name, email, or applications associated with your account changes), you can always log in via the browser and generate a new token at https://api.resourcewatch.org/auth/generate-token.

Dataset

What is a dataset?

If you are new to the RW API, or want to learn more about the concept of a dataset, we strongly encourage you to read the dataset concept documentation first. It gives you a brief and clear description of what a dataset is, and what it can do for you.

Once you've read that section, you can come back here to learn more details about using the RW API's datasets feature. The RW API is home to many datasets uploaded by WRI, its partner organizations, or by API users like you. These datasets contain a lot of information about a wide range of topics that you may want to learn about or build on top of. To find out more about finding and accessing the datasets already available on the RW API, check out the documentation on getting datasets. A nice, visual way to explore existing datasets is by using the Resource Watch website.

You can also create you own datasets on the RW API, if you'd like to share your data with the world, or if you are looking to use the RW API and its features to gain insights into your data.

Getting all datasets

This endpoint will allow you to get the list of the datasets available in the API, and it's a great place for new users to start exploring the RW API. By default, this endpoint will give you a paginated list of 10 datasets. In the sections below, we'll explore how you can customize this endpoint call to match your needs.

For a detailed description of each field, check out the Dataset reference section.

Getting a list of datasets

curl -X GET https://api.resourcewatch.org/v1/dataset

Response:

{
    "data": [
        {
        "id": "00f2be42-1ee8-4069-a55a-16a988f2b7a0",
        "type": "dataset",
        "attributes": {
            "name": "Glad points",
            "slug": "Glad-points-1490086842129",
            "type": null,
            "subtitle": null,
            "application": ["data4sdgs"],
            "dataPath": null,
            "attributesPath": null,
            "connectorType": "document",
            "provider": "csv",
            "userId": "58333dcfd9f39b189ca44c75",
            "connectorUrl": "http://gfw2-data.s3.amazonaws.com/alerts-tsv/glad_headers.csv",
            "sources": [],
            "tableName": "data",
            "status": "pending",
            "published": true,
            "overwrite": false,
            "env": "production",
            "geoInfo": false,
            "legend": {
                "date": [],
                "region": [],
                "country": []
                },
            "clonedHost": {},
            "errorMessage": null,
            "updatedAt": "2017-01-13T10:45:46.368Z",
            "widgetRelevantProps": [],
            "layerRelevantProps": []
            }
        }
  ],
  "links": {
    "self": "http://api.resourcewatch.org/v1/dataset?page[number]=1&page[size]=10",
    "first": "http://api.resourcewatch.org/v1/dataset?page[number]=1&page[size]=10",
    "last": "http://api.resourcewatch.org/v1/dataset?page[number]=99&page[size]=10",
    "prev": "http://api.resourcewatch.org/v1/dataset?page[number]=1&page[size]=10",
    "next": "http://api.resourcewatch.org/v1/dataset?page[number]=2&page[size]=10"
  },
  "meta": {
    "total-pages": 99,
    "total-items": 990,
    "size": 10
  }
}

Pagination

Example request to load page 2 using 25 results per page

curl -X GET https://api.resourcewatch.org/v1/dataset?page[number]=2&page[size]=25

The Dataset service adheres to the conventions defined in the Pagination guidelines for the RW API, so we recommend reading that section for more details on how paginate your datasets list.

Search for datasets

curl -X GET https://api.resourcewatch.org/v1/dataset?search=wind

The dataset service offers a simple yet powerful search mechanism that will help you look for datasets. The query argument search allows you to specify a search string that will match:

Filters

Filtering datasets

curl -X GET https://api.resourcewatch.org/v1/dataset?name=birds&provider=cartodb

Matching vocabulary tags

curl -X GET https://api.resourcewatch.org/v1/dataset?vocabulary[legacy]=umd

The dataset list provides a wide range of parameters that you can use to tailor your dataset listing. Most of these parameters reflect fields you'll find in a dataset itself (which you can learn more about in the Dataset reference section), while others are convenience filters for things like user role or favourites.

Filtering datasets adheres to the conventions defined in the Filter guidelines for the RW API, so we strongly recommend reading that section before proceeding. In addition to these conventions, you can use the following fields as filters supported by the dataset list endpoint:

Filter Description Type Expected values
name Filter returned datasets by the name of the dataset. String any valid text
slug Filter returned datasets by the slug of the dataset. String any valid text
type Filter returned datasets by dataset type. String any valid text
subtitle Filter returned datasets by dataset subtitle. String any valid text
application Applications associated to this dataset. Read more about this field here. Array any valid text
applicationConfig If the dataset has applicationConfig data (i.e. contains a non-empty object in the applicationConfig field) Boolean true or false
dataPath String any valid text
attributesPath String any valid text
connectorType Filter returned datasets by the type of connector used. String rest, document or wms
provider Dataset provider this include inner connectors and 3rd party ones String Check the available providers when creating a dataset
connectorUrl String any valid text
sources Array any valid text
tableName String any valid text
userId Filter results by the owner of the dataset. Does not support regexes. String valid user id
status Filter results by the current status of the dataset. String pending, saved or failed
overwrite If the data can be overwritten (only for being able to make dataset updates) Boolean trueor false
errorMessage If this dataset is in error state, this field may contain additional details about the error. String any valid text
mainDateField String any valid text
published If the dataset is published or not. Boolean trueor false
env Environment to which the dataset belongs. Multiple values can be combined using , as a separator. Does not support regexes. Read more about this field in the Environments concept section. String any valid text. Defaults to production.
geoInfo If it contains interceptable geographical info Boolean trueor false
protected If the dataset is protected. Boolean trueor false
taskId Id of the latest task associated with this dataset. Typically only present in document connectorType datasets String any valid text
legend.lat String any valid text
legend.long String any valid text
legend.date Array any valid text
legend.region Array any valid text
legend.country Array any valid text
legend.nested Array any valid text
legend.integer Array any valid text
legend.short Array any valid text
legend.byte Array any valid text
legend.double Array any valid text
legend.byte Array any valid text
legend.float Array any valid text
legend.half_float Array any valid text
legend.scaled_float Array any valid text
legend.boolean Array any valid text
legend.binary Array any valid text
legend.text Array any valid text
legend.keyword Array any valid text
clonedHost.hostProvider String any valid text
clonedHost.hostUrl String any valid text
clonedHost.hostId String any valid text
clonedHost.hostType String any valid text
clonedHost.hostPath String any valid text
widgetRelevantProps Array any valid text
layerRelevantProps Array any valid text
subscribable If the dataset is subscribable (i.e. contains a non-empty object in the subscribable field) Boolean true or false
user.role Filter results by the role of the owner of the dataset. If the requesting user does not have the ADMIN role, this filter is ignored. String ADMIN, MANAGER or USER
vocabulary[name] Filter returned datasets by vocabulary tags. Does not support regexes. String any valid text
collection Filter returned datasets collection id. Does not support regexes. String any valid text
favourite Filter by favourited datasets. See this section for more info. Does not support regexes. String any valid text

Sorting

Basics of sorting

Sorting datasets

curl -X GET https://api.resourcewatch.org/v1/dataset?sort=name

Sorting datasets by multiple criteria

curl -X GET https://api.resourcewatch.org/v1/dataset?sort=name,description

Sort by name descending, description ascending

curl -X GET https://api.resourcewatch.org/v1/dataset?sort=-name,+description

Sorting datasets by the role of the user who owns the dataset

curl -X GET https://api.resourcewatch.org/v1/dataset?sort=user.role

The Dataset service currently supports sorting using the sort query parameter. Sorting dataset adheres to the conventions defined in the Sorting guidelines for the RW API, so we strongly recommend reading that section before proceeding. Additionally, you can check out the Dataset reference section for a detailed description of the fields you can use when sorting. In addition to all dataset model fields, you can sort the returned results by the name (using user.name) or role (using user.role) of the user owner of the dataset. Keep in mind that sorting by user data is restricted to ADMIN users.

Special sorting criteria

Sorting datasets with special criteria

curl -X GET https://api.resourcewatch.org/v1/dataset?sort=-most-favorited
curl -X GET https://api.resourcewatch.org/v1/dataset?sort=relevance&status=saved&search=agriculture

Special search criteria must be used as sole sorting criteria, as it's not possible to combine any of them with any other search criteria. The following criteria can be used for special sorting in datasets:

You can specify the sorting order by prepending the criteria with either - for descending order or + for ascending order. By default, ascending order is assumed.

Include entities associated with the datasets

Loads metadata and widgets associated with each dataset:

curl -X GET https://api.resourcewatch.org/v1/dataset?includes=metadata,widget
{
    "data": [
        {
            "id": "06c44f9a-aae7-401e-874c-de13b7764959",
            "type": "dataset",
            "attributes": {
                "name": "Historical Precipitation -- U.S. (Puget Sound Lowlands)",
                "slug": "Historical-Precipitation-US-Puget-Sound-Lowlands-1490086842133",
                ...
                "metadata": [
                    {  

                        "id": "57a2251d5cd6980a00e054d9",
                        "type": "metadata",
                        "attributes": { ... }
                    }
                ],
                "widget": [
                    {  
                        "id": "73f00267-fe34-42aa-a611-13b102f38d75",
                        "type": "widget",
                        "attributes": { ... }
                    }
                ]
            }
        }
    ],
    "links": {
        "self": "http://api.resourcewatch.org/v1/dataset?includes=widget%2Cmetadata&page[number]=1&page[size]=10",
        "first": "http://api.resourcewatch.org/v1/dataset?includes=widget%2Cmetadata&page[number]=1&page[size]=10",
        "last": "http://api.resourcewatch.org/v1/dataset?includes=widget%2Cmetadata&page[number]=223&page[size]=10",
        "prev": "http://api.resourcewatch.org/v1/dataset?includes=widget%2Cmetadata&page[number]=1&page[size]=10",
        "next": "http://api.resourcewatch.org/v1/dataset?includes=widget%2Cmetadata&page[number]=2&page[size]=10"
    },
    "meta": {
        "total-pages": 223,
        "total-items": 2228,
        "size": 10
    }
}

Loading layers for the given dataset

curl -X GET http://api.resourcewatch.org/dataset?includes=layer

Loading the information about the user who authored the dataset

curl -X GET https://api.resourcewatch.org/v1/dataset?includes=user

When fetching datasets, you can request additional entities to be loaded. The following entities are available:

Note: If you include related entities (e.g. layers) with query filters, the filters will not cascade to the related entities.

Getting a dataset by id or slug

Getting a dataset by id:

curl -X GET "https://api.resourcewatch.org/v1/dataset/51943691-eebc-4cb4-bdfb-057ad4fc2145"

Getting a dataset by slug:

curl -X GET "https://api.resourcewatch.org/v1/dataset/Timber-Production-RDC"

Response (equal for both cases):

{
    "data": {
        "id": "51943691-eebc-4cb4-bdfb-057ad4fc2145",
        "type": "dataset",
        "attributes": {
            "name": "Timber Production RDC",
            "slug": "Timber-Production-RDC",
            "type": null,
            "subtitle": null,
            "application": ["forest-atlas"],
            "dataPath": null,
            "attributesPath": null,
            "connectorType": "document",
            "provider": "csv",
            "userId": "58750a56dfc643722bdd02ab",
            "connectorUrl": "http://wri-forest-atlas.s3.amazonaws.com/COD/temp/annual%20timber%20production%20DRC%20%28test%29%20-%20Sheet1.csv",
            "sources": [],
            "tableName": "index_51943691eebc4cb4bdfb057ad4fc2145",
            "status": "saved",
            "overwrite": false,
            "legend": {
                "date": ["year"],
                "region": [],
                "country": [],
                "long": "",
                "lat": ""
            },
            "clonedHost": {},
            "errorMessage": null,
            "createdAt": "2017-01-25T21:48:27.535Z",
            "updatedAt": "2017-01-25T21:48:28.675Z"
        }
    }
}

If you know the id or the slug of a dataset, then you can access it directly. Both id and slug are case-sensitive.

Using this endpoint, you can also include entities associated with the dataset, in the same way you do when loading multiple datasets.

Getting a dataset by its including its relationships:

curl -X GET https://api.resourcewatch.org/v1/dataset/06c44f9a-aae7-401e-874c-de13b7764959?includes=metadata,vocabulary,widget,layer

Getting multiple datasets by ids

This endpoint allows you to load multiple datasets by id in a single request.

Errors for getting multiple datasets by ids

Error code Error message Description
400 ids: ids can not be empty. The required ids field is missing in the request body.

Getting multiple datasets by their ids:

curl -X POST https://api.resourcewatch.org/v1/dataset/find-by-ids \
-H "Content-Type: application/json"  -d \
'{
    "ids": [
        "0706f039-b929-453e-b154-7392123ae99e",
        "0c630feb-8146-4fcc-a9be-be5adcb731c8",
    ]
}'

Response

    {
        "data": [
          {
            "id": "0706f039-b929-453e-b154-7392123ae99e",
            "type": "dataset",
            "attributes": {
              "name": "Social Vulnerability Index (2006-2010) -- U.S. (New Hampshire)",
              "slug": "Social-Vulnerability-Index-2006-2010-US-New-Hampshire-1490086842541",
              "type": "tabular",
              "subtitle": null,
              ...
            }
          },
          {
            "id": "0c630feb-8146-4fcc-a9be-be5adcb731c8",
            "type": "dataset",
            "attributes": {
              "name": "USGS Land Cover - Impervious Surface (2001) -- U.S. (Alaska)",
              "slug": "USGS-Land-Cover-Impervious-Surface-2001-US-Alaska-1490086842439",
              "type": "raster",
              "subtitle": null,
              ...
            }
          }
        ]
    }

Creating a dataset

So you are ready to create your first dataset on the RW API? Great, welcome aboard! These instruction will help you create your dataset on the RW API, so you can start sharing your data with the world and taking full advantage of all the RW API features on your projects.

Before creating a dataset, there are a few things you must know and do:

The first thing to consider when creating a dataset is where your data currently is - this will determine the Dataset provider you will need to use and, with it, a set of things you need to take into account - we'll cover each provider in detail shortly. When building your request to the RW API to create your dataset, you will need to take into account both the general details that follow, plus the details for the provider you are using. Be sure to review both sections when creating your datasets, to avoid any pitfalls.

Creating a dataset is done using a POST request and passing the relevant data as body files. The supported body fields are as defined on the dataset reference section, but the minimum field list you must specify for all datasets is:

Additionally, depending on the data provider you will be using, other fields may be required - we'll cover those in detail in each provider's specific documentation.

A successful dataset creation request will return a 200 HTTP code, and the dataset details as stored on the RW API. PAy special attention to the id or the slug, as those will allow you to access your dataset later.

There's one aspect of the dataset creation process that you need to keep in mind: it is an asynchronous process. This means that a successful call to the create dataset endpoint will start the process, but the dataset may not be immediately available to be used. The status field will tell you if the dataset creation process is in progress (status set to pending), if something went wrong (failed, in which case the errorMessage field will have a short description of what went wrong) or if the dataset is available to be used (when status is saved). The amount of time it takes for a newly created dataset to go from pending to saved depends on the provider and amount of data. Just keep in mind that you need to wait for the status to be set to saved before starting to use your datasets. You should check your dataset manually to see when the status is updated.

Errors for creating a dataset

Error code Error message Description
400 <field>: <field> can not be empty Your are missing a required field value.
400 <field>: empty or invalid <field> The provided value for <field> is invalid. This is usually happens if an invalid value type is provided, but certain fields use more advanced validation rules, that may produce this error message if validation fails (ie: on a carto dataset, the connectorUrl must contain a valid carto URL).
400 provider: must be valid Your provider value is invalid. The <list of valid providers> will contain the list of providers that are supported for the connectorType you specified.
401 Unauthorized You are not authenticated. If creating a BigQuery dataset, you may also see this message even if you are authenticated. Refer to the BigQuery documentation for more details.
403 Forbidden - User does not have access to this dataset's application You are trying to create a dataset with one or more application values that are not associated with your user account.

Carto datasets

Example of creating a dataset based on CartoDB data with the minimum fields required

curl -X POST https://api.resourcewatch.org/v1/dataset \
-H "Authorization: Bearer <your-token>" \
-H "Content-Type: application/json"  -d \
'{
  "dataset": {
    "name":"World Database on Protected Areas -- Global",
    "connectorType":"rest",
    "provider":"cartodb",
    "connectorUrl":"https://wri-01.carto.com/tables/wdpa_protected_areas/table",
    "application":[
      "gfw", 
      "forest-atlas"
    ]
  }
}'

To create a dataset connected to a Carto data source, besides the common required fields, you must provide the following required data:

Field Description Example value
connectorType The type of connector. Must be set to rest. rest
provider The provider should be set to cartodb. cartodb
connectorUrl The URL for the CartoDB table that this dataset will be using. https://wri-01.carto.com/tables/wdpa_protected_areas/table

The RW API will use the information above to directly query the Carto account specified on the connectorUrl field whenever this dataset is accessed on the RW API. This has a few implications that you should be aware of:

The tableName value of a carto-based dataset will automatically be filled with the name of the carto table corresponding to the dataset.

When creating a Carto based-dataset, the RW API will try to validate the connectorUrl by trying to connect to the corresponding Carto table - the result of this will determine if the dataset's status will be set to saved or error.

ArcGIS feature layer

Example of creating a dataset based on ArcGIS feature layer data with the minimum fields required

curl -X POST https://api.resourcewatch.org/v1/dataset \
-H "Authorization: Bearer <your-token>" \
-H "Content-Type: application/json"  -d \
'{
  "dataset": {
    "connectorType":"rest",
    "provider":"featureservice",
    "connectorUrl":"https://services.arcgis.com/uDTUpUPbk8X8mXwl/arcgis/rest/services/Public_Schools_in_Onondaga_County/FeatureServer/0?f=json",
    "application":[
     "prep"
    ],
    "name":"Uncontrolled Public-Use Airports -- U.S."
  }
}'

To create a dataset using ArcGIS feature layer as data source, besides the common required fields, you must provide the following required data:

Field Description Example value
connectorType The type of connector. Must be set to rest. rest
provider The provider should be set to featureservice. featureservice
connectorUrl The URL for the JSON data in ArcGIS services this dataset will be using. https://services.arcgis.com/uuid/arcgis/rest/services/example/FeatureServer/0?f=json

The RW API will use the information above to directly query the ArcGIS feature layer server specified on the connectorUrl field whenever this dataset is accessed on the RW API. This has a few implications that you should be aware of:

The tableName value of a ArcGIS-based dataset will automatically be filled with the name of the ArcGIS feature layer table corresponding to the dataset.

When creating a ArcGIS-based dataset, the RW API will try to validate the connectorUrl by trying to connect to the corresponding ArcGIS Feature Layer - the result of this will determine if the dataset's status will be set to saved or error.

Google Earth Engine

Example of creating a dataset based on Google Earth Engine data with the minimum fields required

curl -X POST https://api.resourcewatch.org/v1/dataset \
-H "Authorization: Bearer <your-token>" \
-H "Content-Type: application/json"  -d \
'{
  "dataset": {
    "connectorType":"rest",
    "provider":"gee",
    "tableName": "JRC/GSW1_0/GlobalSurfaceWater"
    "application":[
     "rw"
    ],
    "name":"Water occurrence"
  }
}'

To create a dataset using Google Earth Engine (GEE) as data source, besides the common required fields, you must provide the following required data:

Field Description Example value
connectorType The type of connector. Must be set to rest. rest
provider The provider should be set to gee. gee
tableName Relative path of the dataset within GEE. users/resourcewatch_wri/dataset_name

The RW API will use the information above to directly query the GEE dataset specified on the tableName field whenever this dataset is accessed on the RW API. This has a few implications that you should be aware of:

When creating a GEE-based dataset, the RW API will try to validate it by connecting to the corresponding dataset GEE - the result of this will determine if the dataset's status will be set to saved or error.

WMS

Example of creating a dataset based on WMS data with the minimum fields required

curl -X POST 'https://api.resourcewatch.org/v1/dataset' -d \
-H 'Authorization: Bearer <your-token>'  \
-H 'Content-Type: application/json' -d \
'{
   "dataset": {
     "application": [
       "rw"
     ],
     "name": "Seasonal variability",
     "connectorType": "wms",
     "provider":"wms",
     "connectorUrl":"http://gis-gfw.wri.org/arcgis/rest/services/prep/nex_gddp_indicators/MapServer/6?f=pjson"
   }
 }
'

To create a dataset using WMS as data source, you should provide the following data:

Field Description Example value
connectorType The type of connector. Must be set to wms. wms
provider The provider should be set to wms. wms
connectorUrl URL of the server hosting the data in WMS format. https://maps.heigit.org/osm-wms/service?request=GetCapabilities&service=WMS

The RW API will use the information above to directly query the WMS dataset specified on the connectorUrl field whenever this dataset is accessed on the RW API. This has a few implications that you should be aware of:

When creating a WMS-based dataset, no validation is done - the dataset is automatically created in a saved state.

Document based datasets: JSON, CSV, TSV or XML

Creating a CSV dataset with data provided by externally hosted files:

curl -X POST https://api.resourcewatch.org/v1/dataset \
-H "Authorization: Bearer <your-token>" \
-H "Content-Type: application/json"  -d \
'{
  "dataset": {
    "connectorType":"document",
    "provider":"csv",
    "sources": [
      "https://gfw2-data.s3.amazonaws.com/alerts-tsv/glad_headers_1.csv",
      "https://gfw2-data.s3.amazonaws.com/alerts-tsv/glad_headers_2.csv",
      "https://gfw2-data.s3.amazonaws.com/alerts-tsv/glad_headers_3.csv"
    ],
    "application":[
     "gfw"
    ],
    "name":"Glad points"
  }
}'

Creating a JSON dataset with data provided on the request body:

curl -X POST https://api.resourcewatch.org/v1/dataset \
-H "Authorization: Bearer <your-token>" \
-H "Content-Type: application/json"  -d \
'{
  "dataset": {
    "connectorType":"document",
    "provider":"json",
    "application":[
     "your", "apps"
    ],
    "data": {"myData":[
            {"name":"nameOne", "id":"random1"},
            {"name":"nameTow", "id":"random2"}
          ]},
    "name":"Example JSON Dataset"
  }
}'

This dataset hosts data from files in JSON, CSV, TSV or XML format.

Here's a breakdown of the fields you need to specify when creating a document type dataset, besides the common required fields:

Field Description Example value
connectorType The type of connector. Must be set to document. document
provider The type of data you are uploading. Must be one of the following: csv, tsv, json or xml. csv, tsv, json or xml
connectorUrl URL from which to source data. http://gis-gfw.wri.org/arcgis/rest/services/prep/nex_gddp_indicators/MapServer/6?f=pjson
sources List of URLs from which to source data. ['http://gis-gfw.wri.org/arcgis/rest/services/prep/nex_gddp_indicators/MapServer/6?f=pjson','http://gis-gfw.wri.org/arcgis/rest/services/prep/nex_gddp_indicators/MapServer/7?f=pjson']
data JSON DATA only for json connector if connectorUrl not present. [{"key":"value1"},{"key":"value2"}]]

When creating a document based dataset, you have multiple ways of providing your data to the API, of which you should use only one:

The data passed in sources or connectorUrl must be available on a publicly accessible URLs, specified in the sources array field or the connectorUrl single value field. The URLs must be an accessible CSV, TSV or XML file, non-compressed - zip, tar, tar.gz, etc are not supported. sources allows you to specify multiple URLs for a single dataset, provided all files have the same format and data structure. This is particularly useful when creating very large datasets, as it will allow the creation process to be parallelized. No warranties are provided about the order in which the files or their parts are imported.

Notice: If you want to create a dataset from a file you have, but that it's not available on a public URL, check out our docs for uploading a dataset.

Unlike with other dataset types, when the dataset is created, the data is copied from the provided source into the API's internal Elasticsearch instance, which is the source used for subsequent queries or other operations. This has a few implications that you should be aware of:

Notice: When creating a document-based dataset, if any of the fields has a numerical name (for example, column: 3), a string named col_ will be appended to the beginning of the name of the column. This way, an uploaded column named 3 will become col_3.

Tip: If you want to periodically and automatically update your document based dataset with new data, check out the dataset automatic synchronization functionality.

When creating a document-based dataset, the RW API will start a complex process that copies your data into the API's internal database, and perform certain indexing actions. This process is called a Task, and is given a taskId that is stored on the dataset's field with the same name. Depending on the size of your dataset, this may take from a few seconds to a few hours to complete. The result of this import process will determine if the dataset's status will be set to saved or error. You can follow this process by using the taskId value with the Tasks API.

Using the legend fields to define field types

By default, when creating a document based dataset, the data is ingested by the API and the field types are automatically determined by the underlying Elasticsearch dynamic mapping API. However, in some scenarios, it may be desirable to specify some or all of these mappings manually, to match each field type to its Elasticsearch equivalent.

When defining manual mappings, you don't need to map every single field. When processing the data, if a field is found for which there isn't a manual mapping, Elasticsearch will fallback to its dynamic mapping algorithm to try and guess that field's type. This API only supports a single explicit mapping per field, meaning you cannot declare a given field as both text and keyword for example.

Field mapping can only be defined on dataset creation. Should you want to change these mappings, you can only do so by creating a new dataset with the new mapping structure.

The legend field allows explicitly identifying the following mappings:

Mapping Notes
lat If lat and long are both provided, a the_geom mapping is added
long If lat and long are both provided, a the_geom mapping is added
date Name of columns with date values (ISO Format)
country Name of columns with country values (ISO3 code)
region Name of columns with region values (ISO3 code)
nested Nested objects need to be explicitly identified in order to be indexed.
integer In beta, not fully supported
short In beta, not fully supported
byte In beta, not fully supported
double In beta, not fully supported
float In beta, not fully supported
half_float In beta, not fully supported
scaled_float In beta, not fully supported
boolean In beta, not fully supported
binary In beta, not fully supported
text In beta, not fully supported
keyword In beta, not fully supported

For more details on the characteristics of each of the basic data types, refer to the Elasticsearch documentation.

Uploading a dataset file

Upload raw data for using in a dataset

curl -X POST https://api.resourcewatch.org/v1/dataset/upload \
-H "Authorization: Bearer <your-token>" \
-F provider=csv,
-F dataset=@<your-file>

Example response

{
  "connectorUrl": "rw.dataset.raw/some-file.csv",
  "fields": [
    "Country (region)",
    "Positive affect",
    "Negative affect",
    "Social support",
    "Freedom",
    "Corruption",
    "Generosity"
  ]
}

Using the returned connectorUrl to create a new dataset

curl -X POST https://api.resourcewatch.org/v1/dataset \
-H "Authorization: Bearer <your-token>" \
-H "Content-Type: application/json"
'{
  "dataset": {
    "connectorType":"document",
    "provider":"csv",
    "connectorUrl":"rw.dataset.raw/some-file.csv",
    "application":[
     "your", "apps"
    ],
    "name":"Example RAW Data Dataset"
  }
}'

The upload endpoint allows you to create datasets on the API from local files that aren't available online. If your file is up to 4MB in size, you can upload it to the API by using the upload endpoint. This endpoint accepts a file in the "dataset" field of your POST request, and a provider that matches your file type and extension. The supported formats/extensions are: csv, json, tsv, xml, tif, tiff and geo.tiff. The request uploads the file to the API, and returns a specially crafted connectorUrl value, and a list of fields found in your file. With this data, you can create a document type dataset by passing it to the connectorUrl value of a new document type dataset.

Errors for upload a dataset file

Error code Error message Description
400 - no file to check - A file was not provided, or was provided in the wrong request field.
400 - dataset: file dataset can not be a empty file - A file was not provided, or was provided in the wrong request field.
400 provider: provider must be in [csv,json,tsv,xml,tif,tiff,geo.tiff]. A file was not provided, or was provided in the wrong request field.
400 - dataset: file too large - Your file is larger than 4MB.
400 - dataset: file is bad file type. - The provider value must match the extension of the uploaded file.
401 Unauthorized You need to be logged in to be able to upload a file.

Updating a dataset

There are multiple options to update a dataset, depending on what modification you are trying to achieve, and the underlying data provider of the dataset itself. This section covers the different endpoints that allow you to modify a dataset, their details, and helps you pick the option that best fits your scenario. We recommend reviewing all of them before proceeding, so you can find the endpoint that best matches your needs.

Updating the fields of a dataset

Example request for updating the name of a dataset

curl -X PATCH https://api.resourcewatch.org/v1/dataset/<dataset-id-or-slug> \
-H "Authorization: Bearer <your-token>" \
-H "Content-Type: application/json" -d \
'{
    "name": "Another name for the dataset"
}'

In order to modify the fields of a dataset, you can use the patch dataset endpoint. This endpoint allows you to modify most of your dataset's details, like the name or publishing status, but can also be used to modify internal fields of a dataset, like connectorType. When making these changes, be mindful that some of these fields are critical to the correct behavior of the dataset, and providing incorrect values may break your dataset. There are other endpoints documented in this page that allow you to perform certain update-like operations (ie. update data on a document-type dataset), so refer to those first before using this endpoint. Also important to keep in mind is the fact that this endpoint does not perform validation on things like connectorUrl/sources URLs.

All the fields in the dataset reference can be modified, except the following:

Additionally, certain fields have special behavior associated with them:

When passing new values for Object type fields, the new value will fully overwrite the previous one. It's up to you, as an API user, to build any merging logic into your application.

To perform this operation, the following conditions must be met:

Use this endpoint when:

Errors for updating the fields of a dataset

Error code Error message Description
401 Unauthorized You need to be logged in to be able to update a dataset.
403 Forbidden You need to either have the ADMIN role, or have role MANAGER and be the dataset's owner (through the userId field of the dataset).
403 Forbidden You are trying to update a dataset with one or more application values that are not associated with your user account.
404 Dataset with id doesn't exist A dataset with the provided id does not exist.

Concatenate and append data to a document based dataset

Concatenate data using external data source:

curl -X POST https://api.resourcewatch.org/v1/dataset/:dataset_id/concat \
-H "Authorization: Bearer <your-token>" \
-H "Content-Type: application/json"  -d \
'{
    "provider": "json",
    "sources": ["<csv1Url>", "<csv2Url>", "<csv3Url>"],
    "dataPath": "data... etc"
}'

Append data using external data source:

curl -X POST https://api.resourcewatch.org/v1/dataset/:dataset_id/append \
-H "Authorization: Bearer <your-token>" \
-H "Content-Type: application/json"  -d \
'{
    "provider": "json",
    "sources": ["<csvUrl>"],
    "dataPath": "data... etc"
}'

Concatenate data using JSON array in post body:

curl -X POST https://api.resourcewatch.org/v1/dataset/:dataset_id/concat \
-H "Authorization: Bearer <your-token>" \
-H "Content-Type: application/json"  -d \
'{
    "provider": "json",
    "data": [{},{}]
}'

Using these endpoints, you can add more data to an already existing dataset. They are exclusively available for document based datasets - you'll get a 404 error if you use them on a dataset of a different type. You can either provide the URL for the file containing the data you wish to add, or simply provide that data in the body of your request, as a JSON object.

These process are asynchronous and not instantaneous. Immediately when triggered, these requests will cause the dataset's status to be set to pending, meaning you will not be able to issue new overwrite, concatenate or append requests. Once the request has been fully processed, the status will be automatically set to saved. Depending on factors like API load or the size of the data being uploaded, this may take from a few minutes to a few hours to occur. The API does not issue any notification when the asynchronous operation is finished.

In order to perform these operation, the following conditions must be met:

While they ultimately achieve a very similar end result, concatenate and append rely on different internal processes, each with its own characteristics.

Here's a more detailed description of the request's body fields:

Field Description Type Values Required
provider Dataset provider this include inner connectors and 3rd party ones String A valid dataset provider Yes
sources List of URLs from which to source data Array URL array Yes, unless JSON data is provided using the data field
data JSON DATA only for json connector if connectorUrl not present Array [{},{},{}] Yes for JSON if sources is not present
dataPath Path to the data in a JSON file-based datasets String '' No

Tip: If you want to periodically and automatically concatenate data to your document based dataset, check out the dataset automatic synchronization functionality.

Use this endpoint when:

Errors for concatenating and appending data to a document based dataset

Error code Error message Description
401 Dataset is not in saved status The dataset's status value is not set to saved. Refer to dataset reference for more details on this field and its values.
401 Unauthorized You need to be logged in to be able to update a dataset.
403 Forbidden You need to either have the ADMIN role, or have role MANAGER and be the dataset's owner (through the userId field of the dataset).
403 Forbidden You are trying to update a dataset with one or more application values that are not associated with your user account.
404 Endpoint not found A dataset with the provided id does not exist, or does not have connectorType with value document.
409 Dataset locked. Overwrite false. The dataset you're trying to modify has overwrite value set to false, to explicitly prevent data modifications.

Overwrite data for a document based dataset

Overwrite data using external data source:

curl -X POST https://api.resourcewatch.org/v1/dataset/:dataset_id/data-overwrite \
-H "Authorization: Bearer <your-token>" \
-H "Content-Type: application/json"  -d \
'{
   "sources": ["<url of the data source>"],
   "provider": "csv"
}'

Overwrite data using JSON array in post body:

curl -X POST https://api.resourcewatch.org/v1/dataset/:dataset_id/data-overwrite \
-H "Authorization: Bearer <your-token>" \
-H "Content-Type: application/json"  -d \
'{
   "data": [{},{}],
   "provider": "csv"
}'

Using this endpoint, you can add or completely replace the data of an already existing dataset. It's exclusively available for document based datasets - you'll get a 404 error if you use it on a dataset of a different type. All previously existing data will be permanently deleted. You can either provide the URL(s) for the file(s) containing the data you wish to add, or simply provide that data in the body of your request, as a JSON object. There are no requirements regarding similarity of the data structure between existing and new data - your overwrite data can have a completely different data schema.

This process is asynchronous and not instantaneous. Immediately when triggered, this request will cause the dataset's status to be set to pending, meaning you will not be able to issue new overwrite or concat requests, and will not yet be able to access the new data yet. Once the request has been fully processed, the status will be automatically set to saved and the new data will be accessible. Depending on factors like API load or the size of the data being uploaded, this may take from a few minutes to a few hours to occur. The API does not issue any notification when the asynchronous operation is finished.

In order to perform this operation, the following conditions must be met:

Here's a more detailed description of the request's body fields:

Field Description Type Values Required
provider Dataset provider this include inner connectors and 3rd party ones String A valid dataset provider Yes
sources List of URLs from which to source data Array URL array Yes, unless JSON data is provided using the data field
data JSON DATA only for json connector if connectorUrl not present Array [{},{},{}] Yes for JSON if sources is not present
legend The schema of the new data. If none is provided, a guessing mechanism will be used. The existing legend value of the dataset will be ignored and overwritten in all overwrite operations. See the legend section above for more details. Object No

Tip: If you want to periodically and automatically overwrite the data on your document based dataset, check out the dataset automatic synchronization functionality.

Errors for overwriting data for a document based dataset

Error code Error message Description
401 Dataset is not in saved status The dataset's status value is not set to saved. Refer to dataset reference for more details on this field and its values.
401 Unauthorized You need to be logged in to be able to update a dataset.
403 Forbidden You need to either have the ADMIN role, or have role MANAGER and be the dataset's owner (through the userId field of the dataset).
403 Forbidden You are trying to update a dataset with one or more application values that are not associated with your user account.
404 Endpoint not found A dataset with the provided id does not exist, or does not have connectorType with value document.
409 Dataset locked. Overwrite false. The dataset you're trying to modify has overwrite value set to false, to explicitly prevent data modifications.

Use this endpoint when:

Cloning a dataset

Example request for cloning a dataset

curl -X POST https://api.resourcewatch.org/v1/dataset/5306fd54-df71-4e20-8b34-2ff464ab28be/clone \
-H "Authorization: Bearer <your-token>"
-H "Content-Type: application/json" -d \
'{
  "dataset": {
    "datasetUrl": "/query/5306fd54-df71-4e20-8b34-2ff464ab28be?sql=select%20%2A%20from%20data%20limit%2010",
    "application": [
      "your",
      "apps"
    ],
    "legend": {...},
    "applicationConfig" : {...}
  }
}'

This endpoint allows you to create a new, json based dataset, from the result of a RW API endpoint call. The basic usage example would be to create a new dataset based on a custom query to an existing dataset - this is illustrated in the example curl call in this section. Other use cases could be converting the result of an analysis endpoint into a dataset, or capturing the result of a query to a REST based dataset (cartodb, arcgis, etc) to an internal json representation of the same data, that is kept in the API database.

In order to perform this operation, the following conditions must be met:

The request requires two fields to be present:

Additionally, you can optionally specify these fields:

For the fields in the following list, values will be copied from the original dataset to the new one, unless specified:

Datasets created through a cloning operation will have a specific clonedHost object, with additional data. Refer to dataset reference for more details on the content of this field.

The dataset cloning requests accepts an optional full boolean query parameter that, when set to true, will clone of vocabulary-related data and metadata from the original dataset to the new one.

Errors for cloning a dataset

Error code Error message Description
400 : can not be empty. The required field identified in the error message is missing in the request body.
400 - application: must be a non-empty array - application must be specified as an array.
401 Unauthorized You need to be logged in to be able to clone a dataset.
403 Forbidden You need to either have the ADMIN role, or have role MANAGER and be the dataset's owner (through the userId field of the dataset).
403 Forbidden - User does not have access to this dataset's application You specified an application in your request body that is not associated with your user account.
404 Dataset with id doesn't exist A dataset with the provided id does not exist.

Deleting a dataset

Use this endpoint if you wish to delete a dataset. Deleting a dataset of type document (connectorType with value document) will cause the API's internal copy of said data to be deleted. Dataset types that proxy data from an external source (ie. carto, gee, etc) will be deleted without modifying said external source.

When deleting a dataset that is associated with multiple application values, the user issuing the request must be associated with all of them in order for the dataset to be deleted. If that's not the case, the application values associated with the user will be removed from the dataset's application list, and no further action will be taken - the dataset itself and its associated resources will continue to exist. The dataset is only actually deleted if the user has access to all of the application to which the dataset belongs.

Besides deleting the dataset itself, this endpoint also deletes graph vocabularies, layers, widgets and metadata related to the dataset itself. These delete operations are issued in this order, and prior to deleting the dataset itself, but are not atomic - if one of them fails (for example, if attempting to delete a protected resource), the following ones are canceled, but the already deleted elements are not restored.

In order to delete a dataset, the following conditions must be met:

Example request for deleting a dataset

curl -X DELETE https://api.resourcewatch.org/v1/dataset/<dataset-id> \
-H "Authorization: Bearer <your-token>"
-H "Content-Type: application/json"

Errors for deleting a dataset

Error code Error message Description
400 Dataset is protected You are attempting to delete a dataset that has protected set to prevent deletion.
401 Unauthorized You need to be logged in to be able to delete a dataset.
403 Forbidden You need to either have the ADMIN role, or have role MANAGER and be the dataset's owner (through the userId field of the dataset)
403 Forbidden You are trying to delete a dataset with one or more application values that are not associated with your user account.
404 Dataset with id doesn't exist A dataset with the provided id does not exist.

Dataset automatic synchronization

curl -X POST https://api.resourcewatch.org/v1/dataset \
-H "Authorization: Bearer <your-token>" \
-H "Content-Type: application/json"
'{
    "connectorType":"document",
    "provider":"csv",
    "connectorUrl":"<csvUrl>",
    "application":[
     "your", "apps"
    ],
    "name":"Example SYNC Dataset",
    "overwrite": true,
    "sync": {
        "action":"concat",
        "cronPattern":"0 * * * * *",
        "url":"<updateCsvUrl>"
    }
}'

Certain datasets contain data that evolves frequently over time, and you, as the creator of this dataset, what to ensure that it's up-to-date. As we've seen before, if your data is hosted on one of the supported 3rd party data providers, like Carto or Arcgis, your data will be proxied, so users of the RW API will always see the latest version of your data. However, if you uploaded your data from a file, your data is copied to the RW API database at the time of the dataset's creation, so keeping it up-to-date requires a different approach. It's with scenario in mind that the RW API offers the automatic synchronization mechanism.

The automatic synchronization mechanism is available for document based datasets only, and you can configure it when creating or updating a dataset. When enabled, it will schedule an automatic, periodic task, that will update your document based dataset's data, based on data from an URL you provide. This means that, once configured, you just have to make sure the automatic synchronization mechanism can find the newest version of the data at the specified URL, and the RW API will take care of the actual data update process for you.

To configure automatic synchronization on dataset creation or update, you need to pass a sync object on your calls to the respective endpoints, next to the other fields. See the included example for a clearer idea of how creating a dataset with automatic synchronization looks like.

There are 3 fields, all required, that you need to specify inside the sync object:

Internally, the automatic synchronization mechanism will call either the dataset concatenation or dataset overwrite endpoint. If that internal request fails - for example, if overwrite is set to false - the sync process will fail silently. If you have the ADMIN role, you can use the /v1/task endpoint to see scheduled tasks and their error output, but otherwise this failure will be invisible to end users.

On the other hand, if the request goes through, but the concatenation/overwrite process fails - for example, if the URL provided is not available - then your dataset status will be set to error and the errorMessage field will give you a simple description of what happened.

To see the details (including the date) of the last operation performed on the dataset, use the link in the taskId field.

Flush dataset cache

Flush dataset's cache

curl -X POST https://api.resourcewatch.org/v1/dataset/0c630feb-8146-4fcc-a9be-be5adcb731c8/flush \
-H "Authorization: Bearer <your-token>"

Response:

OK

Flushes the cache for the specified dataset. Take into account that only the dataset itself, query results and fields will be flushed. Any other relation, like metadata, layers or widgets linked to the specified dataset will not be affected by this action.

In order to flush a dataset's cache, the following conditions must be met:

Errors for flushing a dataset's cache

Error code Error message Description
401 Unauthorized You need to be logged in to be able to delete a dataset.
403 Forbidden You need to either have the ADMIN role, or have role MANAGER and be the dataset's owner (through the userId field of the dataset)
403 Forbidden You are trying to delete a dataset with one or more application values that are not associated with your user account.
404 Dataset with id doesn't exist A dataset with the provided id does not exist.

Recover

Recover dataset

curl -X POST https://api.resourcewatch.org/v1/0c630feb-8146-4fcc-a9be-be5adcb731c8/recover \
-H "Authorization: Bearer <your-token>"

Response:

OK

Resets a dataset's status to saved and clears its errors. Keep in mind that this does NOT modify the dataset in any other way - if the underling dataset's data was inconsistent for any reason, this endpoint will not change it, and it's up to you to fix it using a data-overwrite or other endpoints.

In order to recover a dataset, the user must be logged in and have the ADMIN role.

Errors for recovering a dataset

Error code Error message Description
401 Unauthorized You need to be logged with to be able to delete a dataset.
403 Forbidden You need to have the ADMIN role.
404 Dataset with id doesn't exist A dataset with the provided id does not exist.

Dataset reference

This section gives you a complete view at the properties that are maintained as part of dataset. When interacting with a dataset (on get, on create, etc) you will find most of these properties available to you, although they may be organized in a slightly different structure (ie: on get, everything but the id is nested inside an attributes object).

You can find more details in the source code.

Field name Type Required Default value Description
id String Yes (autogenerated) Unique Id of the dataset. Auto generated on creation. Cannot be modified by users.
name String Yes Name of the dataset.
slug String Yes (autogenerated) Slug of the dataset. Auto generated on creation. Cannot be modified by users.
type String No null Type of the dataset.
subtitle String No null Subtitle of the dataset.
application Array Yes Applications associated with this dataset. Read more about this field here.
applicationConfig Object No Key-value storage of application-specific data. Use the application value as key and a JSON Object as the value to store complex, extensible data.
dataPath String No null Path to the data in a JSON file-based datasets.
attributesPath String No null
connectorType String Yes Type of connector. wms for WMS-based datasets, rest for datasets that rely on external data sources (carto, arcgis, etc) or document for file-based datasets (JSON, CSV, etc).
provider String Yes Dataset provider.
userId String Yes (autopopulated) Id of the user who created the dataset. Set automatically on creation. Cannot be modified by users.
connectorUrl String No null Path to the source of the data. On datasets with document connectorType, sources should be used instead.
sources Array No null Path to the source files of the data. Only used on datasets with document connectorType.
tableName String No null Additional value used to locate the dataset within a given underlying provider. Refer to the documentation of the different connector for more details.
status String No pending Status of the dataset. saved means the dataset is available to use, pending means an operation is ongoing and the dataset is temporarily unavailable, error means the dataset is in an invalid state and requires further action before becoming available.
overwrite Boolean No false If the data can be overwritten (only for being able to update dataset)
errorMessage String No null If this dataset is in error state, this field may contain additional details about the error.
mainDateField String No null
published Boolean Yes true If the dataset is published or not.
env String Yes production Environment to which the dataset belongs. Read more about this field in the Environments concept section.
geoInfo Boolean Yes false If it contains interceptable geographical info
protected Boolean Yes false If the dataset is protected. A protected dataset cannot be deleted.
taskId String No null Id of the latest task associated with this dataset. Typically only present in document connectorType datasets
subscribable Object No Information about the dataset being subscribable for alerts. More info about this can be found on the Subscriptions section of the docs.
legend.lat String No Dataset field representing a latitude value.
legend.long String No Dataset field representing a longitude value.
legend.* Array No Different keys corresponding to data types. Each key may have an array of strings, referencing dataset fields that match that data type. Used functionally for document-based datasets, but may also be set by the user as reference for other types. See this section for more details.
clonedHost.hostProvider String No When cloning a dataset, this will retain the provider value of the original dataset.
clonedHost.hostUrl String No When cloning a dataset, this will retain the connectorUrl value of the original dataset.
clonedHost.hostId String No When cloning a dataset, this will retain the Id value of the original dataset.
clonedHost.hostType String No When cloning a dataset, this will retain the connectorType value of the original dataset.
clonedHost.hostPath String No When cloning a dataset, this will retain the tableName value of the original dataset.
widgetRelevantProps Array No Group of relevant props of a widget.
layerRelevantProps Array No Group of relevant props of a layer.
dataLastUpdated Date No User defined date of when a dataset was last updated.
userName String No (autogenerated) null Name of the user who created the dataset. This value is used only internally, and is never directly exposed through the API. Cannot be modified by users.
userRole String No (autogenerated) null Role of the user who created the dataset. This value is used only internally, and is never directly exposed through the API. Cannot be modified by users.
createdAt Date No (autogenerated) Automatically maintained date of when the dataset was created. Cannot be modified by users.
updatedAt Date No (autogenerated) Automatically maintained date of when the dataset was last updated. Cannot be modified by users.

Fields

What are fields?

Fields are the properties of a dataset your will find when querying its data, use when filtering data through queries, or visualise when rendering a layer or a widget.

Fields are part of a dataset, and are determined by the structure of data provided by the dataset creator. Each field also includes information about its data type, derived automatically by the dataset provider (check out the specifics of each provider in the sections below). If you are uploading your own datasets to the RW API, you don't have to do anything else for your dataset to be available through the fields endpoints - there's no additional data you have to provide. Keep in mind the endpoints described in the sections below are read-only - if you want to change your dataset's fields, you need to upload the dataset's data again.

Fields are targeted at users consuming datasets available on the RW API, particularly if you want to build a flexible and scalable application. The fields endpoints aim at giving you a consistent and uniform view of the structure of data hosted in different dataset providers, that would otherwise be served in a heterogeneous structure.

How to get the dataset fields

Querying the fields of a dataset

curl -X GET https://api.resourcewatch.org/v1/fields/<dataset-id>

Response example

{
    "tableName": "public.cait_2_0_country_ghg_emissions_toplow2011",
    "fields": {
        "cartodb_id": {
            "type": "number"
        },
        "the_geom": {
            "type": "geometry"
        },
        "the_geom_webmercator": {
            "type": "geometry"
        },
        "x": {
            "type": "string"
        },
        "y": {
            "type": "number"
        },
        "z": {
            "type": "string"
        }
    }
}

Once the dataset has been created and its status is set to saved, you will be able to use this endpoint to get details about a its fields. The resulting response contains two root fields

While the aim of this endpoint is to provide an homogeneous view of data stored in different systems, you will still encounter slight variations in data, depending on the underlying type of the dataset you're querying. The example response on the right illustrates the typical basic response structure: tableName with a string value, and a fields map that matches each field's name to a type. You'll find this structure throughout all responses, but you may also find additional details for each field, and the data types may vary in name. In the next sections we'll cover some of the specifics for each dataset type.

Carto

Example response for a Carto dataset

{
    "tableName": "gadm28_adm1",
    "fields": {
        "cartodb_id": {
            "type": "number",
            "pgtype": "int4"
        },
        "the_geom": {
            "type": "geometry",
            "wkbtype": "Unknown",
            "dims": 2,
            "srid": 4326
        },
        "the_geom_webmercator": {
            "type": "geometry",
            "wkbtype": "Unknown",
            "dims": 2,
            "srid": 3857
        },
        "objectid": {
            "type": "number",
            "pgtype": "int8"
        },
        "iso": {
            "type": "string",
            "pgtype": "text"
        },
        "centroid": {
            "type": "string",
            "pgtype": "text"
        },
        "area_ha": {
            "type": "number",
            "pgtype": "float8"
        },
        "topojson": {
            "type": "string",
            "pgtype": "text"
        },
        "the_geom_simple": {
            "type": "geometry",
            "wkbtype": "Unknown",
            "dims": 2,
            "srid": 4326
        },
        "geojson": {
            "type": "string",
            "pgtype": "text"
        }
    }
}

Carto datasets provide a type for each field, as well as additional details, depending on the field type. Most fields will have a pgtype field, which will identify a sub-type of sorts - for example, type number is matched with different pgtype values in this example. This is related with the underling Carto implementation, that uses PostgreSQL, PostGIS and its own software stack. We recommend relying on the type as much as possible.

Other, more complex, field types, like geometry types, include additional details for their respective types. As before, this is related with the underlying Carto implementation tools, and not actively maintained or supported by the RW API.

For more information about the different types that can be found in Carto datasets please refer to PostgreSQL's documentation on Data Types or PostGIS's documentation.

ArcGIS feature layer

Example response for a ArcGIS dataset

{
    "tableName": "conservationMapServer3",
    "fields": {
        "objectid": {
            "type": "esriFieldTypeOID"
        },
        "tcl_name": {
            "type": "esriFieldTypeString"
        },
        "tcl_id": {
            "type": "esriFieldTypeSmallInteger"
        },
        "area_ha": {
            "type": "esriFieldTypeInteger"
        },
        "tx2_tcl": {
            "type": "esriFieldTypeSmallInteger"
        },
        "gfwid": {
            "type": "esriFieldTypeString"
        },
        "globalid": {
            "type": "esriFieldTypeGlobalID"
        },
        "shape": {
            "type": "esriFieldTypeGeometry"
        },
        "shape_Length": {
            "type": "esriFieldTypeDouble"
        },
        "shape_Area": {
            "type": "esriFieldTypeDouble"
        }
    }
}

ArcGIS uses its own type naming convention, as you see reflected in the included example. The RW API passes that information as-is to you. As different ArcGIS datasets rely on different ArcGIS server instances and versions, you may encounter variations in the types you'll find, depending on how ArcGIS evolves these types over type.

For more information about the different types that can be found in ArcGIS datasets please refer to ArcGIS's field data types documentation.

Google Earth Engine

Example response for a Google Earth Engine dataset

{
    "data": {
        "fields": {
            "bands": [
                {
                    "dataType": {
                        "precision": "INT",
                        "range": {
                            "max": 2147483647,
                            "min": -2147483648
                        }
                    },
                    "grid": {
                        "affineTransform": {
                            "scaleX": 0.00833333376795053,
                            "scaleY": -0.00833333376795053,
                            "translateX": -180.0000000000001,
                            "translateY": 90.00000782310963
                        },
                        "crsCode": "EPSG:4326",
                        "dimensions": {
                            "height": 18000,
                            "width": 43200
                        }
                    },
                    "id": "b1",
                    "pyramidingPolicy": "MEAN"
                }
            ],
            "geometry": {
                "coordinates": [
                    [
                        [
                            "-Infinity",
                            "-Infinity"
                        ],
                        [
                            "Infinity",
                            "-Infinity"
                        ],
                        [
                            "Infinity",
                            "Infinity"
                        ],
                        [
                            "-Infinity",
                            "Infinity"
                        ],
                        [
                            "-Infinity",
                            "-Infinity"
                        ]
                    ]
                ],
                "type": "Polygon"
            },
            "id": "users/resourcewatch/cli_030_global_aridity",
            "name": "projects/earthengine-legacy/assets/users/resourcewatch/cli_030_global_aridity",
            "properties": {
                "title": "Image:cli_030 _global_aridity"
            },
            "sizeBytes": "413389345",
            "title": "Image:cli_030 _global_aridity",
            "type": "IMAGE",
            "updateTime": "2017-10-06T18:58:39.646890Z"
        },
        "tableName": "users/resourcewatch/cli_030_global_aridity"
    }
}

Google Earth Engine (GEE) is perhaps the biggest outlier when it comes to fields data. Because it relies on raster data, rather than tabular data, the data structure you'll find in a GEE dataset is very different, as you can see in the example on the side.

The response consists of loading the details for a single image, with the most meaningful information being the properties (of an image) and bands (of said image). Those will be the fields you'll be able to retrieve when using the query endpoints.

NEX-GDDP

Example response for a NEX-GDDP dataset

{
    "fields": {
        "tasavg": {
            "type": "number",
            "uom": "10^0"
        },
        "tasavg_q25": {
            "type": "number",
            "uom": "10^0"
        },
        "tasavg_q75": {
            "type": "number",
            "uom": "10^0"
        },
        "year": {
            "type": "date"
        }
    },
    "tableName": "tasavg/rcp45_30_y"
}

NEX-GDDP datasets have an additional uom (unit of measure) field on some field types, but otherwise has no other info besides the basic details.

BigQuery

Example response for a BigQuery dataset

{
    "tableName": "[bigquery-public-data:ghcn_m.ghcnm_tmin]",
    "fields": [
        {
            "name": "id",
            "type": "INTEGER",
            "mode": "REQUIRED",
            "description": "11 digit identifier, digits 1-3=Country Code, digits 4-8 represent the WMO id if the station is a WMO station. It is a WMO station if digits 9-11=\"000\"."
        },
        {
            "name": "year",
            "type": "INTEGER",
            "mode": "NULLABLE",
            "description": "4 digit year of the station record."
        },
        {
            "name": "element",
            "type": "STRING",
            "mode": "NULLABLE",
            "description": "element type, monthly mean temperature=\"TAVG\" monthly maximum temperature=\"TMAX\" monthly minimum temperature=\"TMIN\""
        },
        {
            "name": "value1",
            "type": "INTEGER",
            "mode": "NULLABLE",
            "description": "monthly value (MISSING=-9999).  Temperature values are in hundredths of a degree Celsius, but are expressed as whole integers (e.g. divide by 100.0 to get whole degrees Celsius)."
        },
        {
            "name": "qcflag3",
            "type": "STRING",
            "mode": "NULLABLE",
            "description": "quality control flag, seven possibilities within quality controlled unadjusted (qcu) dataset, and 2 possibilities within the quality controlled adjusted (qca) dataset."
        },
        {
            "name": "qcflag12",
            "type": "STRING",
            "mode": "NULLABLE",
            "description": "quality control flag, seven possibilities within quality controlled unadjusted (qcu) dataset, and 2 possibilities within the quality controlled adjusted (qca) dataset."
        },
        {
            "name": "dsflag12",
            "type": "STRING",
            "mode": "NULLABLE",
            "description": "data source flag for monthly value, 21 possibilities"
        }
    ]
}

BigQuery has a slight variation on the core structure returned by the fields endpoint for other dataset types. Instead of fields having a key-value map, it has an array of objects, each describing a field. Each of these objects has a name and type property, identifying a field and its type, as well as a mode and description, respectively indicating if the field is nullable or required, and providing a human-friendly description of the field's content or purpose.

Loca

Example response for a Loca dataset

{
    "fields": {
        "xs": {
            "type": "number",
            "uom": "10^0"
        },
        "xs_q25": {
            "type": "number",
            "uom": "10^0"
        },
        "xs_q75": {
            "type": "number",
            "uom": "10^0"
        },
        "year": {
            "type": "date"
        }
    },
    "tableName": "loca_xs/rcp85_30_y"
}

Loca datasets have an additional uom (unit of measure) field on some field types, but otherwise has no other info besides the basic details.

Document-based dataset types (csv, tsv, json and xml)

Example response for a document-based dataset

{
    "tableName": "index_1c9a1e4f455b4c03ac88dd2242a2e4b1_1602065490373",
    "fields": {
        "cartodb_id": {
            "type": "long"
        },
        "commodity": {
            "type": "text",
            "fields": {
                "keyword": {
                    "type": "keyword",
                    "ignore_above": 256
                }
            }
        },
        "data_id": {
            "type": "text",
            "fields": {
                "keyword": {
                    "type": "keyword",
                    "ignore_above": 256
                }
            }
        },
        "gcm_type": {
            "type": "text",
            "fields": {
                "keyword": {
                    "type": "keyword",
                    "ignore_above": 256
                }
            }
        },
        "impactparameter": {
            "type": "text",
            "fields": {
                "keyword": {
                    "type": "keyword",
                    "ignore_above": 256
                }
            }
        },
        "iso": {
            "type": "text",
            "fields": {
                "keyword": {
                    "type": "keyword",
                    "ignore_above": 256
                }
            }
        },
        "region": {
            "type": "text",
            "fields": {
                "keyword": {
                    "type": "keyword",
                    "ignore_above": 256
                }
            }
        },
        "scenario": {
            "type": "text",
            "fields": {
                "keyword": {
                    "type": "keyword",
                    "ignore_above": 256
                }
            }
        },
        "value": {
            "type": "float"
        },
        "year": {
            "type": "long"
        }
    }
}

Document based datasets from the 4 different types of sources (json, xml, csv and tsv) all share a common internal storage engine, based on Elasticsearch. So, when querying for fields of a document-based dataset, you'll find information matching the field mechanism used by Elasticsearch. This is particularly evident on text fields, where the keyword information is present. During most uses cases, we don't anticipate this information being needed, as relying on the type value should cover the majority of your needs.

Dataset types not supported by the fields endpoint

The following dataset types have not been integrated with the fields endpoint, so you will get a 404 response when querying for their fields:

Errors for getting a dataset fields

Error code Error message Description
404 Endpoint not found You are querying for fields of a dataset which type is not integrated with the fields endpoint
404 Dataset not found A dataset with the provided id does not exist.

Query

In order to retrieve data from datasets, you can send queries to the API using a syntax very similar to SQL. Using these endpoints, you can also download the results of a particular query. If you are new to the RW API, or want to learn more about the concept of a querying datasets, we strongly encourage you to read the query concept documentation first. It gives you a brief and clear description of what a query is, and what it is useful for.

Please note that some SQL features might not be supported. Check here for a reference of the SQL features' support for each dataset provider.

Querying datasets

Structure of the endpoint for executing a query:

curl -i -X GET 'https://api.resourcewatch.org/v1/query/<dataset.id>?sql=SELECT * FROM <dataset.tableName>'

In order to query a dataset, you'll need two pieces of information:

The dataset documentation covers different ways that you can use to browse the existing dataset catalog or upload your own, all of which will give you the details of a dataset, including the dataset id you'll need to query it.

The SQL query will have to be custom built by you to fit your needs, but a good starting point for newcomers would be something like SELECT * FROM <dataset.tableName> limit 10.

Notice: the limit parameter restricts our results to 10 rows, and is not required. However, for our learning purposes, this is useful, as it keeps the API responses small and fast.

Most of the SQL query is up to you to define, based on your needs and the support provided for the dataset type you are using. The FROM clause, however, does use a special value - the dataset's tableName value, which you can also get from the dataset documentation described above.

Example endpoint for executing a query:

curl -i -X GET 'https://api.resourcewatch.org/v1/query/098b33df-6871-4e53-a5ff-b56a7d989f9a?sql=SELECT cartodb_id, iso, name_0, name_1, type_1 FROM gadm28_adm1 limit 10'

With both pieces of information at hand, you can now send your query to the API and get the response. The example cURL to the side shows how that would look like.

Query response body

Example response:

{
    "data": [
        {
            "cartodb_id": 1830,
            "iso": "MEX",
            "name_0": "Mexico",
            "name_1": "Ciudad de México",
            "type_1": "Distrito Federal"
        },
        {
            "cartodb_id": 1109,
            "iso": "HTI",
            "name_0": "Haiti",
            "name_1": "L'Artibonite",
            "type_1": "Département"
        },
        ...
    ],
    "meta": {
        "cloneUrl": {
            "http_method": "POST",
            "url": "/dataset/098b33df-6871-4e53-a5ff-b56a7d989f9a/clone",
            "body": {
                "dataset": {
                    "datasetUrl": "/query/098b33df-6871-4e53-a5ff-b56a7d989f9a?sql=SELECT%20*%20FROM%20gadm28_adm1%20limit%2010",
                    "application": [
                        "your",
                        "apps"
                    ]
                }
            }
        }
    }
}

The following table describes the response body fields:

Field Type Description
data Array Array of objects that correspond to the result of the query execution. The data structure varies according to SELECT clause of your query, or the structure of dataset being queried.
meta Object Object with metadata regarding the query executed.
meta.cloneUrl Object Object with information for creating a new dataset from the current query execution.
meta.cloneUrl.http_method String The HTTP method that should be used for the request to create a new dataset from the current query execution. Read the documentation on cloning a dataset for more info.
meta.cloneUrl.url String The API endpoint path that should be used for the request to create a new dataset from the current query execution.
meta.cloneUrl.body Object The body request data that should be provided for creating a new dataset from the current query execution.

Query endpoint parameters

Example of requesting the query results as CSV data:

curl -i -X GET 'https://api.resourcewatch.org/v1/query/9be3bf63-97fc-4bb0-b913-775ccae3cf9e?sql=SELECT alert__date from gadm28_adm1 limit 2&format=csv'

Example response:

"alert__date",
"_id"
"2019-04-12",
"AW6O0fqMLu2ttL7ZDM4P"
"2015-08-22",
"AW6O0fqMLu2ttL7ZDM4T"

Example of requesting to freeze the query results:

curl -i -X GET 'https://api.resourcewatch.org/v1/query/9be3bf63-97fc-4bb0-b913-775ccae3cf9e?sql=SELECT alert__date from gadm28_adm1 limit 2&freeze=true' \
-H "Authorization: Bearer <your-token>"

Example response:

{
    "url": "https://storage.googleapis.com/query-freeze/1589458072773.json"
}

The following parameters can be provided as query parameters, in order to customize the output of the response returned:

Query parameter Description Type Required
sql The SQL query to be executed. This parameter changes the data returned in the query response body. String Yes
format The format of the returned response. By default, JSON format is assumed (json), but you can also request the response as CSV (csv), in which case the returned response will contain the CSV contents of the response. This parameter will only be considered for document-based datasets. String No
freeze The freeze parameter, when provided as true, will create a file with the results of the execution of the query and return the URL for that file. Please note that you should be authenticated in order to request freezing the results of query executions. Boolean No
geostore Read more about the geostore query parameter here. String No

Filter query results by geostore

Example query providing a geostore id as query parameter to filter the results:

curl -i -X GET 'https://api.resourcewatch.org/v1/query/1d7085f7-11c7-4eaf-a29a-5a4de57d010e?sql=SELECT * FROM dis_001_significant_earthquakes LIMIT 5&geostore=972c24e1da2c2baacc7572ee9501abdc'

Some dataset providers support receiving a geostore query parameter. When providing this parameter, you can request geo-referenced data that fits within the bounding box of the geostore with id provided. You can obtain the id of the geostore using the RW API Geostore API. If the data is not geo-referenced, or if the dataset provider does not support the geostore query parameter, it will be ignored.

The following providers support this parameter:

Alternative ways for querying datasets

While the GET request described above is the recommended way of querying datasets, there are other ways to query the RW API datasets that may be more suited for specific use cases.

Using the dataset slug instead of the id

Example query not using the dataset id in the request path, and using the dataset slug in the FROM clause:

curl -i -X GET 'https://api.resourcewatch.org/v1/query/9be3bf63-97fc-4bb0-b913-775ccae3cf9e?sql=SELECT alert__date from gadm28_adm1 limit 2'
curl -i -X GET 'https://api.resourcewatch.org/v1/query/Glad-Alerts-Daily-Geostore-User-Areas_3?sql=SELECT alert__date from gadm28_adm1 limit 2'

When referencing a dataset's id in a query, you have the option to use the dataset's slug instead, obtaining the same result. This is also applicable to the alternative query methods described in the sections below.

POST requests

The same query executed as GET, and as a POST request providing the SQL as request body param:

curl -i -X GET 'https://api.resourcewatch.org/v1/query/9be3bf63-97fc-4bb0-b913-775ccae3cf9e?sql=SELECT alert__date from gadm28_adm1 limit 2'
curl -i -X POST 'https://api.resourcewatch.org/v1/query/9be3bf63-97fc-4bb0-b913-775ccae3cf9e' \
-H 'Content-Type: application/json' \
-d '{
    "sql": "SELECT alert__date from gadm28_adm1 limit 2"
}'

Using the GET request is the recommended approach, as it allows HTTP caching of your result - subsequent requests for the same query will see a great performance increase, even if they are made by a different application or client.

Alternatively, you can also query a dataset using a POST request. POST requests are not cached, so you will not benefit from these speed improvements. However, GET requests can sometimes hit URL length restrictions, should your query string be too long. Using a POST request is the recommended solution for these cases. See the example on the side to see how you can query a dataset with a POST request.

Dataset id as the FROM clause

Three different but equivalent syntaxes for the same query:

curl -i -X GET 'https://api.resourcewatch.org/v1/query/098b33df-6871-4e53-a5ff-b56a7d989f9a?sql=SELECT cartodb_id, iso, name_0, name_1, type_1 FROM gadm28_adm1 limit 10'

curl -i -X GET 'https://api.resourcewatch.org/v1/query?sql=SELECT cartodb_id, iso, name_0, name_1, type_1 FROM 098b33df-6871-4e53-a5ff-b56a7d989f9a limit 10'

curl -i -X POST 'https://api.resourcewatch.org/v1/query' \
-H 'Content-Type: application/json' \
-d '{
    "sql": "SELECT cartodb_id, iso, name_0, name_1, type_1 FROM 098b33df-6871-4e53-a5ff-b56a7d989f9a limit 10"
}'

The examples we've seen so far expect the URL to have the /query/<dataset id or slug>?sql=SELECT * FROM <dataset.tableName> format. However, you can also use the equivalent /query?sql=SELECT * FROM <dataset id> syntax. You can also use this alternative syntax with POST requests.

Redundant FROM clause (document based datasets only)

Example query providing a document-based dataset id in the request path or as the FROM clause:

curl -i -X GET 'https://api.resourcewatch.org/v1/query?sql=SELECT alert__date FROM 9be3bf63-97fc-4bb0-b913-775ccae3cf9e limit 10'
curl -i -X GET 'https://api.resourcewatch.org/v1/query/9be3bf63-97fc-4bb0-b913-775ccae3cf9e?sql=SELECT alert__date FROM data limit 10'

When querying a document based dataset using either GET or POST /query/<dataset id or slug> request, the FROM clause is required but ignored, meaning you don't have to provide the dataset's tableName as you normally would. The example on the side illustrates this.

Downloading data from a dataset

Structure of the endpoint for downloading the results of a query:

curl -i -X GET 'https://api.resourcewatch.org/v1/download/<dataset.id>?sql=SELECT * FROM <dataset.tableName>'

Example endpoint for downloading the results of a query:

curl -i -X GET 'https://api.resourcewatch.org/v1/download/098b33df-6871-4e53-a5ff-b56a7d989f9a?sql=SELECT cartodb_id, iso, name_0, name_1, type_1 FROM gadm28_adm1 limit 10'

The download endpoint allows you to download the results of the execution of a query over a dataset. This endpoint is greatly based on the query datasets endpoint, so we strongly suggest you read that section of the documentation.

Note: Some dataset providers do not support downloading query results. You can download query results for the following dataset providers:

Like when querying datasets, in order to download the results of the execution of query, you'll need two pieces of information:

The dataset documentation covers different ways that you can use to browse the existing dataset catalog or upload your own, all of which will give you the details of a dataset, including the dataset id you'll need to query it.

The SQL query will have to be custom built by you to fit your needs, but a good starting point for newcomers would be something like SELECT * FROM <dataset.tableName> limit 10.

Notice: the limit parameter restricts our results to 10 rows, and is not required. However, for our learning purposes, this is useful, as it keeps the API responses small and fast.

As with the query endpoint, the FROM clause should reference the dataset's tableName value, which you can also get from the dataset documentation described above. And also, don't forget that you can check the support provided for the dataset type you are using if you are having trouble writing your SQL query.

Download response body

Example of downloading query results (by default, CSV data is assumed):

curl -i -X GET 'https://api.resourcewatch.org/v1/download/9be3bf63-97fc-4bb0-b913-775ccae3cf9e?sql=SELECT alert__date, alert__count from gadm28_adm1 limit 2'

Example CSV response:

"alert__date",
"alert__count",
"_id"
"2019-04-12",
5,
"AW6O0fqMLu2ttL7ZDM4P"
"2015-08-22",
6,
"AW6O0fqMLu2ttL7ZDM4T"

Example of downloading query results requesting format as JSON:

curl -i -X GET 'https://api.resourcewatch.org/v1/download/9be3bf63-97fc-4bb0-b913-775ccae3cf9e?sql=SELECT alert__date, alert__count from gadm28_adm1 limit 2&format=json'

Example JSON response:

{
    "data": [
        {
            "alert__date": "2019-04-12",
            "alert__count": 5,
            "_id": "AW6O0fqMLu2ttL7ZDM4P"
        },
        {
            "alert__date": "2015-08-22",
            "alert__count": 6,
            "_id": "AW6O0fqMLu2ttL7ZDM4T"
        }
    ]
}

The response body of executing the download endpoint will contain the data to be downloaded. You can use the format query parameter to customize the format of the data returned. By default, format=csv will be assumed, so you will receive the corresponding query results the actual CSV data in the response body. If you provide format=json, the returned result will be a JSON object with a data index containing the results of the execution of the query provided.

Download execution errors

Calling the download endpoint might sometimes result in an error being returned. The following table describes the possible errors that can occur when downloading query execution results:

Error code Error message Description
400 SQL or FS required The required sql field is missing either as query string parameter or in the request body.
400 - format: format must be in [json,csv]. - If provided, format must be either csv or json.
500 Internal server error The error message might vary in this case.

Download endpoint parameters

Example of requesting to freeze the download results:

curl -i -X GET 'https://api.resourcewatch.org/v1/download/9be3bf63-97fc-4bb0-b913-775ccae3cf9e?sql=SELECT alert__date from gadm28_adm1 limit 2&freeze=true' \
-H "Authorization: Bearer <your-token>"

Example response:

{
    "url": "https://storage.googleapis.com/query-freeze/1589458072773.json"
}

You can use the following query parameters to customize the output of the download query execution results endpoint:

Query parameter Description Type Required
sql The SQL query to be executed. This parameter changes the data returned in the query response body. String Yes
format The format of the returned response. By default, CSV format is assumed (csv), but you can also request the response as JSON (json). Check the section on the download endpoint response body for some examples of how the format query parameter can be used. String No
freeze The freeze parameter, when provided as true, will create a file with the results of the execution of the query and return the URL for that file. Please note that you should be authenticated in order to request freezing the results of query executions. Boolean No
geostore Read more about the geostore query parameter here. String No

Filter download results by geostore

Example download request providing a geostore id as query parameter to filter the results:

curl -i -X GET 'https://api.resourcewatch.org/v1/download/1d7085f7-11c7-4eaf-a29a-5a4de57d010e?sql=SELECT * FROM dis_001_significant_earthquakes LIMIT 5&geostore=972c24e1da2c2baacc7572ee9501abdc'

Some dataset providers support receiving a geostore query parameter. When providing this parameter, you can request geo-referenced data that fits within the bounding box of the geostore with id provided. You can obtain the id of the geostore using the RW API Geostore API. If the data is not geo-referenced, or if the dataset provider does not support the geostore query parameter, it will be ignored.

The following providers support this parameter:

Alternative ways for downloading query execution results

As in the case of querying datasets, there are some alternative ways that you can use for downloading query execution results. While the GET request described above is the recommended way of downloading query results, there are other ways to download query results that may be more suited for specific use cases.

Using the dataset slug instead of the id

Example request for downloading the query execution results not using the dataset id in the request path, and using the dataset slug in the FROM clause:

curl -i -X GET 'https://api.resourcewatch.org/v1/download/9be3bf63-97fc-4bb0-b913-775ccae3cf9e?sql=SELECT alert__date from gadm28_adm1 limit 2'
curl -i -X GET 'https://api.resourcewatch.org/v1/download/Glad-Alerts-Daily-Geostore-User-Areas_3?sql=SELECT alert__date from gadm28_adm1 limit 2'

When referencing a dataset's id in th SQL query, you have the option to use the dataset's slug instead, obtaining the same result. This is also applicable to the alternative download methods described in the sections below.

POST requests

The same download request executed as GET, and as a POST request providing the SQL as request body param:

curl -i -X GET 'https://api.resourcewatch.org/v1/download/9be3bf63-97fc-4bb0-b913-775ccae3cf9e?sql=SELECT alert__date from gadm28_adm1 limit 2'
curl -i -X POST 'https://api.resourcewatch.org/v1/download/9be3bf63-97fc-4bb0-b913-775ccae3cf9e' \
-H 'Content-Type: application/json' \
-d '{
    "sql": "SELECT alert__date from gadm28_adm1 limit 2"
}'

Using the GET request is the recommended approach, as it allows HTTP caching of your result - subsequent requests for the same download endpoint call will see a great performance increase, even if they are made by a different application or client.

Alternatively, you can also download the query results using a POST request. POST requests are not cached, so you will not benefit from these speed improvements. However, GET requests can sometimes hit URL length restrictions, should your SQL query string be too long. Using a POST request is the recommended solution for these cases. See the example on the side to see how you can download the query execution results with a POST request.

Dataset id as the FROM clause

Three different but equivalent syntaxes for the same call to the download endpoint:

curl -i -X GET 'https://api.resourcewatch.org/v1/download/098b33df-6871-4e53-a5ff-b56a7d989f9a?sql=SELECT cartodb_id, iso, name_0, name_1, type_1 FROM gadm28_adm1 limit 10'

curl -i -X GET 'https://api.resourcewatch.org/v1/download?sql=SELECT cartodb_id, iso, name_0, name_1, type_1 FROM 098b33df-6871-4e53-a5ff-b56a7d989f9a limit 10'

curl -i -X POST 'https://api.resourcewatch.org/v1/download' \
-H 'Content-Type: application/json' \
-d '{
    "sql": "SELECT cartodb_id, iso, name_0, name_1, type_1 FROM 098b33df-6871-4e53-a5ff-b56a7d989f9a limit 10"
}'

The examples we've seen so far expect the URL to have the /download/<dataset id or slug>?sql=SELECT * FROM <dataset.tableName> format. However, you can also use the equivalent /download?sql=SELECT * FROM <dataset id> syntax. This alternative syntax is also available for POST requests.

Redundant FROM clause (document-based datasets only)

Example download providing a document-based dataset id in the request path or as the FROM clause:

curl -i -X GET 'https://api.resourcewatch.org/v1/download?sql=SELECT alert__date FROM 9be3bf63-97fc-4bb0-b913-775ccae3cf9e limit 10'
curl -i -X GET 'https://api.resourcewatch.org/v1/download/9be3bf63-97fc-4bb0-b913-775ccae3cf9e?sql=SELECT alert__date FROM data limit 10'

When downloading the query results for a document based dataset using either GET or POST /download/<dataset id or slug> request, the FROM clause is required but ignored, meaning you don't have to provide the dataset's tableName as you normally would. The example on the side illustrates this.

Deleting data from a dataset

Example requests to delete data from a dataset:

curl -i -X GET 'https://api.resourcewatch.org/v1/query/:dataset_id?sql=DELETE FROM index_bf86b945c4ec41d2b5b7af00f3f61423'
curl -i -X GET 'https://api.resourcewatch.org/v1/query/:dataset_id?sql=DELETE FROM index_bf86b945c4ec41d2b5b7af00f3f61423 WHERE x = "y"'

Write queries such as INSERT or UPDATE are not supported in the RW API. You can use dataset endpoints to append or overwrite a given dataset's data, but you cannot use SQL to write data into the datasets.

Most providers do not support DELETE queries either. However, in the case of document-based datasets (i.e. where the connectorType is document), you can delete the dataset's data via SQL DELETE query. Executing a DELETE query requires authentication, and additionally, one of the following conditions must be met:

If the query is successfully executed, the request will return an HTTP response with status code 204 No Content. Please note that executing a delete query is an asynchronous process - as in the case of appending or overwriting a dataset's data, the dataset will have its status updated to pending, and updated once again to saved once the deletion process is completed.

Delete query execution errors

Error code Error message Description
403 Forbidden Not authorized to execute DELETE query - the logged user provided does not meet at least one of the conditions required to be able to delete the dataset data.
400 Unsupported query element detected The SQL query provided is not valid, or the syntax provided is not supported.

Supported SQL syntax reference

This section details the support for SQL syntax for the different dataset providers RW API supports. Keep in mind that your HTTP request parameters (like sql) should always be escaped according to the official HTTP specification. You can use this online tool as an example of proper URL parameter encoding.

CartoDB datasets

This section describes the SQL support for querying datasets with provider cartodb.

Supported Feature Example URL
YES SELECT: Selecting all columns using wildcard SELECT * FROM edi LIMIT 5
YES SELECT: Count all rows SELECT count(*) FROM edi
YES SELECT: Selecting specific columns SELECT region, overall_score FROM edi LIMIT 5
YES SELECT: Selecting DISTINCT values for specific columns SELECT DISTINCT(region) FROM edi LIMIT 5
NO SELECT: Selecting columns AND counting all rows SELECT region, count(*) FROM edi LIMIT 5
YES SELECT: Aliasing aggregate function results such as AVG in SELECT SELECT AVG(overall_score) as alias FROM edi LIMIT 5
YES SELECT: Usage of aggregate functions (AVG) in SELECT SELECT AVG(overall_score) FROM edi LIMIT 5
YES SELECT: Usage of aggregate functions (MAX) in SELECT SELECT MAX(overall_score) FROM edi LIMIT 5
YES SELECT: Usage of aggregate functions (MIN) in SELECT SELECT MIN(overall_score) FROM edi LIMIT 5
YES SELECT: Usage of aggregate functions (SUM) in SELECT SELECT SUM(overall_score) FROM edi LIMIT 5
YES FROM: Using dataset id in FROM statement SELECT * FROM 0b9f0100-ce5b-430f-ad8f-3363efa05481 LIMIT 5
YES FROM: Using dataset slug in FROM statement SELECT * FROM Environmental-Democracy-Index-1490086842552 LIMIT 5
YES FROM: Using dataset tableName in FROM statement SELECT * FROM edi LIMIT 5
YES WHERE: Greater than filtering SELECT * FROM edi WHERE overall_score > 2 LIMIT 5
YES WHERE: Greater than or equal filtering SELECT * FROM edi WHERE overall_score >= 2 LIMIT 5
YES WHERE: Equality filtering SELECT * FROM edi WHERE overall_score = 2.1 LIMIT 5
YES WHERE: Lower than filtering SELECT * FROM edi WHERE overall_score < 2.2 LIMIT 5
YES WHERE: Lower than or equal filtering SELECT * FROM edi WHERE overall_score <= 2.2 LIMIT 5
YES WHERE: Conjunction (AND) filtering SELECT * FROM edi WHERE overall_score <= 2.2 AND justice_pillar_score > 1 LIMIT 5
YES WHERE: Disjunction (OR) filtering SELECT * FROM edi WHERE overall_score <= 2.2 OR justice_pillar_score > 1 LIMIT 5
YES WHERE: BETWEEN filtering SELECT * FROM edi WHERE overall_score BETWEEN 2 AND 2.2 LIMIT 5
YES WHERE: LIKE filtering SELECT * FROM edi WHERE region LIKE 'Europ%' LIMIT 5
YES GROUP BY: Group results by a single column SELECT region FROM edi GROUP BY region LIMIT 5
YES GROUP BY: Group results by multiple columns SELECT region, overall_score FROM edi GROUP BY region, overall_score LIMIT 5
YES GROUP BY: Aggregate functions used with GROUP BY statements SELECT region, COUNT(*) as count FROM edi GROUP BY region LIMIT 5
NO GROUP BY: Special grouping by range function SELECT count(*) FROM edi GROUP BY range(overall_score, 0,1,2,3,4) LIMIT 5
YES ORDER BY: Ordering results by one column SELECT region FROM edi ORDER BY region LIMIT 5
YES ORDER BY: Ordering results by one column descending SELECT region FROM edi ORDER BY region DESC LIMIT 5
YES ORDER BY: Ordering results by multiple column SELECT region, overall_score FROM edi ORDER BY region, overall_score LIMIT 5
YES ORDER BY: Ordering results by multiple column descending SELECT region, overall_score FROM edi ORDER BY region, overall_score DESC LIMIT 5
YES LIMIT: Limit the number of returned results SELECT region FROM edi LIMIT 5
NO OFFSET: Offset the returned results SELECT region FROM edi LIMIT 5 OFFSET 10
NO OFFSET: Offset the returned results using short syntax SELECT region FROM edi LIMIT 5, 10

CartoDB geo-spatial query support

CartoDB datasets can be queried using PostGIS functions. This means if your dataset contains geo-referenced data, you can execute PostGIS functions on the data to extract the information you need. The table below displays some examples of supported PostGIS functions:

Supported Feature Example URL
YES PostGIS: ST_MetaData SELECT ST_METADATA(the_raster_webmercator) FROM sp_richness LIMIT 5
YES PostGIS: ST_BandMetaData SELECT ST_BANDMETADATA(the_raster_webmercator) FROM sp_richness LIMIT 5
YES PostGIS: ST_SummaryStats SELECT ST_SUMMARYSTATS(the_raster_webmercator, true) FROM sp_richness LIMIT 5
YES PostGIS: ST_Histogram SELECT ST_HISTOGRAM(the_raster_webmercator) FROM sp_richness LIMIT 5
YES PostGIS: ST_ValueCount SELECT ST_VALUECOUNT(the_raster_webmercator) FROM sp_richness LIMIT 5
YES Using PostGIS functions in WHERE clause SELECT * FROM sp_richness WHERE ST_METADATA(the_raster_webmercator) IS NOT NULL LIMIT 5
NO Using PostGIS functions in GROUP BY clause SELECT * FROM sp_richness GROUP BY ST_SUMMARYSTATS(the_raster_webmercator, true) IS NOT NULL LIMIT 5
YES Using PostGIS functions in ORDER BY clause SELECT * FROM sp_richness ORDER BY ST_METADATA(the_raster_webmercator) IS NOT NULL LIMIT 5

ArcGIS Feature Service datasets

This section describes the SQL support for querying datasets with connector type rest and provider featureservice.

Supported Feature Example URL
YES SELECT: Selecting all columns using wildcard SELECT * FROM cdonexradMapServer0 LIMIT 5
YES SELECT: Count all rows SELECT count(*) FROM cdonexradMapServer0
YES SELECT: Selecting specific columns SELECT STATION_NAME, ELEVATION FROM cdonexradMapServer0 LIMIT 5
NO SELECT: Selecting DISTINCT values for specific columns SELECT DISTINCT(STATION_NAME) FROM cdonexradMapServer0 LIMIT 5
NO SELECT: Selecting columns AND counting all rows SELECT STATION_NAME, count(*) FROM cdonexradMapServer0 LIMIT 5
YES SELECT: Aliasing aggregate function results such as AVG in SELECT SELECT AVG(ELEVATION) as alias FROM cdonexradMapServer0 LIMIT 5
YES SELECT: Usage of aggregate functions (AVG) in SELECT SELECT AVG(ELEVATION) FROM cdonexradMapServer0 LIMIT 5
YES SELECT: Usage of aggregate functions (MAX) in SELECT SELECT MAX(ELEVATION) FROM cdonexradMapServer0 LIMIT 5
YES SELECT: Usage of aggregate functions (MIN) in SELECT SELECT MIN(ELEVATION) FROM cdonexradMapServer0 LIMIT 5
YES SELECT: Usage of aggregate functions (SUM) in SELECT SELECT SUM(ELEVATION) FROM cdonexradMapServer0 LIMIT 5
YES FROM: Using dataset id in FROM statement SELECT * FROM 0b9e546c-f42a-4b26-bad3-7d606f58961c LIMIT 5
YES FROM: Using dataset slug in FROM statement SELECT * FROM NOAA-NEXt-Generation-RADar-NEXRAD-Products-Locations-1490086842546 LIMIT 5
YES FROM: Using dataset tableName in FROM statement SELECT * FROM cdonexradMapServer0 LIMIT 5
YES WHERE: Greater than filtering SELECT * FROM cdonexradMapServer0 WHERE ELEVATION > 3587 LIMIT 5
YES WHERE: Greater than or equal filtering SELECT * FROM cdonexradMapServer0 WHERE ELEVATION >= 3587 LIMIT 5
YES WHERE: Equality filtering SELECT * FROM cdonexradMapServer0 WHERE ELEVATION = 5870 LIMIT 5
YES WHERE: Lower than filtering SELECT * FROM cdonexradMapServer0 WHERE ELEVATION < 5000 LIMIT 5
YES WHERE: Lower than or equal filtering SELECT * FROM cdonexradMapServer0 WHERE ELEVATION <= 5000 LIMIT 5
YES WHERE: Conjunction (AND) filtering SELECT * FROM cdonexradMapServer0 WHERE ELEVATION <= 5000 AND LATITUDE > 35.23333 LIMIT 5
YES WHERE: Disjunction (OR) filtering SELECT * FROM cdonexradMapServer0 WHERE ELEVATION <= 5000 OR LATITUDE > 35.23333 LIMIT 5
YES WHERE: BETWEEN filtering SELECT * FROM cdonexradMapServer0 WHERE ELEVATION BETWEEN 3587 AND 5000 LIMIT 5
YES WHERE: LIKE filtering SELECT * FROM cdonexradMapServer0 WHERE STATION_NAME LIKE 'AMARI%' LIMIT 5
YES GROUP BY: Group results by a single column SELECT STATION_NAME FROM cdonexradMapServer0 GROUP BY STATION_NAME LIMIT 5
YES GROUP BY: Group results by multiple columns SELECT STATION_NAME, ELEVATION FROM cdonexradMapServer0 GROUP BY STATION_NAME, ELEVATION LIMIT 5
NO GROUP BY: Aggregate functions used with GROUP BY statements SELECT STATION_NAME, COUNT(*) as count FROM cdonexradMapServer0 GROUP BY STATION_NAME LIMIT 5
YES GROUP BY: Special grouping by range function SELECT count(*) FROM cdonexradMapServer0 GROUP BY range(ELEVATION, 0,1,2,3,4) LIMIT 5
YES ORDER BY: Ordering results by one column SELECT STATION_NAME FROM cdonexradMapServer0 ORDER BY STATION_NAME LIMIT 5
YES ORDER BY: Ordering results by one column descending SELECT STATION_NAME FROM cdonexradMapServer0 ORDER BY STATION_NAME DESC LIMIT 5
YES ORDER BY: Ordering results by multiple column SELECT STATION_NAME, ELEVATION FROM cdonexradMapServer0 ORDER BY STATION_NAME, ELEVATION LIMIT 5
YES ORDER BY: Ordering results by multiple column descending SELECT STATION_NAME, ELEVATION FROM cdonexradMapServer0 ORDER BY STATION_NAME, ELEVATION DESC LIMIT 5
YES LIMIT: Limit the number of returned results SELECT STATION_NAME FROM cdonexradMapServer0 LIMIT 5
YES OFFSET: Offset the returned results SELECT STATION_NAME FROM cdonexradMapServer0 LIMIT 5 OFFSET 10
NO OFFSET: Offset the returned results using short syntax SELECT STATION_NAME FROM cdonexradMapServer0 LIMIT 5, 10

Note: This table was generated automatically with the help of this repository. If you are maintaining the docs, please do not edit manually these tables.

GEE datasets

This section describes the SQL support for querying datasets with connector type rest and providers gee.

Supported Feature Example URL
YES SELECT: Selecting all columns using wildcard SELECT * FROM users/resourcewatch_wri/foo_024_vegetation_health_index LIMIT 5
YES SELECT: Count all rows SELECT count(*) FROM users/resourcewatch_wri/foo_024_vegetation_health_index
YES SELECT: Selecting specific columns SELECT system:index, system:asset_size FROM users/resourcewatch_wri/foo_024_vegetation_health_index LIMIT 5
NO SELECT: Selecting DISTINCT values for specific columns SELECT DISTINCT(system:index) FROM users/resourcewatch_wri/foo_024_vegetation_health_index LIMIT 5
YES SELECT: Selecting columns AND counting all rows SELECT system:index, count(*) FROM users/resourcewatch_wri/foo_024_vegetation_health_index LIMIT 5
NO SELECT: Aliasing aggregate function results such as AVG in SELECT SELECT AVG(system:asset_size) as alias FROM users/resourcewatch_wri/foo_024_vegetation_health_index LIMIT 5
YES SELECT: Usage of aggregate functions (AVG) in SELECT SELECT AVG(system:asset_size) FROM users/resourcewatch_wri/foo_024_vegetation_health_index LIMIT 5
YES SELECT: Usage of aggregate functions (MAX) in SELECT SELECT MAX(system:asset_size) FROM users/resourcewatch_wri/foo_024_vegetation_health_index LIMIT 5
YES SELECT: Usage of aggregate functions (MIN) in SELECT SELECT MIN(system:asset_size) FROM users/resourcewatch_wri/foo_024_vegetation_health_index LIMIT 5
YES SELECT: Usage of aggregate functions (SUM) in SELECT SELECT SUM(system:asset_size) FROM users/resourcewatch_wri/foo_024_vegetation_health_index LIMIT 5
NO FROM: Using dataset id in FROM statement SELECT * FROM c12446ce-174f-4ffb-b2f7-77ecb0116aba LIMIT 5
NO FROM: Using dataset slug in FROM statement SELECT * FROM foo024nrt-Vegetation-Health-Index_replacement_4 LIMIT 5
YES FROM: Using dataset tableName in FROM statement SELECT * FROM users/resourcewatch_wri/foo_024_vegetation_health_index LIMIT 5
YES WHERE: Greater than filtering SELECT * FROM users/resourcewatch_wri/foo_024_vegetation_health_index WHERE system:asset_size > 36975655 LIMIT 5
YES WHERE: Greater than or equal filtering SELECT * FROM users/resourcewatch_wri/foo_024_vegetation_health_index WHERE system:asset_size >= 36975655 LIMIT 5
YES WHERE: Equality filtering SELECT * FROM users/resourcewatch_wri/foo_024_vegetation_health_index WHERE system:asset_size = 37153685 LIMIT 5
YES WHERE: Lower than filtering SELECT * FROM users/resourcewatch_wri/foo_024_vegetation_health_index WHERE system:asset_size < 37180450 LIMIT 5
YES WHERE: Lower than or equal filtering SELECT * FROM users/resourcewatch_wri/foo_024_vegetation_health_index WHERE system:asset_size <= 37180450 LIMIT 5
NO WHERE: Conjunction (AND) filtering SELECT * FROM users/resourcewatch_wri/foo_024_vegetation_health_index WHERE system:asset_size <= 37180450 AND system:time_start > 1572739200000 LIMIT 5
NO WHERE: Disjunction (OR) filtering SELECT * FROM users/resourcewatch_wri/foo_024_vegetation_health_index WHERE system:asset_size <= 37180450 OR system:time_start > 1572739200000 LIMIT 5
NO WHERE: BETWEEN filtering SELECT * FROM users/resourcewatch_wri/foo_024_vegetation_health_index WHERE system:asset_size BETWEEN 36975655 AND 37180450 LIMIT 5
NO WHERE: LIKE filtering SELECT * FROM users/resourcewatch_wri/foo_024_vegetation_health_index WHERE system:index LIKE 'foo_024_vegetation_health_index%' LIMIT 5
NO GROUP BY: Group results by a single column SELECT system:index FROM users/resourcewatch_wri/foo_024_vegetation_health_index GROUP BY system:index LIMIT 5
NO GROUP BY: Group results by multiple columns SELECT system:index, system:asset_size FROM users/resourcewatch_wri/foo_024_vegetation_health_index GROUP BY system:index, system:asset_size LIMIT 5
NO GROUP BY: Aggregate functions used with GROUP BY statements SELECT system:index, COUNT(*) as count FROM users/resourcewatch_wri/foo_024_vegetation_health_index GROUP BY system:index LIMIT 5
NO GROUP BY: Special grouping by range function SELECT count(*) FROM users/resourcewatch_wri/foo_024_vegetation_health_index GROUP BY range(system:asset_size, 0,1,2,3,4) LIMIT 5
NO ORDER BY: Ordering results by one column SELECT system:index FROM users/resourcewatch_wri/foo_024_vegetation_health_index ORDER BY system:index LIMIT 5
NO ORDER BY: Ordering results by one column descending SELECT system:index FROM users/resourcewatch_wri/foo_024_vegetation_health_index ORDER BY system:index DESC LIMIT 5
NO ORDER BY: Ordering results by multiple column SELECT system:index, system:asset_size FROM users/resourcewatch_wri/foo_024_vegetation_health_index ORDER BY system:index, system:asset_size LIMIT 5
NO ORDER BY: Ordering results by multiple column descending SELECT system:index, system:asset_size FROM users/resourcewatch_wri/foo_024_vegetation_health_index ORDER BY system:index, system:asset_size DESC LIMIT 5
YES LIMIT: Limit the number of returned results SELECT system:index FROM users/resourcewatch_wri/foo_024_vegetation_health_index LIMIT 5
YES OFFSET: Offset the returned results SELECT system:index FROM users/resourcewatch_wri/foo_024_vegetation_health_index LIMIT 5 OFFSET 10
NO OFFSET: Offset the returned results using short syntax SELECT system:index FROM users/resourcewatch_wri/foo_024_vegetation_health_index LIMIT 5, 10

Note: This table was generated automatically with the help of this repository. If you are maintaining the docs, please do not edit manually these tables.

Document-based datasets

This section describes the SQL support for querying datasets with connector type document and providers csv, tsv, json or xml.

While the API has it's own query handling mechanism, it mostly relies on Opendistro for Elasticsearch 1.x SQL support, meaning its limitations will also apply to queries done to document-based datasets.

Supported Feature Example URL
YES SELECT: Selecting all columns using wildcard SELECT * FROM data LIMIT 5
YES SELECT: Count all rows SELECT count(*) FROM data
YES SELECT: Selecting specific columns SELECT bra_biome__name, alert__count FROM data LIMIT 5
NO SELECT: Selecting DISTINCT values for specific columns SELECT DISTINCT(bra_biome__name) FROM data LIMIT 5
YES SELECT: Selecting columns AND counting all rows SELECT bra_biome__name, count(*) FROM data LIMIT 5
YES SELECT: Aliasing aggregate function results such as AVG in SELECT SELECT AVG(alert__count) as alias FROM data LIMIT 5
YES SELECT: Usage of aggregate functions (AVG) in SELECT SELECT AVG(alert__count) FROM data LIMIT 5
YES SELECT: Usage of aggregate functions (MAX) in SELECT SELECT MAX(alert__count) FROM data LIMIT 5
YES SELECT: Usage of aggregate functions (MIN) in SELECT SELECT MIN(alert__count) FROM data LIMIT 5
YES SELECT: Usage of aggregate functions (SUM) in SELECT SELECT SUM(alert__count) FROM data LIMIT 5
YES FROM: Using dataset id in FROM statement SELECT * FROM 9be3bf63-97fc-4bb0-b913-775ccae3cf9e LIMIT 5
YES FROM: Using dataset slug in FROM statement SELECT * FROM Glad-Alerts-Daily-Geostore-User-Areas_3 LIMIT 5
YES FROM: Using dataset tableName in FROM statement SELECT * FROM data LIMIT 5
YES WHERE: Greater than filtering SELECT * FROM data WHERE alert__count > 2 LIMIT 5
YES WHERE: Greater than or equal filtering SELECT * FROM data WHERE alert__count >= 2 LIMIT 5
YES WHERE: Equality filtering SELECT * FROM data WHERE alert__count = 5 LIMIT 5
YES WHERE: Lower than filtering SELECT * FROM data WHERE alert__count < 8 LIMIT 5
YES WHERE: Lower than or equal filtering SELECT * FROM data WHERE alert__count <= 8 LIMIT 5
YES WHERE: Conjunction (AND) filtering SELECT * FROM data WHERE alert__count <= 8 AND alert_area__ha > 0.1 LIMIT 5
YES WHERE: Disjunction (OR) filtering SELECT * FROM data WHERE alert__count <= 8 OR alert_area__ha > 0.1 LIMIT 5
YES WHERE: BETWEEN filtering SELECT * FROM data WHERE alert__count BETWEEN 2 AND 8 LIMIT 5
NO WHERE: LIKE filtering SELECT * FROM data WHERE bra_biome__name LIKE 'Amaz%' LIMIT 5
YES GROUP BY: Group results by a single column SELECT bra_biome__name FROM data GROUP BY bra_biome__name LIMIT 5
YES GROUP BY: Group results by multiple columns SELECT bra_biome__name, alert__count FROM data GROUP BY bra_biome__name, alert__count LIMIT 5
YES GROUP BY: Aggregate functions used with GROUP BY statements SELECT bra_biome__name, COUNT(*) as count FROM data GROUP BY bra_biome__name LIMIT 5
YES GROUP BY: Special grouping by range function SELECT count(*) FROM data GROUP BY range(alert__count, 0,1,2,3,4) LIMIT 5
YES ORDER BY: Ordering results by one column SELECT bra_biome__name FROM data ORDER BY bra_biome__name LIMIT 5
YES ORDER BY: Ordering results by one column descending SELECT bra_biome__name FROM data ORDER BY bra_biome__name DESC LIMIT 5
YES ORDER BY: Ordering results by multiple column SELECT bra_biome__name, alert__count FROM data ORDER BY bra_biome__name, alert__count LIMIT 5
YES ORDER BY: Ordering results by multiple column descending SELECT bra_biome__name, alert__count FROM data ORDER BY bra_biome__name, alert__count DESC LIMIT 5
YES LIMIT: Limit the number of returned results SELECT bra_biome__name FROM data LIMIT 5
YES OFFSET: Offset the returned results SELECT bra_biome__name FROM data LIMIT 5 OFFSET 10
NO OFFSET: Offset the returned results using short syntax SELECT bra_biome__name FROM data LIMIT 5, 10

Note: This table was generated automatically with the help of this repository. If you are maintaining the docs, please do not edit manually these tables.

Troubleshooting SQL queries for document-based datasets

This SQL syntax supported when running queries for document-based datasets has some known limitations:

You can read more about the limitations of using SQL with document-based datasets here.

Rasdaman datasets

SQL-like queries can be employed for accessing data stored in Rasdaman datasets. Subsets on the original axes of the data may be provided in the WHERE statement. So far, only operations that result in a single scalar can be obtained from Rasdaman - averages, minimums, maximums.

curl -XGET 'https://api.resourcewatch.org/v1/query?sql=SELECT avg(Green) from 18c0b71d-2f55-4a45-9e5b-c35db3ebfe94 where Lat > 0 and  Lat < 45' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer <token>'

NEX-GDDP and Loca datasets

Example of a query for a NEX-GDDP/Loca dataset, providing lat and lon as query parameters:

curl -X GET 'https://api.resourcewatch.org/v1/query/aaadd6c3-93ea-44bc-ba8b-7af3f40d39e1?sql=SELECT * FROM data&lat=30&lon=9'

Example of a query for a NEX-GDDP/Loca dataset, providing a geostore id:

curl -X GET 'https://api.resourcewatch.org/v1/query/aaadd6c3-93ea-44bc-ba8b-7af3f40d39e1?sql=SELECT * FROM data&geostore=972c24e1da2c2baacc7572ee9501abdc'

Example response:

{
  "data": [
    {
      "tasmin": 243.6352,
      "tasmin_q25": 243.4849,
      "tasmin_q75": 243.8861,
      "year": "1971-01-01T00:00:00-01:00"
    },
    {
      "tasmin": 244.0795,
      "tasmin_q25": 243.7174,
      "tasmin_q75": 244.3168,
      "year": "1981-01-01T00:00:00-01:00"
    },
    {
      "tasmin": 244.4218,
      "tasmin_q25": 243.9681,
      "tasmin_q75": 244.5883,
      "year": "1991-01-01T00:00:00-01:00"
    },
    {
      "tasmin": 244.697,
      "tasmin_q25": 244.2883,
      "tasmin_q75": 244.8852,
      "year": "2001-01-01T00:00:00-01:00"
    },
    {
      "tasmin": 244.7719,
      "tasmin_q25": 244.3449,
      "tasmin_q75": 245.0115,
      "year": "2011-01-01T00:00:00-01:00"
    }
  ]
}

Like with the other supported providers, you can use a SQL-like syntax to query datasets stored both in NASA NEX-GDDP or in Loca. However, these datasets always contain geo-referenced data, and so they expect that you always provide either a lat + lon pair, or a geostore id, in order to filter the returned data. If you don't provide either a geostore id or a lat+lon pair, the request will fail with status code 400 Bad Request, with the following message: No coordinates provided. Include geostore or lat & lon.

The examples on the side allow you to understand how you can provide either the geostore id or the lat + lon combination.

WMS datasets

Queries to WMS datasets are no longer supported.

Layer

What is a layer?

By now, you are probably already familiar with datasets and querying them (if you are not, now is a good time to get up to speed on those). Many of the datasets you'll find on the RW API - and perhaps the datasets you are uploading too - contain georeferenced information. If that's the case, then you may want to render your data as a web map layer, and the RW API's layer endpoints can help you with that.

As we've seen in the layer concept docs, a RW API layer may store data in different formats, depending on the needs of its author. This is done using the several open format fields a layer has. To keep this documentation easy to understand, we'll spit our approach to layers into two sections:

After viewing the documentation below, consider looking at the webmap tutorial for a step-by-step guide to rendering an actual layer on a web application.

Getting all layers

Getting a list of layers

curl -X GET "https://api.resourcewatch.org/v1/layer"

Example response:

{
    "data": [
        {
            "id": "e5c3e7c5-19ae-4ca0-a461-71f1f67aa553",
            "type": "layer",
            "attributes": {
                "slug": "total-co2-emissions-by-year",
                "userId": "5858f37140621f11066fb2f7",
                "application": [
                    "rw"
                ],
                "name": "Total CO2 emissions by year",
                "default": false,
                "dataset": "11de2bc1-368b-42ed-a207-aaff8ece752b",
                "env": "production",
                "provider": "cartodb",
                "iso": [],
                "description": null,
                "layerConfig": {
                    "account": "rw",
                    "body": {
                        "maxzoom": 18,
                        "minzoom": 3,
                        "layers": [
                            {
                                "type": "mapnik",
                                "options": {
                                    "sql": "SELECT * cait_2_0_country_ghg_emissions_filtered",
                                    "cartocss": "",
                                    "cartocss_version": "2.3.0"
                                }
                            }
                        ]
                    }
                },
                "legendConfig": {
                    "marks": {
                        "type": "rect",
                        "from": {
                            "data": "table"
                        }
                    }
                },
                "applicationConfig": {},
                "staticImageConfig": {}
            }
        }
    ],
    "links": {
        "self": "https://api.resourcewatch.org/v1/layer?page[number]=1&page[size]=10",
        "first": "https://api.resourcewatch.org/v1/layer?page[number]=1&page[size]=10",
        "last": "https://api.resourcewatch.org/v1/layer?page[number]=634&page[size]=10",
        "prev": "https://api.resourcewatch.org/v1/layer?page[number]=1&page[size]=10",
        "next": "https://api.resourcewatch.org/v1/layer?page[number]=2&page[size]=10"
    },
    "meta": {
        "total-pages": 63,
        "total-items": 628,
        "size": 10
    }
}

This endpoint allows you to list existing layers and their properties. The result is a paginated list of 10 layers, followed by metadata on total number of layers and pages, as well as useful pagination links. By default, only layers with env value production are displayed. In the sections below, we’ll explore how you can customize this endpoint call to match your needs.

Getting all layers for a dataset

Return the layers associated with a dataset

curl -X GET "https://api.resourcewatch.org/v1/dataset/<dataset-id>/layer"

When handling layers, it's common to want to limit results to those layers associated with a given dataset. Besides the filters covered below, there's an additional convenience endpoint to get the layers associated with a dataset, as shown in this example.

Getting all layers for multiple datasets

Return all layers associated with two datasets

curl -X POST "https://api.resourcewatch.org/layer/find-by-ids" \
-H "Authorization: Bearer <your-token>" \
-H 'Content-Type: application/json' \
-d '{
    "ids": ["<dataset 1 id>", "<dataset 2 id>"]
}'
{
    "data": [
        {
            "id": "0dc39924-5736-4898-bda4-49cdc2f3b208",
            "type": "layer",
            "attributes": {
                "name": "NOAA NEXt-Generation RADar (NEXRAD) Products (Locations)",
                "slug": "noaa-next-generation-radar-nexrad-products-locations",
                "dataset": "0b9e546c-f42a-4b26-bad3-7d606f58961c",
                "description": "",
                "application": [
                    "prep"
                ],
                "iso": [
                    "USA"
                ],
                "provider": "arcgis",
                "userId": "legacy",
                "default": true,
                "protected": false,
                "published": false,
                "env": "production",
                "layerConfig": {
                    "body": {
                        "useCors": false,
                        "layers": [
                            0
                        ],
                        "url": "https://gis.ncdc.noaa.gov/arcgis/rest/services/cdo/nexrad/MapServer"
                    },
                    "type": "dynamicMapLayer"
                },
                "legendConfig": {
                    "type": "basic",
                    "items": [
                        {
                            "name": "NEXRAD",
                            "color": "#FF0000",
                            "icon": "http://gis.ncdc.noaa.gov/arcgis/rest/services/cdo/nexrad/MapServer/0/images/47768c7d812818af98d8da03a04d4fe4"
                        }
                    ]
                },
                "interactionConfig": {},
                "applicationConfig": {},
                "staticImageConfig": {},
                "createdAt": "2016-09-07T14:50:22.578Z",
                "updatedAt": "2017-12-18T12:08:25.703Z"
            }
        },
        {
            "id": "0b021478-f4d3-4a1e-ae88-ab97f0085bc9",
            "type": "layer",
            "attributes": {
                "name": "Projected change in average precipitation (in)",
                "slug": "projected-change-in-average-precipitation-between-u-s",
                "dataset": "d443beca-d199-4872-9d7d-d82c45e43151",
                "description": "Projected change in average precipitation for the A2 emissions scenario.",
                "application": [
                    "prep"
                ],
                "iso": [
                    "USA"
                ],
                "provider": "arcgis",
                "userId": "legacy",
                "default": true,
                "protected": false,
                "published": false,
                "env": "production",
                "layerConfig": {
                    "body": {
                        "use-cors": false,
                        "layers": [
                            12
                        ],
                        "url": "https://gis-gfw.wri.org/arcgis/rest/services/prep/nca_figures/MapServer"
                    },
                    "zoom": 4,
                    "center": {
                        "lat": 39.6395375643667,
                        "lng": -99.84375
                    },
                    "type": "dynamicMapLayer",
                    "bbox": [
                        -125.61,
                        24.73,
                        -66.81,
                        49.07
                    ]
                },
                "legendConfig": {
                    "type": "choropleth",
                    "items": [
                        {
                            "value": "< -90",
                            "color": "#8C5107"
                        },
                        {
                            "value": "-90 - -60",
                            "color": "#BF822B"
                        }
                    ]
                },
                "interactionConfig": {},
                "applicationConfig": {},
                "staticImageConfig": {},
                "createdAt": "2016-09-15T13:47:39.829Z",
                "updatedAt": "2018-03-02T20:54:17.260Z"
            }
        }
    ]
}

This endpoint allows authenticated users to load all layers belonging to multiple datasets in a single request.

Return all layers associated with two datasets, that are associated with either rw or prep applications

curl -X POST "https://api.resourcewatch.org/layer/find-by-ids" \
-H "Authorization: Bearer <your-token>" \
-H 'Content-Type: application/json' \
-d '{
    "ids": ["<dataset 1 id>", "<dataset 2 id>"],
    "app" "rw,prep"
}'

Return all layers associated with two datasets, that are associated with both rw and prep applications simultaneously

curl -X POST "https://api.resourcewatch.org/layer/find-by-ids" \
-H "Authorization: Bearer <your-token>" \
-H 'Content-Type: application/json' \
-d '{
    "ids": ["<dataset 1 id>", "<dataset 2 id>"],
    "app" "rw@prep"
}'

Besides the required ids array, your request body may optionally include a app string value if you'd like to filter the returned layers by their application:

Please note that, unlike getting all layers or getting all layers for a dataset, this endpoint does not come with paginated results, nor does it support pagination, filtering or sorting or including related entities described in their respective sections.

Pagination

Example request to load page 2 using 25 results per page

curl -X GET "https://api.resourcewatch.org/v1/layer?page[number]=2&page[size]=25"

The Layers service adheres to the conventions defined in the Pagination guidelines for the RW API, so we recommend reading that section for more details on how paginate your layers list.

Filters

Return the layers filtered by those whose name contains emissions

curl -X GET "https://api.resourcewatch.org/v1/layer?name=emissions"

Return the layers filtered by dataset

curl -X GET "https://api.resourcewatch.org/v1/layer?dataset=11de2bc1-368b-42ed-a207-aaff8ece752b"
curl -X GET "https://api.resourcewatch.org/v1/dataset/11de2bc1-368b-42ed-a207-aaff8ece752b/layer"

Filter layers by published status

curl -X GET "https://api.resourcewatch.org/v1/layer?published=false"

Filter layers by environment

curl -X GET "https://api.resourcewatch.org/v1/layer?env=staging"

Return the layers filtered by those whose applications contain rw

curl -X GET "https://api.resourcewatch.org/v1/layer?app=rw"

The layer list endpoint provides a wide range of filters that you can use to tailor your layer listing. Filtering layers adheres to the conventions defined in the Filter guidelines for the RW API, so we strongly recommend reading that section before proceeding. In addition to these conventions, you will be able to use the great majority of the layer fields you'll find on the layer reference section, with the following exceptions:

Additionally, you can use the following filters:

Sorting

Sorting layers

curl -X GET "https://api.resourcewatch.org/v1/layer?sort=name"

Sorting layers by multiple criteria

curl -X GET "https://api.resourcewatch.org/v1/layer?sort=name,slug"

Explicit order of sorting

curl -X GET "https://api.resourcewatch.org/v1/layer?sort=-name,+slug"

Sorting layers by the role of the user who owns the layer

curl -X GET "https://api.resourcewatch.org/v1/layer?sort=user.role"

The Layer service currently supports sorting using the sort query parameter. Sorting layer adheres to the conventions defined in the Sorting guidelines for the RW API, so we strongly recommend reading that section before proceeding. Additionally, you can check out the Layer reference section for a detailed description of the fields you can use when sorting. In addition to all layer model fields, you can sort the returned results by the name (using user.name) or role (using user.role) of the user owner of the layer. Keep in mind that sorting by user data is restricted to ADMIN users.

Include entities associated with the layers

When fetching layers, you can request additional entities to be loaded. The following entities are available:

Vocabulary

Loads vocabulary associated with each layer:

curl -X GET "https://api.resourcewatch.org/v1/layer?includes=vocabulary"

Example response:

{
    "data": [
        {
            "id": "e5c3e7c5-19ae-4ca0-a461-71f1f67aa553",
            "type": "layer",
            "attributes": {
                "slug": "total-co2-emissions-by-year",
                "userId": "5858f37140621f11066fb2f7",
                "application": [
                    "rw"
                ],
                "name": "Total CO2 emissions by year",
                "default": false,
                "dataset": "11de2bc1-368b-42ed-a207-aaff8ece752b",
                "env": "production",
                "provider": "cartodb",
                "iso": [],
                "description": null,
                "layerConfig": {
                    "account": "rw",
                    "body": {
                        "maxzoom": 18,
                        "minzoom": 3,
                        "layers": [
                            {
                                "type": "mapnik",
                                "options": {
                                    "sql": "SELECT * cait_2_0_country_ghg_emissions_filtered",
                                    "cartocss": "",
                                    "cartocss_version": "2.3.0"
                                }
                            }
                        ]
                    }
                },
                "legendConfig": {
                    "marks": {
                        "type": "rect",
                        "from": {
                            "data": "table"
                        }
                    }
                },
                "applicationConfig": {},
                "staticImageConfig": {},
                "vocabulary": [
                    {
                        "id": "resourcewatch",
                        "type": "vocabulary",
                        "attributes": {
                            "tags": [
                                "inuncoast",
                                "rp0002",
                                "historical",
                                "nosub"
                            ],
                            "name": "resourcewatch",
                            "application": "rw"
                        }
                    }
                ]
            }
        }
    ]
}

Loads all vocabulary entities associated with each layer. Internally this uses the dataset/<dataset_id>/layer/<layer_id>/vocabulary endpoint, and thus it's affected by its behavior - particularly, only vocabularies associated with the rw application will be listed. There's currently no way to modify this behavior.

User

Loads the name and email address of the author of the layer. If you request this issue as an authenticated user with ADMIN role, you will additionally get the author's role.

If the data is not available (for example, the user has since been deleted), no user property will be added to the layer object.

curl -X GET "https://api.resourcewatch.org/v1/layer?includes=user"

Example response:

{
    "data": [
        {
            "id": "e5c3e7c5-19ae-4ca0-a461-71f1f67aa553",
            "type": "layer",
            "attributes": {
                "slug": "total-co2-emissions-by-year",
                "userId": "5858f37140621f11066fb2f7",
                "application": [
                    "rw"
                ],
                "name": "Total CO2 emissions by year",
                "default": false,
                "dataset": "11de2bc1-368b-42ed-a207-aaff8ece752b",
                "env": "production",
                "provider": "cartodb",
                "iso": [],
                "description": null,
                "layerConfig": {
                    "account": "rw",
                    "body": {
                        "maxzoom": 18,
                        "minzoom": 3,
                        "layers": [
                            {
                                "type": "mapnik",
                                "options": {
                                    "sql": "SELECT * cait_2_0_country_ghg_emissions_filtered",
                                    "cartocss": "",
                                    "cartocss_version": "2.3.0"
                                }
                            }
                        ]
                    }
                },
                "legendConfig": {
                    "marks": {
                        "type": "rect",
                        "from": {
                            "data": "table"
                        }
                    }
                },
                "applicationConfig": {},
                "staticImageConfig": {},
                "user": {
                    "name": "John Doe",
                    "email": "john.doe@vizzuality.com"
                }
            }
        }
    ]
}

Requesting multiple additional entities

You can request multiple related entities in a single request using commas to separate multiple keywords

curl -X GET "https://api.resourcewatch.org/v1/layer?includes=user,vocabulary"

Getting a layer by id or slug

Getting a layer by id:

curl -X GET "https://api.resourcewatch.org/v1/dataset/<dataset-id>/layer/<layer_id>"
curl -X GET "https://api.resourcewatch.org/v1/layer/<layer_id>"

Getting a layer by slug:

curl -X GET "https://api.resourcewatch.org/v1/dataset/<dataset-id>/layer/<layer_slug>"
curl -X GET "https://api.resourcewatch.org/v1/layer/<layer_slug>"

Example response:

{
   "data": {
       "id": "e5c3e7c5-19ae-4ca0-a461-71f1f67aa553",
       "type": "layer",
       "attributes": {
           "slug": "total-co2-emissions-by-year",
           "userId": "5858f37140621f11066fb2f7",
           "application": [
               "rw"
           ],
           "name": "Total CO2 emissions by year",
           "default": false,
           "dataset": "11de2bc1-368b-42ed-a207-aaff8ece752b",
           "env": "production",
           "provider": "cartodb",
           "iso": [],
           "description": null,
           "layerConfig": {
               "account": "rw",
               "body": {
                   "maxzoom": 18,
                   "minzoom": 3,
                   "layers": [
                       {
                           "type": "mapnik",
                           "options": {
                               "sql": "SELECT * cait_2_0_country_ghg_emissions_filtered",
                               "cartocss": "",
                               "cartocss_version": "2.3.0"
                           }
                       }
                   ]
               }
           },
           "legendConfig": {
               "marks": {
                   "type": "rect",
                   "from": {
                       "data": "table"
                   }
               }
           },
           "applicationConfig": {},
           "staticImageConfig": {}
       }
   },
   "meta": {
       "status": "saved",
       "published": true,
       "updatedAt": "2017-01-23T16:51:42.571Z",
       "createdAt": "2017-01-23T16:51:42.571Z"
   }
}

If you know the id or the slug of a layer, then you can access it directly. Both id and slug are case-sensitive.

Include entities associated with the layer

You can load related user and vocabulary data in the same request. See this section for more details.

Creating a layer

To create a layer, you need to provide at least the following details:

curl -X POST "https://api.resourcewatch.org/v1/dataset/<dataset-id>/layer" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <your-token>" \
-d  \
'{
    "application": [
      "rw"
    ],
    "name": "Water stress",
    "description": "water stress"
}'

Response:

{
    "data": {
        "id": "bd8a36df-2e52-4b2d-b7be-a48bdcd7c769",
        "type": "layer",
        "attributes": {
            "name": "Water stress",
            "slug": "Water-stress_7",
            "dataset": "7fa6ec77-5ab0-43f4-9a4c-a3d19bed1e90",
            "description": "water stress",
            "application": [
                "rw"
            ],
            "iso": [],
            "userId": "5dbadb06df2dc74d2ad054fb",
            "default": false,
            "protected": false,
            "published": true,
            "env": "production",
            "layerConfig": {},
            "legendConfig": {},
            "interactionConfig": {},
            "applicationConfig": {},
            "staticImageConfig": {},
            "createdAt": "2020-06-04T14:28:24.575Z",
            "updatedAt": "2020-06-04T14:28:24.575Z"
        }
    }
}

In this section we'll guide you through the process of creating a layer in the RW API. Layer creation is available to all registered API users, and will allow you to store your own layer visualisation settings on the API, for reusing and sharing.

Before creating a layer, there are a few things you must know and do:

Creating a layer is done using a POST request and passing the relevant data as body fields. The supported body fields are as defined on the layer reference section, but the minimum field list you must specify for all layers is:

There's also a dependency on a dataset id, as it is required to build the POST URL. As noted on the layer concept documentation, a layer is meant to hold the rendering details of a layer, but not the actual data - that should be part of the dataset. While this is not enforced - it's up to your rendering tool to load the data, and it can do it from a RW API dataset or from anywhere else - it's common and best practice to have the data for a layer be sourced from the dataset that's associated with it.

When a layer is created, a vocabulary tag for it is automatically created, associated with the dataset tag.

The layer service was built to be very flexible, and not be restricted to specific layer rendering libraries or tools. This gives you the freedom to use virtually any rendering technology you want, but it also means you'll have to make additional decisions on how to structure your data into the different open format fields provided by a RW API layer. In a future release of these docs, we'll show you some examples of how existing applications use different rendering tools with the layer endpoints, to give you an idea on how you can structure your own data, and also as a way to help you get started creating your first layers for your own custom applications. Until then, the tutorials section of the documentation shows an example of how existing raster tile layers may be structured and how the information in the layer response can be utilized by a third-party visualization library.

Errors for creating a layer

Error code Error message Description
400 <field>: <field> can not be empty Your are missing a required field value.
400 - <field>: must be a <restriction> The value provided for the mentioned field does not match the requirements.
401 Unauthorized You are not authenticated.
403 Forbidden You are trying to create a layer with one or more application values that are not associated with your user account.
404 Dataset not found The provided dataset id does not exist.
404 Error: StatusCodeError: 404 - {\"errors\":[{\"status\":404,\"detail\":\"Dataset not found\"}]} The provided dataset exists but is not present on the graph.

Updating a layer

Example PATCH request that updates a layer's name:

curl -X PATCH "https://api.resourcewatch.org/v1/dataset/<dataset-id>/layer/<layer_id>" \
-H "Authorization: Bearer <your-token>" \
-H "Content-Type: application/json" -d \
'{
  "name":"foo"
}'

The update layer endpoint allows you to modify the details of an existing layer. As noted on the layer concept documentation, the layer object stores the details of how layer is meant to be rendered, but does not contain the actual data. As such, if you are looking to update the data that's being displayed on your map, this is probably not the endpoint you're looking for - you may want to update your dataset instead. Use this endpoint if you want to modify things like legend details, color schemes, etc - this will depend on your rendering implementation.

Unless specified otherwise in their description, all the fields present in the layer reference section can be updated using this endpoint. When passing new values for Object type fields, the new value will fully overwrite the previous one. It’s up to you, as an API user, to build any merging logic into your application.

To perform this operation, the following conditions must be met:

Errors for updating a layer

Error code Error message Description
400 - <field>: must be a <restriction> The value provided for the mentioned field does not match the requirements.
401 Unauthorized You need to be logged in to be able to update a layer.
403 Forbidden You need to either have the ADMIN role, or have role MANAGER and be the layer's owner (through the userId field of the layer).
403 Forbidden You are trying to update a layer with one or more application values that are not associated with your user account.
404 Layer with id doesn't exist A layer with the provided id does not exist.
404 Dataset not found A dataset with the provided id does not exist.

Deleting a layer

Example DELETE request that deletes a layer:

curl -X DELETE "https://api.resourcewatch.org/v1/dataset/<dataset-id>/layer/<layer_id>" \
-H "Authorization: Bearer <your-token>" \
-H "Content-Type: application/json"

Response:

{
    "data": {
        "id": "bd8a36df-2e52-4b2d-b7be-a48bdcd7c769",
        "type": "layer",
        "attributes": {
            "name": "Water stress",
            "slug": "Water-stress_7",
            "dataset": "7fa6ec77-5ab0-43f4-9a4c-a3d19bed1e90",
            "description": "water stress",
            "application": [
                "rw"
            ],
            "iso": [],
            "userId": "5dbadb06df2dc74d2ad054fb",
            "default": false,
            "protected": false,
            "published": true,
            "env": "production",
            "layerConfig": {},
            "legendConfig": {},
            "interactionConfig": {},
            "applicationConfig": {},
            "staticImageConfig": {},
            "createdAt": "2020-06-04T14:28:24.575Z",
            "updatedAt": "2020-06-04T14:28:24.575Z"
        }
    }
}

Use this endpoint if you'd like to delete a layer from the RW API. As a layer object does not store the actual data being displayed, this will only delete the layer settings, but the actual data will continue to be available at its source.

Besides deleting the layer itself, this endpoint also deletes graph vocabularies and metadata related to the layer itself. These delete operations are issued after the layer itself is deleted. The process is not atomic, and the output of the API request is based solely on the result of the deletion of the layer itself. For example, is the metadata service is temporarily unavailable when you issue your delete layer request, the layer itself will be deleted, but the associated metadata will continue to exist. The response will not reflect the failure to delete metadata in any way.

In order to delete a layer, the following conditions must be met:

Errors for deleting a layer

Error code Error message Description
400 Layer is protected You are attempting to delete a layer that has protected set to prevent deletion.
401 Unauthorized You need to be logged in to be able to delete a layer.
403 Forbidden You need to either have the ADMIN role, or have role MANAGER and be the layer's owner (through the userId field of the layer)
404 Dataset not found A dataset with the provided id does not exist.
404 Layer with id doesn't exist A layer with the provided id does not exist.

Layer reference

This section gives you a complete view at the properties that are maintained as part of layer. When interacting with a layer (on get, on create, etc) you will find most of these properties available to you, although they may be organized in a slightly different structure (ie: on get, everything but the id is nested inside an attributes object).

You can find more details in the source code.

Field name Type Required Default value Description
id String Yes (autogenerated) Unique Id of the layer. Auto generated on creation. Cannot be modified by users.
name String Yes Name of the layer.
dataset String Yes Id of the dataset to which the layer corresponds. Set on layer creation, cannot be modified.
slug String Yes (autogenerated) Slug of the layer. Auto generated on creation. Cannot be modified by users.
description String No User defined description of the layer.
application Array Yes Applications associated with this layer. Read more about this field here.
iso Array No List of ISO3 codes of the countries that relate to the layer. If empty (or contains a single element: 'global') then the layer is a global layer.
provider String No Layer provider. It typically identifies the source service for the data displayed in the layer.
type String No Layer type.
userId String Yes (autopopulated) Id of the user who created the layer. Set automatically on creation. Cannot be modified by users.
default Boolean No false If the layer should be used as the dataset's default layer.
protected Boolean Yes false If the layer is protected. A protected layer cannot be deleted.
published Boolean Yes true If the layer is published or not.
env String Yes production Environment to which the layer belongs. Read more about this field in the Environments concept section.
applicationConfig Object No Schema-less object meant to host application-specific data or behavior configuration.
layerConfig Object No Schema-less object meant to define layer specific data, like source of data, styling and animation settings.
legendConfig Object No Schema-less object meant to define how a layer legend should be represented visually.
staticImageConfig Object No
interactionConfig Object No Schema-less object meant to define interactive layer element behavior, ie.: how tooltips behave on click.
userName String No (autogenerated) null Name of the user who created the layer. This value is used only internally, and is never directly exposed through the API. Cannot be modified by users.
userRole String No (autogenerated) null Role of the user who created the layer. This value is used only internally, and is never directly exposed through the API. Cannot be modified by users.
createdAt Date No (autogenerated) Automatically maintained date of when the layer was created. Cannot be modified by users.
updatedAt Date No (autogenerated) Automatically maintained date of when the layer was last updated. Cannot be modified by users.

Contextual layers

What is a contextual layer

Contextual layers are a simpler version of RW API layers, focused on supporting raster or vector layers that can be intersected with map coordinates. Unlike RW API layers, contextual layers support out-of-the-box downloading layer tiles from a remote tile URL pattern set in the contextual layer itself.

Also, another significant difference between layers and contextual layers is that layers, despite being owned by users, cannot be private - if you create layers, any other RW API user will be able to see them when they get all layers. Contextual layers are, by default, private. However, you can also set your contextual layers to be publicly accessible by other users, if you choose to do so.

Another thing you should keep in mind is that, aside from being owned by users, contextual layers can be owned by teams - a separate RW API entity that groups users, assigning some of them a manager profile (not to be confused with the MANAGER user role). If owned by a team, the contextual layer can be fetched or edited by any of the team members, not only by the creator of the contextual layer. Additionally, the contextual layer can also be deleted by a team manager aside from the owner of the contextual layer. Unfortunately, documentation for team endpoints is not up-to-date, so it can be hard to understand how you can interact with teams or use them to create contextual layers. However, for the time being, just keep in mind that contextual layers can be owned by teams, not only by users.

Contextual layers are mostly used by the Forest Watcher mobile application, so for more information about contextual layer use cases, please check out the FW app or reach out to a member of the FW team.

Getting contextual layers

Getting the list of contextual layers:

curl -X GET "https://api.resourcewatch.org/v1/contextual-layer" \
-H "Authorization: Bearer <your-token>"

Example response:

{
    "data": [
        {
            "type": "contextual-layers",
            "id": "59a979235f17780012d7dfcf",
            "attributes": {
                "isPublic": true,
                "name": "layers.treeCoverLoss2015",
                "url": "https://production-api.globalforestwatch.org/contextual-layer/loss-layer/2015/2016/{z}/{x}/{y}.png",
                "enabled": true,
                "owner": {
                    "type": "USER"
                },
                "createdAt": "2017-09-01T15:13:39.502Z"
            }
        }
    ]
}

This endpoint allows you to list contextual layers and their properties. If successful, the returned response will include a list of contextual layers in the data index of the response body, including contextual layers that match one of the following conditions:

Keep in mind this endpoint is restricted to authenticated users, so always remember to provide your authentication token when calling this endpoint. The result is not paginated, so you will get all layers that match at least one of the conditions defined above.

Filters

Return only contextual layers with the enabled attribute equal to true:

curl -X GET "https://api.resourcewatch.org/v1/contextual-layer?enabled=true" \
-H "Authorization: Bearer <your-token>"

The contextual layer list endpoint allows you to filter by the enabled attribute, to retrieve only enabled or disabled layers.

Sorting

Sorting is currently not supported for contextual layers.

Errors for getting contextual layers

Error code Error message Description
401 Unauthorized You haven't provided your authentication token.
500 Error while retrieving user team An internal error occurred while fetching the request user's team.

Creating a contextual layer for a user

To create a contextual layer for a user, you need to provide at least the following fields:

curl -X POST "https://api.resourcewatch.org/v1/contextual-layer" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <your-token>" \
-d  \
'{
    "name": "Test",
    "url": "https://example.com/contextual-layer/{z}/{x}/{y}.png"
}'

Example successful response for creating a contextual layer:

{
    "data": {
        "type": "contextual-layers",
        "id": "5fe9fe6bdc8bd5001bbcb9d0",
        "attributes": {
            "isPublic": false,
            "name": "Test",
            "url": "https://example.com/contextual-layer/{z}/{x}/{y}.png",
            "enabled": false,
            "owner": {
                "type": "USER"
            },
            "createdAt": "2020-12-28T15:48:59.812Z"
        }
    }
}

RW API contextual layers can be associated with either a user or a team. This section details the information you need to provide to create a contextual layer associated with a user. This endpoint is available to all registered API users.

You can create a contextual layer by calling a POST request, passing the relevant data as body fields. The supported body fields are defined in the contextual layer reference section, but the required fields you must provide are name and url.

Errors for creating a contextual layer for a user

Error code Error message Description
400 Bad Request The structure of the JSON request payload is not valid.
401 Unauthorized You haven't provided your authentication token.
500 Layer creation Failed. The creation of the contextual layer failed, check if you are sending all the required fields.

Creating a contextual layer for a team

To create a contextual layer for a team, you need to provide at least the following fields:

curl -X POST "https://api.resourcewatch.org/v1/contextual-layer/team/:teamId" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <your-token>" \
-d  \
'{
    "name": "Test",
    "url": "https://example.com/contextual-layer/{z}/{x}/{y}.png"
}'

Example successful response for creating a contextual layer:

{
    "data": {
        "type": "contextual-layers",
        "id": "5fe9fe6bdc8bd5001bbcb9d0",
        "attributes": {
            "isPublic": false,
            "name": "Test",
            "url": "https://example.com/contextual-layer/{z}/{x}/{y}.png",
            "enabled": false,
            "owner": {
                "type": "USER"
            },
            "createdAt": "2020-12-28T15:48:59.812Z"
        }
    }
}

RW API contextual layers can be associated with either a user or a team. This section details the information you need to provide to create a contextual layer associated with a team. This endpoint is available to all registered API users.

You can create a contextual layer by calling a POST request, passing the relevant data as body fields. The supported body fields are defined on the contextual layer reference section, but the required fields you must provide are name and url.

Errors for creating a contextual layer for a team

Error code Error message Description
400 Bad Request The structure of the JSON request payload is not valid.
401 Unauthorized You haven't provided your authentication token.
500 Layer creation Failed. The creation of the contextual layer failed, check if you are sending all the required fields.
500 Team retrieval Failed. An error occurred while fetching the information about the team with id provided, check you are providing a valid team id.

Updating a contextual layer

Example PATCH request to update a contextual layer:

curl -X PATCH "https://api.resourcewatch.org/v1/contextual-layer/:layerId" \
-H "Authorization: Bearer <your-token>" \
-H "Content-Type: application/json" -d \
'{
    "name": "Test 2",
    "url": "https://example.com/contextual-layer/{z}/{x}/{y}.png"
}'

Example successful response for updating a contextual layer:

{
    "data": {
        "type": "contextual-layers",
        "id": "5fe9fe6bdc8bd5001bbcb9d0",
        "attributes": {
            "isPublic": false,
            "name": "Test 2",
            "url": "https://example.com/contextual-layer/{z}/{x}/{y}.png",
            "enabled": false,
            "owner": {
                "type": "USER"
            },
            "createdAt": "2020-12-28T15:48:59.812Z"
        }
    }
}

To update the details of an existing contextual layer (either created for a user or a team), you should issue a PATCH request. This endpoint is available to all registered API users.

Keep in mind that, as in the case of creating a contextual layer, you must provide at least name and url in all update contextual layer requests. Remember that you can check the contextual layer reference section for the list of fields available.

Updating contextual layers also has some caveats:

Errors for updating a layer

Error code Error message Description
404 Layer not found No contextual layer was found for the provided id.
500 Layer retrieval failed. An error occurred while fetching the layer information from the database.
500 Team retrieval Failed. An error occurred while fetching the information about the team with id provided.
500 Layer update failed. An error occurred while saving the updated information of the contextual layer.

Deleting a contextual layer

Example DELETE request to delete a contextual layer:

curl -X DELETE "https://api.resourcewatch.org/v1/contextual-layer/:layerId" \
-H "Authorization: Bearer <your-token>" \
-H "Content-Type: application/json"

Use this endpoint if you'd like to delete a contextual layer from the RW API. In order to delete a contextual layer, you must either be an ADMIN user or, alternatively, meet all of the following conditions:

If successful, the request to delete a contextual layer returns a 204 No Content response.

Errors for deleting a layer

Error code Error message Description
404 Layer not found No contextual layer was found for the provided id.
500 Layer retrieval failed. An error occurred while fetching the layer information from the database.
500 Team retrieval Failed. An error occurred while fetching the information about the team with id provided.
500 Layer update failed. An error occurred while saving the updated information of the contextual layer.

Getting loss layer tiles

Example request to fetch loss layer tiles:

curl -X GET "https://api.resourcewatch.org/v1/contextual-layer/loss-layer/:startYear/:endYear/:z/:x/:y.png"

This endpoint can be used as a shortcut to obtain PNG tiles, instead of retrieving the contextual layer's url field and manually interpolating coordinates. The base URL of the service containing the PNG tiles for the layers referred by this endpoint can be configured changing the hansenUrl configuration value in the Contextual Layers service.

Use this endpoint to retrieve PNG image corresponding to the loss layer tiles for the (x,y,z) tuple (where x represents latitude, y longitude, and z the zoom level) for loss layers for the interval of years from startYear to endYear.

If successful, this endpoint returns a PNG file of the loss layer tile.

Errors for getting loss layer tiles

Error code Error message Description
404 Tile not found No tile was found for the parameters provided.

Contextual layer reference

This section gives you a complete view of the properties that are maintained as part of a contextual layer. When interacting with a contextual layer (on get, on create, etc) you will find most of these properties available to you, although they may be organized in a slightly different structure (ie: on get, everything but the id is nested inside an attributes object).

You can find more details in the source code.

Field name Type Required Default value Description
id String Yes (autogenerated) Unique Id of the contextual layer. Auto-generated on creation. Cannot be modified by users.
name String Yes Name of the contextual layer.
description String No Description of the contextual layer.
url String Yes URL to fetch tiles for the contextual layer.
isPublic Boolean No false If the contextual layer is publicly accessible.
enabled Boolean No false If the contextual layer is enabled.
owner Object No Object containing information about the owner of the contextual layer.
owner.type String Yes (auto-filled according to the endpoint used to create the contextual layer) Type of the owner of the layer - can be USER or TEAM.
owner.id String Yes (auto-filled according to the endpoint used to create the contextual layer) Id of the user or team (according to the value of the owner.type attribute) owner of the contextual layer.
createdAt Date No (autogenerated) Automatically maintained date of when the contextual layer was created. Cannot be modified by users.

Widget

What is a widget?

In a nutshell, a RW API widget is a toolset to help you render your data in a visually more appealing way. The widget concept documentation will give you a more detailed description of this, and we encourage you to read it before proceeding. We also recommend you take a look at our section about Vega if you plan on reusing existing widgets or upload widgets that are reusable by other users. The RW API does not require you to use Vega, but we highly recommend that you do, as it's the technology used by many of the widgets you'll find on the RW API.

Getting all widgets

Getting a list of widgets

curl -X GET "https://api.resourcewatch.org/v1/widget"

Example response:

{
   "data":[
      {
         "id": "51851e22-1eda-4bf5-bbcc-cde3f9a3a943",
         "type": "widget",
         "attributes": {
             "name": "Example Widget",
             "dataset": "be76f130-ed4e-4972-827d-aef8e0dc6b18",
             "slug": "example-widget",
             "userId": "5820ad9469a0287982f4cd18",
             "description": "",
             "source": null,
             "sourceUrl": null,
             "authors": null,
             "application": [
                 "rw"
             ],
             "verified": false,
             "default": false,
             "protected": false,
             "defaultEditableWidget": false,
             "published": true,
             "freeze": false,
             "env": "production",
             "queryUrl": null,
             "widgetConfig": "{}",
             "template": false,
             "layerId": null,
             "createdAt": "2017-02-08T15:30:34.505Z",
             "updatedAt": "2017-02-08T15:30:34.505Z"
         }
      },
      {...}
   ],
   "links":{
      "first":"https://api.resourcewatch.org/v1/widget?page%5Bnumber%5D=1",
      "prev":"https://api.resourcewatch.org/v1/widget?page%5Bnumber%5D=1",
      "next":"https://api.resourcewatch.org/v1/widget?page%5Bnumber%5D=2&page%5Bsize%5D=10",
      "last":"https://api.resourcewatch.org/v1/widget?page%5Bnumber%5D=64&page%5Bsize%5D=10",
      "self":"https://api.resourcewatch.org/v1/widget?page%5Bnumber%5D=1&page%5Bsize%5D=10"
   },
   "meta": {
      "total-pages": 38,
      "total-items": 372,
      "size": 10
   }
}

This endpoint allows you to list existing widgets and their properties. The result is a paginated list of 10 widgets, followed by metadata on total number of widgets and pages, as well as useful pagination links. By default, only widgets with env value production are displayed. In the sections below, we’ll explore how you can customize this endpoint call to match your needs.

Getting all widgets for a dataset

Return the widgets associated with a dataset

curl -X GET "https://api.resourcewatch.org/v1/dataset/<dataset-id>/widget"

Example response:

{
    "data": [
        {
            "id": "73f00267-fe34-42aa-a611-13b102f38d75",
            "type": "widget",
            "attributes": {
                "name": "Precipitation Change in Puget Sound",
                "dataset": "06c44f9a-aae7-401e-874c-de13b7764959",
                "slug": "precipitation-change",
                "userId": "58333dcfd9f39b189ca44c75",
                "description": "NOAA nCLIMDIV Precipitation: Historical Precipitation",
                "source": null,
                "sourceUrl": null,
                "authors": null,
                "application": [
                    "prep"
                ],
                "verified": false,
                "default": true,
                "protected": false,
                "defaultEditableWidget": false,
                "published": true,
                "freeze": false,
                "env": "production",
                "queryUrl": "query/06c44f9a-aae7-401e-874c-de13b7764959?sql=select annual as x, year as y from index_06c44f9aaae7401e874cde13b7764959%20order%20by%20year%20asc",
                "widgetConfig": {...},
                "template": false,
                "layerId": null,
                "createdAt": "2016-08-03T16:17:06.863Z",
                "updatedAt": "2017-03-21T16:07:57.631Z"
            }
        },
        {...}
    ],
    "links": {
        "self": "http://api.resourcewatch.org/v1/dataset/06c44f9a-aae7-401e-874c-de13b7764959/widget?page[number]=1&page[size]=10",
        "first": "http://api.resourcewatch.org/v1/dataset/06c44f9a-aae7-401e-874c-de13b7764959/widget?page[number]=1&page[size]=10",
        "last": "http://api.resourcewatch.org/v1/dataset/06c44f9a-aae7-401e-874c-de13b7764959/widget?page[number]=2&page[size]=10",
        "prev": "http://api.resourcewatch.org/v1/dataset/06c44f9a-aae7-401e-874c-de13b7764959/widget?page[number]=1&page[size]=10",
        "next": "http://api.resourcewatch.org/v1/dataset/06c44f9a-aae7-401e-874c-de13b7764959/widget?page[number]=2&page[size]=10"
    },
    "meta": {
        "total-pages": 2,
        "total-items": 18,
        "size": 10
    }
}

When handling widgets, it's common to want to limit results to those widgets associated with a given dataset. Besides the filters covered below, there's an additional convenience endpoint to get the widgets associated with a dataset, as shown in this example.

Getting all widgets for multiple datasets

Return all widgets associated with two datasets

curl -X POST "https://api.resourcewatch.org/widget/find-by-ids" \
-H "Authorization: Bearer <your-token>" \
-H 'Content-Type: application/json' \
-d '{
    "ids": ["<dataset 1 id>", "<dataset 2 id>"]
}'

Example response:

{
    "data": [
        {
            "id": "73f00267-fe34-42aa-a611-13b102f38d75",
            "type": "widget",
            "attributes": {
                "name": "Precipitation Change in Puget Sound",
                "dataset": "06c44f9a-aae7-401e-874c-de13b7764959",
                "slug": "precipitation-change",
                "userId": "58333dcfd9f39b189ca44c75",
                "description": "NOAA nCLIMDIV Precipitation: Historical Precipitation",
                "source": null,
                "sourceUrl": null,
                "authors": null,
                "application": [
                    "prep"
                ],
                "verified": false,
                "default": true,
                "protected": false,
                "defaultEditableWidget": false,
                "published": true,
                "freeze": false,
                "env": "production",
                "queryUrl": "query/06c44f9a-aae7-401e-874c-de13b7764959?sql=select annual as x, year as y from index_06c44f9aaae7401e874cde13b7764959%20order%20by%20year%20asc",
                "widgetConfig": {...}
            }
        },
        {...}
    ]
}

This endpoint allows users to load all widgets belonging to multiple datasets in a single request.

Return all widgets associated with two datasets, that are associated with either rw or prep applications

curl -X POST "https://api.resourcewatch.org/widget/find-by-ids" \
-H "Authorization: Bearer <your-token>" \
-H 'Content-Type: application/json' \
-d '{
    "ids": ["<dataset 1 id>", "<dataset 2 id>"],
    "app": "rw,prep"
}'

Return all widgets associated with two datasets, that are associated with both rw and prep applications simultaneously

curl -X POST "https://api.resourcewatch.org/widget/find-by-ids" \
-H "Authorization: Bearer <your-token>" \
-H 'Content-Type: application/json' \
-d '{
    "ids": ["<dataset 1 id>", "<dataset 2 id>"],
    "app": "rw@prep"
}'

Besides the required ids array, your request body may optionally include a app string value if you'd like to filter the returned widgets by their application:

Please note that, unlike getting all widgets or getting all widgets for a dataset, this endpoint does not come with paginated results, nor does it support pagination, filtering or sorting or including related entities described in their respective sections.

Pagination

Example request to load page 2 using 25 results per page

curl -X GET "https://api.resourcewatch.org/v1/widget?page[number]=2&page[size]=25"

The Widgets service adheres to the conventions defined in the Pagination guidelines for the RW API, so we recommend reading that section for more details on how paginate your widgets list.

Filters

Return the widgets filtered by those whose name contains emissions

curl -X GET "https://api.resourcewatch.org/v1/widget?name=emissions"

Return the widgets filtered by dataset

curl -X GET "https://api.resourcewatch.org/v1/widget?dataset=11de2bc1-368b-42ed-a207-aaff8ece752b"
curl -X GET "https://api.resourcewatch.org/v1/dataset/11de2bc1-368b-42ed-a207-aaff8ece752b/widget"

Filter widgets by default value

curl -X GET "https://api.resourcewatch.org/v1/widget?default=false"

Filter widgets by environment

curl -X GET "https://api.resourcewatch.org/v1/widget?env=staging"

Return the widgets filtered by those whose applications contain both rw and prep applications simultaneously

curl -X GET "https://api.resourcewatch.org/v1/widget?app=rw@prep"

The widget list endpoint provides a wide range of filters that you can use to tailor your widget listing. Filtering widgets adheres to the conventions defined in the Filter guidelines for the RW API, so we strongly recommend reading that section before proceeding. In addition to these conventions, you'll be able to use the great majority of the widget fields you'll find on the widget reference, with the following exceptions:

Additionally, you can use the following filters:

Sorting

Sorting widgets

curl -X GET "https://api.resourcewatch.org/v1/widget?sort=name"

Sorting widgets by multiple criteria

curl -X GET "https://api.resourcewatch.org/v1/widget?sort=name,slug"

Explicit order of sorting

curl -X GET "https://api.resourcewatch.org/v1/widget?sort=-name,+slug"

Sorting widgets by the role of the user who owns the widget

curl -X GET "https://api.resourcewatch.org/v1/widget?sort=user.role"

The Widget service currently supports sorting using the sort query parameter. Sorting widgets adheres to the conventions defined in the Sorting guidelines for the RW API, so we strongly recommend reading that section before proceeding. Additionally, you can check out the Widget reference section for a detailed description of the fields you can use when sorting. In addition to all widget model fields, you can sort the returned results by the name (using user.name) or role (using user.role) of the user owner of the widget. Keep in mind that sorting by user data is restricted to ADMIN users.

Include entities associated with the widgets

When loading widget data, you can optionally pass an includes query argument to load additional data.

Vocabulary

Loads related vocabularies. If none are found, an empty array is returned.

curl -X GET "https://api.resourcewatch.org/v1/widget?includes=vocabulary"

Example response:

{
    "data": [
        {
            "id": "51851e22-1eda-4bf5-bbcc-cde3f9a3a943",
            "type": "widget",
            "attributes": {
                "name": "Example widget",
                "dataset": "be76f130-ed4e-4972-827d-aef8e0dc6b18",
                "slug": "example-widget",
                "userId": "5820ad9469a0287982f4cd18",
                "description": null,
                "source": null,
                "sourceUrl": null,
                "authors": null,
                "application": [
                    "rw"
                ],
                "verified": false,
                "default": false,
                "protected": false,
                "defaultEditableWidget": false,
                "published": true,
                "freeze": false,
                "env": "production",
                "queryUrl": null,
                "widgetConfig": "{}",
                "template": false,
                "layerId": null,
                "createdAt": "2017-02-08T15:30:34.505Z",
                "updatedAt": "2017-02-08T15:30:34.505Z",
                "vocabulary": [
                    {
                        "id": "resourcewatch",
                        "type": "vocabulary",
                        "attributes": {
                            "tags": [
                                "inuncoast",
                                "rp0002",
                                "historical",
                                "nosub"
                            ],
                            "name": "resourcewatch",
                            "application": "rw"
                        }
                    }
                ]
            }
        }
    ]
}

User

curl -X GET "https://api.resourcewatch.org/v1/widget?includes=user"

Example response:

{
    "data": [{
        "id": "51851e22-1eda-4bf5-bbcc-cde3f9a3a943",
        "type": "widget",
        "attributes": {
            "name": "Example widget",
            "dataset": "be76f130-ed4e-4972-827d-aef8e0dc6b18",
            "slug": "example-widget",
            "userId": "5820ad9469a0287982f4cd18",
            "description": "",
            "source": null,
            "sourceUrl": null,
            "authors": null,
            "application": [
                "rw"
            ],
            "verified": false,
            "default": false,
            "protected": false,
            "defaultEditableWidget": false,
            "published": true,
            "freeze": false,
            "env": "production",
            "queryUrl": null,
            "widgetConfig": "{}",
            "template": false,
            "layerId": null,
            "createdAt": "2017-02-08T15:30:34.505Z",
            "updatedAt": "2017-02-08T15:30:34.505Z",
            "user": {
              "name": "John Sample",
              "email": "john.sample@vizzuality.com"
            }
        }
    }]
}

Loads the name and email address of the author of the widget. If the user issuing the request has role ADMIN, the response will also display the role of the widget's author. If the data is not available (for example, the user has since been deleted), no user property will be added to the widget object.

Metadata

curl -X GET "https://api.resourcewatch.org/v1/widget?includes=metadata"

Example response:

{
    "data": [
        {
            "id": "51851e22-1eda-4bf5-bbcc-cde3f9a3a943",
            "type": "widget",
            "attributes": {
                "name": "Example widget",
                "dataset": "be76f130-ed4e-4972-827d-aef8e0dc6b18",
                "slug": "example-widget",
                "userId": "5820ad9469a0287982f4cd18",
                "description": "",
                "source": null,
                "sourceUrl": null,
                "authors": null,
                "application": [
                    "rw"
                ],
                "verified": false,
                "default": false,
                "protected": false,
                "defaultEditableWidget": false,
                "published": true,
                "freeze": false,
                "env": "production",
                "queryUrl": null,
                "widgetConfig": "{}",
                "template": false,
                "layerId": null,
                "createdAt": "2017-02-08T15:30:34.505Z",
                "updatedAt": "2017-02-08T15:30:34.505Z",
                "metadata": [
                    {
                        "id": "5aeb1c74a096b50010f3843f",
                        "type": "metadata",
                        "attributes": {
                            "dataset": "86777822-d995-49cd-b9c3-d4ea4f82c0a3",
                            "application": "rw",
                            "resource": {
                                "id": "51851e22-1eda-4bf5-bbcc-cde3f9a3a943",
                                "type": "widget"
                            },
                            "language": "en",
                            "info": {
                                "caption": "t",
                                "widgetLinks": []
                            },
                            "createdAt": "2018-05-03T14:28:04.482Z",
                            "updatedAt": "2018-06-07T11:30:40.054Z",
                            "status": "published"
                        }
                    }
                ]
            }
        }
    ]
}

Loads the metadata available for the widget. If none are found, an empty array is returned.

Requesting multiple additional entities

curl -X GET "https://api.resourcewatch.org/v1/widget?includes=metadata,user,vocabulary"

You can request multiple related entities in a single request using commas to separate multiple keywords

Getting a widget by id

Getting a widget by id:

curl -X GET "https://api.resourcewatch.org/v1/widget/<widget_id>"
curl -X GET "https://api.resourcewatch.org/v1/dataset/<dataset-id>/widget/<widget_id>"

Example response:

{
    "data": {
        "id": "51851e22-1eda-4bf5-bbcc-cde3f9a3a943",
        "type": "widget",
        "attributes": {
            "name": "Example widget",
            "dataset": "be76f130-ed4e-4972-827d-aef8e0dc6b18",
            "slug": "example-widget",
            "userId": "5820ad9469a0287982f4cd18",
            "description": "",
            "source": null,
            "sourceUrl": null,
            "authors": null,
            "application": [
                "rw"
            ],
            "verified": false,
            "default": false,
            "protected": false,
            "defaultEditableWidget": false,
            "published": true,
            "freeze": false,
            "env": "production",
            "queryUrl": null,
            "widgetConfig": "{}",
            "template": false,
            "layerId": null,
            "createdAt": "2017-02-08T15:30:34.505Z",
            "updatedAt": "2017-02-08T15:30:34.505Z"
        }
    }
}

If you know the id of a widget, then you can access it directly. Ids are case-sensitive.

Overwrite the query url of a widget response

Getting a widget by id with a custom query url value:

curl -X GET "https://api.resourcewatch.org/v1/widget/<widget_id>?queryUrl=/v1/query?sql=Select%20*%20from%20data"

Example response:

{
    "data": {
        "id": "51851e22-1eda-4bf5-bbcc-cde3f9a3a943",
        "type": "widget",
        "attributes": {
            "name": "Example widget",
            "dataset": "be76f130-ed4e-4972-827d-aef8e0dc6b18",
            "slug": "example-widget",
            "userId": "5820ad9469a0287982f4cd18",
            "description": null,
            "source": null,
            "sourceUrl": null,
            "authors": null,
            "application": [
                "rw"
            ],
            "verified": false,
            "default": false,
            "protected": false,
            "defaultEditableWidget": false,
            "published": true,
            "freeze": false,
            "env": "production",
            "queryUrl": "/v1/query?sql=Select * from data",
            "widgetConfig": {
                "data": {
                    "url": "/v1/query?sql=Select * from data"
                }
            },
            "template": false,
            "layerId": null,
            "createdAt": "2017-02-08T15:30:34.505Z",
            "updatedAt": "2017-02-08T15:30:34.505Z"
        }
    }
}

When getting a single widget, you can optionally provide a queryUrl query parameter. If provided, this parameter will overwrite the following response values:

This overwrite will only happen if a previous value already existed for the respective field. Also, keep in mind that these changes will NOT be persisted to the database, and will only affect the current request's response.

Customize the query url of a widget response

Getting a widget by id with a custom query url parameters:

curl -X GET "https://api.resourcewatch.org/v1/widget/<widget_id>?geostore=ungeostore"

Example response:

{
    "data": {
        "id": "51851e22-1eda-4bf5-bbcc-cde3f9a3a943",
        "type": "widget",
        "attributes": {
            "name": "Example widget",
            "dataset": "be76f130-ed4e-4972-827d-aef8e0dc6b18",
            "slug": "example-widget",
            "userId": "5820ad9469a0287982f4cd18",
            "description": null,
            "source": null,
            "sourceUrl": null,
            "authors": null,
            "application": [
                "rw"
            ],
            "verified": false,
            "default": false,
            "protected": false,
            "defaultEditableWidget": false,
            "published": true,
            "freeze": false,
            "env": "production",
            "queryUrl": "<previous queryUrl value>?geostore=ungeostore",
            "widgetConfig": {
                "data": {
                    "url": "<previous widgetConfig.data.url value>?geostore=ungeostore"
                }
            },
            "template": false,
            "layerId": null,
            "createdAt": "2017-02-08T15:30:34.505Z",
            "updatedAt": "2017-02-08T15:30:34.505Z"
        }
    }
}

Getting a widget by id with a custom query url value parameters:

curl -X GET "https://api.resourcewatch.org/v1/widget/<widget_id>?queryUrl=/v1/query?sql=Select%20*%20from%20data&geostore=ungeostore"

Example response:

{
    "data": {
        "id": "51851e22-1eda-4bf5-bbcc-cde3f9a3a943",
        "type": "widget",
        "attributes": {
            "name": "Example widget",
            "dataset": "be76f130-ed4e-4972-827d-aef8e0dc6b18",
            "slug": "example-widget",
            "userId": "5820ad9469a0287982f4cd18",
            "description": null,
            "source": null,
            "sourceUrl": null,
            "authors": null,
            "application": [
                "rw"
            ],
            "verified": false,
            "default": false,
            "protected": false,
            "defaultEditableWidget": false,
            "published": true,
            "freeze": false,
            "env": "production",
            "queryUrl": "/v1/query?sql=Select * from data&geostore=ungeostore",
            "widgetConfig": {
                "data": {
                    "url": "/v1/query?sql=Select * from data&geostore=ungeostore"
                }
            },
            "template": false,
            "layerId": null,
            "createdAt": "2017-02-08T15:30:34.505Z",
            "updatedAt": "2017-02-08T15:30:34.505Z"
        }
    }
}

When getting a single widget, you can optionally provide additional custom query parameter. These parameters will be appended to the following response values:

The widget service assumes these values are URLs, and will append your custom query parameters as such:

This overwrite will only happen if a previous value already existed for the respective field. Also, keep in mind that these changes will NOT be persisted to the database, and will only affect the current request's response. You can combine these custom query parameters with an overwritten query url, as seen on the included example.

Include entities associated with the widget

You can load related user, vocabulary and metadata data in the same request. See this section for more details.

Creating a widget

To create a widget, you need to provide at least the following details:

curl -X POST "https://api.resourcewatch.org/v1/dataset/<dataset-id>/widget" \
-H "Authorization: Bearer <your-token>" \
-H "Content-Type: application/json"  -d \
 '{
    "application":[
      "gfw"
    ],
    "name":"Example Widget"
  }'


curl -X POST "https://api.resourcewatch.org/v1/widget" \
-H "Authorization: Bearer <your-token>" \
-H "Content-Type: application/json"  -d \
 '{
    "application":[
      "gfw"
    ],
    "name":"Example Widget",
    "dataset": "7fa6ec77-5ab0-43f4-9a4c-a3d19bed1e90"    
  }'

Response

{
    "data": {
        "id": "7946bca1-6c2a-4329-a127-558ef9551eba",
        "type": "widget",
        "attributes": {
            "name": "Example Widget",
            "dataset": "7fa6ec77-5ab0-43f4-9a4c-a3d19bed1e90",
            "slug": "Example-Widget_2",
            "userId": "5dbadb0adf2dc74d2ad05dfb",
            "application": [
                "gfw"
            ],
            "verified": false,
            "default": false,
            "protected": false,
            "defaultEditableWidget": false,
            "published": true,
            "freeze": false,
            "env": "production",
            "template": false,
            "createdAt": "2020-06-11T14:13:19.677Z",
            "updatedAt": "2020-06-11T14:13:19.677Z"
        }
    }
}

In this section we'll guide you through the process of creating a widget in the RW API. Widget creation is available to all registered API users, and will allow you to store your own widget visualisation settings on the API, for reusing and sharing.

Before creating a widget, there are a few things you must know and do:

Creating a widget is done using a POST request and passing the relevant data as body files. The supported body fields are as defined on the widget reference section, but the minimum field list you must specify for all widgets is:

The widget service was built to be very flexible, and not be restricted to specific widget rendering libraries or tools. While we recommend using Vega, it's up to you to decide which library to use, and how to save your custom data within a widget's widgetConfig field. While there is no hard limit on this, widgets that rely on excessively large widgetConfig objects have been known to cause issues, so we recommend being mindful of this.

Widget thumbnails

Preview of the thumbnail of a widget

curl -X GET "https://resourcewatch.org/embed/widget/<widget_id>"

When a widget is created or updated, the RW API will automatically try to generate a thumbnail preview of it. This is done using the renderer that's part of the Resource Watch website, and will only produce a thumbnail if your widget uses the same approach as the RW website for declaring its widgets. Searching for widgets belonging to the rw application will give you an idea of how this is achieved.

The thumbnail process is asynchronous, meaning it may take up to one minute for your newly created or updated widget to have a valid and/or up to date thumbnailUrl value. If the thumbnail generation process fails (for example, if you decide to use a different rendering tool and data structure), the thumbnail generation will fail silently, but will not affect the actual widget creation or update process.

Errors for creating a widget

Error code Error message Description
400 <field>: <field> can not be empty Your are missing a required field value.
400 - <field>: must be a <restriction> The value provided for the mentioned field does not match the requirements.
401 Unauthorized You are not authenticated.
403 Forbidden You are trying to create a widget with one or more application values that are not associated with your user account.
404 Dataset not found The provided dataset id does not exist.

Updating a widget

To update a widget, you have to do one of the following PATCH requests:

curl -X PATCH "https://api.resourcewatch.org/v1/dataset/<dataset-id>/widget/<widget_id_or_slug>" \
-H "Authorization: Bearer <your-token>" \
-H "Content-Type: application/json"  -d \
 '{
    "name":"New Example Widget Name"
 }'


curl -X PATCH "https://api.resourcewatch.org/v1/widget/<widget_id_or_slug>" \
-H "Authorization: Bearer <your-token>" \
-H "Content-Type: application/json"  -d \
 '{
    "name":"New Example Widget Name",
    "dataset":"<dataset-id>
 }'

Response

{
    "data": {
        "id": "7946bca1-6c2a-4329-a127-558ef9551eba",
        "type": "widget",
        "attributes": {
            "name": "New Example Widget Name",
            "dataset": "7fa6ec77-5ab0-43f4-9a4c-a3d19bed1e90",
            "slug": "Example-Widget_2",
            "userId": "5dbadb0adf2dc74d2ad05dfb",
            "application": [
                "gfw"
            ],
            "verified": false,
            "default": false,
            "protected": false,
            "defaultEditableWidget": false,
            "published": true,
            "freeze": false,
            "env": "production",
            "template": false,
            "createdAt": "2020-06-11T14:13:19.677Z",
            "updatedAt": "2020-06-11T14:13:19.677Z"
        }
    }
}

The update widget endpoint allows you to modify the details of an existing widget. As noted on the widget concept documentation, the widget object stores the details of how widget is meant to be rendered, but may not contain the actual data. As such, if you are looking to update the data that's being displayed on your widget, this is probably not the endpoint you're looking for - you may want to update your dataset instead. Use this endpoint if you want to modify things like legend details, color schemes, etc - this will depend on your rendering implementation.

Unless specified otherwise in their description, all the fields present in the widget reference section can be updated using this endpoint. When passing new values for Object type fields, like widgetConfig, the new value will fully overwrite the previous one. It’s up to you, as an API user, to build any merging logic into your application.

To perform this operation, the following conditions must be met:

Widget thumbnails

When a widget is updated, a new thumbnail is generated. Refer to this section for details on this process.

Errors for updating a widget

Error code Error message Description
400 - <field>: must be a <restriction> The value provided for the mentioned field does not match the requirements.
401 Unauthorized You need to be logged in to be able to update a widget.
403 Forbidden You need to either have the ADMIN role, or have role MANAGER or USER and be the widget's owner (through the userId field of the widget) and belong to all the applications associated with the widget.
403 Forbidden You are trying to update a widget with one or more application values that are not associated with your user account.
404 Widget with id doesn't exist A widget with the provided id does not exist.
404 Dataset not found A dataset with the provided id does not exist.

Cloning a widget

To clone a widget, you should use one of the following POST requests:

curl -X POST "https://api.resourcewatch.org/v1/widget/<widget_id_or_slug>/clone" \
-H "Authorization: Bearer <your-token>" \
-H "Content-Type: application/json"
curl -X POST "https://api.resourcewatch.org/v1/dataset/<dataset-id>/widget/<widget_id_or_slug>/clone" \
-H "Authorization: Bearer <your-token>" \
-H "Content-Type: application/json"

Response

{
    "data": {
        "id": "7946bca1-6c2a-4329-a127-558ef9551eba",
        "type": "widget",
        "attributes": {
            "name": "Example Widget",
            "dataset": "7fa6ec77-5ab0-43f4-9a4c-a3d19bed1e90",
            "slug": "Example-Widget_2",
            "userId": "5dbadb0adf2dc74d2ad05dfb",
            "application": [
                "gfw"
            ],
            "verified": false,
            "default": false,
            "protected": false,
            "defaultEditableWidget": false,
            "published": true,
            "freeze": false,
            "env": "production",
            "template": false,
            "createdAt": "2020-06-11T14:13:19.677Z",
            "updatedAt": "2020-06-11T14:13:19.677Z"
        }
    }
}

This endpoint allows you to duplicate an existing widget. The newly created widget is identical to the old one, except:

To perform this operation, the following conditions must be met:

Cloning a widget while optionally setting a new name or description:

curl -X POST "https://api.resourcewatch.org/v1/widget/<widget_id_or_slug>/clone" \
-H "Authorization: Bearer <your-token>" \
-H "Content-Type: application/json"  -d \
 '{
   "name": "name for the cloned widget",
   "description": "description of the cloned widget"
}'
curl -X POST "https://api.resourcewatch.org/v1/dataset/<dataset-id>/widget/<widget_id_or_slug>/clone" \
-H "Authorization: Bearer <your-token>" \
-H "Content-Type: application/json"  -d \
 '{
   "name": "name for the cloned widget",
   "description": "description of the cloned widget"
}'

Response

{
    "data": {
        "id": "7946bca1-6c2a-4329-a127-558ef9551eba",
        "type": "widget",
        "attributes": {
            "name": "name for the cloned widget",
            "description": "description of the cloned widget",
            "dataset": "7fa6ec77-5ab0-43f4-9a4c-a3d19bed1e90",
            "slug": "Example-Widget_2",
            "userId": "5dbadb0adf2dc74d2ad05dfb",
            "application": [
                "gfw"
            ],
            "verified": false,
            "default": false,
            "protected": false,
            "defaultEditableWidget": false,
            "published": true,
            "freeze": false,
            "env": "production",
            "template": false,
            "createdAt": "2020-06-11T14:13:19.677Z",
            "updatedAt": "2020-06-11T14:13:19.677Z"
        }
    }
}

Widget thumbnails

When a widget is cloned, a new thumbnail is generated. Refer to this section for details on this process.

Errors for cloning a widget

Error code Error message Description
401 Unauthorized You need to be logged in to be able to clone a widget.
403 Forbidden You need to either have the ADMIN or MANAGER role, or have role USER and be the widget's owner (through the userId field of the widget) and belong to all the applications associated with the widget.
404 Widget with id doesn't exist A widget with the provided id or slug does not exist.

Deleting a widget

Example DELETE request that deletes a widget:

curl -X DELETE "https://api.resourcewatch.org/v1/dataset/<dataset-id>/widget/<widget_id>" \
-H "Authorization: Bearer <your-token>" \
-H "Content-Type: application/json"


curl -X DELETE "https://api.resourcewatch.org/v1/widget/<widget_id>" \
-H "Authorization: Bearer <your-token>" \
-H "Content-Type: application/json"

Response

{
    "data": {
        "id": "7946bca1-6c2a-4329-a127-558ef9551eba",
        "type": "widget",
        "attributes": {
            "name": "name for the cloned widget",
            "description": "description of the cloned widget",
            "dataset": "7fa6ec77-5ab0-43f4-9a4c-a3d19bed1e90",
            "slug": "Example-Widget_2",
            "userId": "5dbadb0adf2dc74d2ad05dfb",
            "application": [
                "gfw"
            ],
            "verified": false,
            "default": false,
            "protected": false,
            "defaultEditableWidget": false,
            "published": true,
            "freeze": false,
            "env": "production",
            "template": false,
            "createdAt": "2020-06-11T14:13:19.677Z",
            "updatedAt": "2020-06-11T14:13:19.677Z"
        }
    }
}

Use this endpoint if you'd like to delete a widget from the RW API. As a widget object may not store the actual data being displayed, this may only delete the widget settings, but the actual data may continue to be available at its source.

Besides deleting the widget itself, this endpoint also deletes graph vocabularies and metadata related to the widget itself. These delete operations are issued after the widget itself is deleted. The process is not atomic, and the response is based solely on the result of the deletion of the widget itself, not related resources. For example, is the metadata service is temporarily unavailable when you issue your delete widget request, the widget itself will be deleted, but the associated metadata will continue to exist. The response will not reflect the failure to delete metadata in any way.

In order to delete a widget, the following conditions must be met:

Widget reference

This section gives you a complete view at the properties that are maintained as part of widget. When interacting with a widget (on get, on create, etc) you will find most of these properties available to you, although they may be organized in a slightly different structure (ie: on get, everything but the id is nested inside an attributes object).

You can find more details in the source code.

Field name Type Required Default value Description
id String Yes (autogenerated) Unique Id of the widget. Auto generated on creation. Cannot be modified by users.
dataset String Yes Id of the dataset to which the widget corresponds. Set on widget creation, cannot be modified.
name String Yes Name of the widget.
slug String Yes (autogenerated) Slug of the widget. Auto generated on creation. Cannot be modified by users.
userId String Yes (autopopulated) Id of the user who created the widget. Set automatically on creation. Cannot be modified by users.
description String No User defined description of the widget.
source String No Description of the source of the widget's data, as it's meant to be displayed to the end user.
sourceUrl String No URL of the source of the data, as it's meant to be displayed to the end user.
authors String No Author or authors of the data displayed on the widget, as it's meant to be displayed to the end user.
queryUrl String No URL of the RW API query or external URL containing the data displayed on the widget
thumbnailUrl String No URL of a example thumbnail of the rendered widget.
env String Yes production Environment to which the widget belongs. Read more about this field in the Environments concept section.
widgetConfig Object No Schema-less object meant to host widget behavior configuration.
application Array Yes Applications associated with this widget. Read more about this field here.
layerId String No Id of the layer to which the widget corresponds.
verified Boolean Yes false
default Boolean No false If the widget should be used as the dataset's default widget.
protected Boolean Yes false If the widget is protected. A protected widget cannot be deleted.
defaultEditableWidget Boolean Yes false Used by the RW frontend to determine if a widget is the default widget displayed on the Explore detail page for a given dataset.
template Boolean Yes false If true, this widget is not necessarily meant to be rendered as-is, but rather as a template for other widgets to be generated from.
published Boolean Yes true If the widget is published or not.
freeze Boolean Yes false If true, the widget is meant to represent data from a specific snapshot taken at a given moment in time, as opposed to using a potentially mutable dataset. This data capturing functionality must be implemented by consuming applications, as this value has no logic associated with it on the API side.
userName String No (autogenerated) null Name of the user who created the widget. This value is used only internally, and is never directly exposed through the API. Cannot be modified by users.
userRole String No (autogenerated) null Role of the user who created the widget. This value is used only internally, and is never directly exposed through the API. Cannot be modified by users.
createdAt Date No (autogenerated) Automatically maintained date of when the widget was created. Cannot be modified by users.
updatedAt Date No (autogenerated) Automatically maintained date of when the widget was last updated. Cannot be modified by users.

Collections

What is a collection?

A collection is a way of aggregating WRI API resources like datasets, layers and widgets. A collection can reference one or more resources of different types.

Collection endpoints require authentication, and the collections are associated with the owner who initially created the collection.

Creating a collection

To create an empty collection, you can do a POST with the following body:

curl -X POST https://api.resourcewatch.org/v1/collection \
-H "Authorization: Bearer <your-token>" \
-H "Content-Type: application/json"  -d \
 '{
    "name": "Collection name"
  }'

Example response:

{
  "data": [
    {
      "id": "5f56170c1fca55001ad51779",
      "type": "collection",
      "attributes": {
        "name": "Collection name",
        "ownerId": "5dd7b92abf56ca0011875ae2",
        "application": "rw",
        "resources": []
      }
    }
  ]
}

You can also add a resource in the body of the request when creating a new collection, with the following body:

curl -X POST https://api.resourcewatch.org/v1/collection \
-H "Authorization: Bearer <your-token>" \
-H "Content-Type: application/json"  -d \
 '{
    "name": "Collection name",
    "resources": [
      {
        "type": "dataset",
        "id": "06c44f9a-aae7-401e-874c-de13b7764959"
      }
    ]
  }'

Example response:

{
  "data": [
    {
      "id": "5f56170c1fca55001ad51779",
      "type": "collection",
      "attributes": {
        "name": "Collection name",
        "ownerId": "5dd7b92abf56ca0011875ae2",
        "application": "rw",
        "resources": [
          {
            "type": "dataset",
            "id": "06c44f9a-aae7-401e-874c-de13b7764959"
          }
        ]
      }
    }
  ]
}

To create a collection, you should send a POST request to the /v1/collection endpoint, providing an authentication token that identifies the user making the request. You also need to (or can) provide the following fields in the request body:

Field name Description Required Type
name Name of collection. Yes String
application The application this collection belongs to (defaults to 'rw'). Read more about this field here. No String
resources Array of resources in the collection. No Array of Objects

Updating a collection

To update a collection, you should perform a PATCH request including the collection ID in the url. Here's an example:

curl -X PATCH https://api.resourcewatch.org/v1/collection/:id \
-H "Authorization: Bearer <your-token>" \
-H "Content-Type: application/json"  -d \
 '{
    "name": "New name"
  }'

Example response:

{
  "data": [
    {
      "id": "5f56170c1fca55001ad51779",
      "type": "collection",
      "attributes": {
        "name": "New name",
        "ownerId": "5dd7b92abf56ca0011875ae2",
        "application": "rw",
        "resources": []
      }
    }
  ]
}

You can update the name of a collection, you can send a PATCH request to the /v1/collection/:id endpoint, providing an authentication token that identifies the user making the request.

Keep in mind that you will only be able to update collections that are owned by your user.

Adding a resource to an existing collection

To add a resource to a collection, you have to do a POST with the following body:

curl -X POST https://api.resourcewatch.org/v1/collection/:id/resource \
-H "Authorization: Bearer <your-token>" \
-H "Content-Type: application/json"  -d \
 '{
    "type": "dataset",
    "id": "06c44f9a-aae7-401e-874c-de13b7764959"
  }'

Example response:

{
  "data": [
    {
      "id": "5f56170c1fca55001ad51779",
      "type": "collection",
      "attributes": {
        "name": "New name",
        "ownerId": "5dd7b92abf56ca0011875ae2",
        "application": "rw",
        "resources": [
          {
            "type": "dataset",
            "id": "06c44f9a-aae7-401e-874c-de13b7764959"
          }
        ]
      }
    }
  ]
}

You can do a POST request to the /v1/collection/:id/resource to push a new resource to an existing collection. You also need to define the following fields in the request body:

Field Description Type
type Type of resource being added Text (dataset, layer, widget)
id Id of the resource Text

Getting collections for the request user

To get all collections of the logged user, you have to do a GET request:

curl -X GET https://api.resourcewatch.org/v1/collection \
-H "Authorization: Bearer <your-token>"

Example response:

{
  "data": [
    {
      "id": "5f56170c1fca55001ad51779",
      "type": "collection",
      "attributes": {
        "name": "Collection name",
        "ownerId": "5dd7b92abf56ca0011875ae2",
        "application": "rw",
        "resources": [{
            "type": "dataset",
            "id": "123456789"            
        }]
      }
    }
  ]
}

By making a GET request to the /v1/collection endpoint, you can obtain the collections of the logged user.

To get all collections of the logged user, including the associated resources:

curl -X GET https://api.resourcewatch.org/v1/collection \
-H "Authorization: Bearer <your-token>"

Example response:

{
  "data": [
    {
      "id": "5f56170c1fca55001ad51779",
      "type": "collection",
      "attributes": {
        "name": "Collection name",
        "ownerId": "5dd7b92abf56ca0011875ae2",
        "application": "rw",
        "resources": [{
            "type": "dataset",
            "id": "123456789",
            "attributes": {
                ...
            }
        }]
      }
    }
  ]
}

You can optionally add the include=true query parameter to load the associated resources.

Pagination

Example request to load page 2 using 25 results per page

curl -X GET https://api.resourcewatch.org/v1/collection?page[number]=2&page[size]=25 \
-H "Authorization: Bearer <your-token>"

The Collections service adheres to the conventions defined in the Pagination guidelines for the RW API, so we recommend reading that section for more details on how paginate your collections list.

In the specific case of the Collections service, the default value for the page[size] query parameter is 9999999, instead of 10. However (as recommended in the pagination guidelines), you should not rely on the default page size and always provide a value tailored to your needs.

Sorting

Sorting collections

curl -X GET "https://api.resourcewatch.org/v1/collection?sort=name" \
-H "Authorization: Bearer <your-token>"

Sorting collections by multiple criteria

curl -X GET "https://api.resourcewatch.org/v1/collection?sort=name,application" \
-H "Authorization: Bearer <your-token>"

Explicit order of sorting

curl -X GET "https://api.resourcewatch.org/v1/collection?sort=-name,+application" \
-H "Authorization: Bearer <your-token>"

The Collections service currently supports sorting using the sort query parameter. Sorting collections adheres to the conventions defined in the Sorting guidelines for the RW API, so we strongly recommend reading that section before proceeding. Additionally, you can check out the Collection reference section for a detailed description of the fields you can use when sorting.

Get a collection by id

To get the collection by id, you have to do a GET request:

curl -X GET https://api.resourcewatch.org/v1/collection/:id \
-H "Authorization: Bearer <your-token>"

Example response:

{
  "data": [
    {
      "id": "5f56170c1fca55001ad51779",
      "type": "collection",
      "attributes": {
        "name": "Collection name",
        "ownerId": "5dd7b92abf56ca0011875ae2",
        "application": "rw",
        "resources": []
      }
    }
  ]
}

This endpoint returns the collection with id of the param. If the collection belongs to other user or does not exist, the endpoint returns 400.

Delete a collection

To delete the collection by id, you have to do a DELETE request:

curl -X DELETE https://api.resourcewatch.org/v1/collection/:id \
-H "Authorization: Bearer <your-token>"

In case of success, the deleted collection is returned in the response body:

{
  "data": [
    {
      "id": "5f56170c1fca55001ad51779",
      "type": "collection",
      "attributes": {
        "name": "Collection name",
        "ownerId": "5dd7b92abf56ca0011875ae2",
        "application": "rw",
        "resources": []
      }
    }
  ]
}

This endpoint deletes the collection with id of the param. If the collection belongs to other user or does not exist, the endpoint returns 400.

Delete a collection resource

To delete the resource you have to do a DELETE request:

curl -X DELETE https://api.resourcewatch.org/v1/collection/:id/resource/:resourceType/:resourceId \
-H "Authorization: Bearer <your-token>"

In case of success, the updated collection is returned in the response body:

{
  "data": [
    {
      "id": "5f56170c1fca55001ad51779",
      "type": "collection",
      "attributes": {
        "name": "Collection name",
        "ownerId": "5dd7b92abf56ca0011875ae2",
        "application": "rw",
        "resources": []
      }
    }
  ]
}

Using this endpoint you can also delete a resource in a collection with the id, resource type and resource id of the param. If the collection belongs to other user or not exist, the endpoint returns 400.

Finding collections by ids

To find collections by ids, you have to do a POST request:

curl -X POST https://api.resourcewatch.org/v1/collection/find-by-ids \
-H "Content-Type: application/json"  -d \
 '{
    "ids": ["5f56170c1fca55001ad51779"],
    "userId": "5dd7b92abf56ca0011875ae2"
  }'

Example response:

{
  "data": [
    {
      "id": "5f56170c1fca55001ad51779",
      "type": "collection",
      "attributes": {
        "name": "Collection name",
        "ownerId": "5dd7b92abf56ca0011875ae2",
        "application": "rw",
        "resources": []
      }
    }
  ]
}

You can also filter the returned results by application:

curl -X POST https://api.resourcewatch.org/v1/collection/find-by-ids?application=gfw \
-H "Content-Type: application/json"  -d \
 '{
    "ids": ["5f56170c1fca55001ad51779"],
    "userId": "5dd7b92abf56ca0011875ae2"
  }'

Example response:

{
  "data": []
}

You can find collections providing an array of ids by making a POST request to the /v1/collection/find-by-ids endpoint. You must provide in the body of the request the ids of the collections you wish to fetch, as well as the id of the user (userId) who owns these collections.

You can filter the returned results by application by providing the application query parameter.

Finding collections by id does not require authentication.

Collection reference

Field name Description Type
name Name of collection. String
ownerId Id of the user owner of this collection. String
application The application this collection belongs to (defaults to 'rw'). Read more about this field here. String
resources Array of resources in the collection. Array of Objects
--- type The type of resource. String (dataset, layer, widget)
--- id The id of the resource. String

Jiminy

Example jiminy GET request providing the SQL as query param:

curl -X GET 'https://api.resourcewatch.org/v1/jiminy?sql=SELECT col_1, col_2 FROM <dataset.id> limit <number>' \
-H "Content-Type: application/json"

Example jiminy POST request providing the SQL in the request body:

curl -X POST 'https://api.resourcewatch.org/v1/jiminy' \
-H "Content-Type: application/json" \
-d '{
   "sql": "SELECT col_1, col_2 FROM <dataset.id> limit <number>"
  }'

Example with real data:

curl -X GET 'https://api.resourcewatch.org/v1/jiminy?sql=SELECT iso, name_0, name_1, type_1 FROM 098b33df-6871-4e53-a5ff-b56a7d989f9a limit 10' \
-H "Content-Type: application/json"

The jiminy endpoint of the RW API makes use of the Jiminy library in order to infer which type of charts can be obtained from a the execution of a SQL query on a given dataset. For a better understanding of this endpoint, it is recommended to read beforehand on how to query datasets.

To use this endpoint and infer the charts that you can build from a result set, you must provide a valid SQL query. This query should contain the name of the columns for which you want to infer the chart types - the usage of the wildcard selector (SELECT *) in the SQL query is not supported by this endpoint.

Note: You must set a limit value to the SQL query provided. If you do not set it and the dataset contains a lot of data, this endpoint will try to obtain all data at once, which can result in performance issues.

Likewise with query and download endpoints, you can either provide the SQL as query param in a GET request, or in the body of the request as a POST request - read more here. Using the GET request is the recommended approach, as it allows HTTP caching of your result - subsequent requests for the same jiminy endpoint call will see a great performance increase, even if they are made by a different application or client. Alternatively, you can also call the jiminy endpoint using a POST request. POST requests are not cached, so you will not benefit from these speed improvements. However, GET requests can sometimes hit URL length restrictions, should your SQL query string be too long. Using a POST request is the recommended solution for these cases.

Jiminy response body

Example of successful response:

{
    "data": {
        "general": [
            "bar",
            "pie",
            "scatter"
        ],
        "byColumns": {
            "iso": [
                "bar",
                "pie"
            ],
            "name_0": [
                "bar",
                "pie"
            ],
            "name_1": [
                "bar",
                "pie"
            ],
            "type_1": [
                "bar",
                "pie"
            ]
        },
        "byType": {
            "bar": {
                "general": [
                    "iso",
                    "name_0",
                    "name_1",
                    "type_1"
                ],
                "columns": {
                    "iso": [],
                    "name_0": [],
                    "name_1": [],
                    "type_1": []
                }
            },
            "line": {
                "general": [],
                "columns": {
                    "iso": [],
                    "name_0": [],
                    "name_1": [],
                    "type_1": []
                }
            },
            "pie": {
                "general": [
                    "iso",
                    "name_0",
                    "name_1",
                    "type_1"
                ],
                "columns": {
                    "iso": [],
                    "name_0": [],
                    "name_1": [],
                    "type_1": []
                }
            },
            "scatter": {
                "general": [
                    "iso",
                    "name_0",
                    "name_1",
                    "type_1"
                ],
                "columns": {
                    "iso": [
                        "name_0",
                        "name_1",
                        "type_1"
                    ],
                    "name_0": [
                        "iso",
                        "name_1",
                        "type_1"
                    ],
                    "name_1": [
                        "iso",
                        "name_0",
                        "type_1"
                    ],
                    "type_1": [
                        "iso",
                        "name_0",
                        "name_1"
                    ]
                }
            },
            "1d_scatter": {
                "general": [],
                "columns": {
                    "iso": [],
                    "name_0": [],
                    "name_1": [],
                    "type_1": []
                }
            },
            "1d_tick": {
                "general": [],
                "columns": {
                    "iso": [],
                    "name_0": [],
                    "name_1": [],
                    "type_1": []
                }
            }
        }
    }
}

For a successful response, the response body is a JSON object containing a single index data, which describes the type of charts that can be obtained from the query provided. The following fields are usually present in the data object:

Field Type Description Example
data.general Array An array of distinct charts that can be used to represent the data of the query. ["bar", "pie"]
data.byColumns Object An object where the keys are the columns provided in the SQL query. For each the, its value is an array with the names of the charts that might be used to represent the data from the column in the key. { "iso": ["bar", "pie"], "name_0": ["bar", "pie"] },
data.byType Object An object where the keys are all the charts supported by Jiminy. The values will contain the column names of the query execution that might be used to display the chart type in the key. If the chart type was not included in the data.general field of the response body, its content will likely be empty. { "bar": { "general": ["iso", "name_0", "name_1", "type_1"], "columns": { "iso": [], "name_0": [], "name_1": [], "type_1": [] } } }

Jiminy execution errors

The jiminy endpoint might sometimes return an error response. The following table describes the possible errors that can occur when calling this endpoint:

Error code Error message Description
400 SQL o FS required The required sql field is missing either as query string parameter or in the request body.
500 Internal server error The error message might vary in this case.

Jiminy endpoint parameters

The jiminy endpoint makes use of a single query parameter, which is required for a successful call of the endpoint:

Query parameter Description Type Required
sql The SQL query which will be the basis for inferring the chart types. String Yes

Forms

This section details the endpoints provided by the GFW Forms API service.

Requesting a webinar

To create a new webinar request, you need to provide at least the following details:

curl -X POST "https://api.resourcewatch.org/v1/form/request-webinar" \
-H "Content-Type: application/json" \
-d  \
'{
    "name": "Example name",
    "email": "example@email.com",
    "description": "Example description"
}'

Successful response: 204 No Content

In order to request a new webinar, you should make a POST request to the form/request-webinar endpoint, providing at least a name and an email in the request body. You can also optionally provide a description.

Webinar requests are pushed into a Google Spreadsheet (using the Google Sheets API). Staging webinar requests are located here, and production webinar requests are located here.

In case of success, this endpoint will return a response with status code 204 No Content. If an error occurs, a response with status code 500 Internal Server Error is returned.

Metadata

What is metadata?

If you are new to the RW API, or want to learn more about the concept of metadata, we strongly encourage you to read the metadata concept documentation first. It gives you a brief and clear description of what metadata is, and why it is useful.

Once you've read that section, you can come back here to learn more details about using the RW API Metadata feature, which aims to provide summary information about Datasets, Layers, and Widgets.

Metadata objects describe things like the name, spatial and temporal coverage, usage rights, and contact information of datasets as well as their associated layers and widgets, uploaded by WRI, its partner organizations, or by API users like you.

They are particularly useful for allowing users to find relevant datasets, layers and widgets, understand their context, and for providing useful extra information, such as descriptions, licensing, and citations.

As such, if you really want people to be able to use your datasets, widgets or layers, it is crucial that it has metadata!

To find out more about accessing metadata objects already available on the RW API, check out the documentation on getting metadata objects. If you'd like to share your data with the world, you can also create your own metadata on the RW API, as well as update and delete existing metadata objects.

Metadata objects

RW API's approach to metadata is designed to offer flexibility; both in terms of the information contained and languages. Hence, when working with metadata objects it is important to understand a few key concepts.

The first of which is that metadata objects contain information about another RW API entity - a dataset, a layer or a widget. Thus, each metadata object belongs to a single resource, identified by its type and id. As this type + id pair directly or indirectly (as widgets and layers themselves are associated with a dataset) references a dataset, and for convenience, each metadata object also has the dataset identifier to which it's associated.

Another important concept to keep in mind is that each metadata object concerns a single combination of language and application. If you want to provide translations of your metadata, or if you'd like it to tailor a resource's metadata to better fit different applications, you should create multiple metadata objects for the different combinations of application and language.

Building on top of the two concepts above, it's important to highlight that while each resource can have multiple metadata, it cannot have multiple metadata for the same combination of language and application. For example, metadata about a tree cover dataset for the Global Forest Watch application might be available in both English and Spanish (each a different metadata object), and these may be different compared to metadata objects in the same languages associated with Resource Watch application. This example would then represent a total of 4 different metadata objects, all associated with the same dataset.

When it comes to its internal structure, metadata objects have a balance of structured and free-format fields that promote a common base across all objects, while allowing different applications and use cases to have their own specific structure and details. You can learn more about the available fields in the metadata reference section.

Last but not least, it's important to keep in mind that the behavior of metadata objects and endpoints aims to be, as much as possible, independent from the target resource it references. In the detailed endpoint documentation below we'll cover the different endpoints in depth, and highlight the differences in behavior when handling different resource types, but you can safely assume that, for most of it, behavior described for a type of resource will be the same for all 3 types.

Metadata endpoints overview

As covered above, each metadata object directly concerns a single dataset, widget or layer. The endpoint structure mostly reflects that, with each metadata action (getting, creating, modifying or deleting metadata) being available through 3 different endpoints, one for each type of resource (for example, /v1/dataset/<dataset-id>/metadata, /v1/dataset/<dataset-id>/layer/<layer_id>/metadata and /v1/dataset/<dataset-id>/widget/<widget_id>/metadata). These endpoints will be documented as a single element, as they behave in exactly the same way, with the only difference between them being the actual endpoint URL. Any differences that may exist will be pointed out, but those will be rare. The only exceptions are the endpoints to load all metadata (which ignores resource type) and to clone a dataset's metadata, which doesn't have a widget or layer equivalent.

Getting metadata

There are 2 main ways to retrieve metadata objects from the RW API: using the "get all" endpoint (and optionally adding some filters), or loading metadata by their resource id (either a single element at a time, or multiple in one go) and type.

Remembering that each resource may have many metadata objects associated with it. In general, you will usually want to use the filter parameters application and language, which may be one or many of valid RW API applications and languages.

Getting all metadata

Getting a list of all metadata

curl -L -X GET 'https://api.resourcewatch.org/v1/metadata?application=rw,gfw&language=en,es&type=dataset&limit=1' \
-H 'Content-Type: application/json'

Getting a list of all metadata with optional parameters

curl -L -X GET 'https://api.resourcewatch.org/v1/metadata?application=rw,gfw&language=en,es&type=dataset&limit=1' \
-H 'Content-Type: application/json'

Example response

{
    "data": [
        {
            "id": "57cfffd6129c3c100054c383",
            "type": "metadata",
            "attributes": {
                "dataset": "0ffe5ad6-c920-421b-b69c-bc8893155df4",
                "application": "gfw",
                "resource": {
                    "id": "0ffe5ad6-c920-421b-b69c-bc8893155df4",
                    "type": "dataset"
                },
                "language": "en",
                "name": "",
                "description": "",
                "source": "",
                "citation": "",
                "license": "",
                "info": {
                    "organization": "",
                    "license": "",
                    "source": "",
                    "citation": "",
                    "description": "",
                    "short-description": "",
                    "subtitle": "",
                    "title": ""
                },
                "createdAt": "2016-12-13T10:02:28.337Z",
                "updatedAt": "2016-12-13T10:03:02.445Z",
                "status": "published"
            }
        }
    ]
}

This endpoint will allow you to get the list of the metadata available in the API, and it's the only endpoint that will allow you to load metadata for multiple resources at once.

It's worth pointing out that, unlike other similar endpoints on the RW API, this endpoint does NOT have pagination by default. If you query it without any of the optional parameters, you will get a list of all metadata objects for all datasets, widgets and layers. This is strongly discouraged, and you should not rely on this behavior - when using this endpoint, you should aim to use a combination of parameters to narrow down your response pool. You should also expect a future update to this endpoint to introduce pagination on all responses, so try to keep this in mind when using this endpoint on your application.

For a detailed description of each field, check out the Metadata reference section.

In the sections below, we’ll explore the optional parameters supported by this, which we strongly recommend you use.

Application and language filters

Getting a list of all metadata belonging to the RW application, written in either English or Spanish

curl -L -X GET 'https://api.resourcewatch.org/v1/metadata?application=rw&language=en,es' \
-H 'Content-Type: application/json'

You can filter by application and language of the metadata by passing query arguments with the same name in your call to this endpoint. You can filter by multiple values at the same time, separating them using using commas.

Type filter

Getting a list of all metadata for widgets

curl -L -X GET 'https://api.resourcewatch.org/v1/metadata?type=widget' \
-H 'Content-Type: application/json'

Using the type query parameter you can specify the type of the metadata resource to load. Expected values are dataset, widget or layer, and any other values will produce no results.

Limit

Getting a list of up to 10 metadata

curl -L -X GET 'https://api.resourcewatch.org/v1/metadata?limit=10' \
-H 'Content-Type: application/json'

Using the limit query parameter you can specify the maximum number of metadata to load in a single response.

Sorting

Sorting metadata

curl -X GET https://api.resourcewatch.org/v1/metadata?sort=name

Sorting metadata by multiple criteria

curl -X GET https://api.resourcewatch.org/v1/metadata?sort=name,description

Sort by name descending, description ascending

curl -X GET https://api.resourcewatch.org/v1/metadata?sort=-name,+description

The Metadata service currently supports sorting using the sort query parameter. Sorting metadata adheres to the conventions defined in the Sorting guidelines for the RW API, so we strongly recommend reading that section before proceeding. Additionally, you can check out the Metadata reference section for a detailed description of the fields you can use when sorting.

Getting metadata for a dataset, layer or widget

Getting metadata associated with a dataset

curl -L -X GET 'https://api.resourcewatch.org/v1/dataset/<dataset-id>/metadata' \
-H 'Content-Type: application/json'

Getting metadata associated with a layer

curl -L -X GET 'https://api.resourcewatch.org/v1/dataset/<dataset-id>/layer/<layer_id>/metadata' \
-H 'Content-Type: application/json'

Getting metadata associated with a widget

curl -L -X GET 'https://api.resourcewatch.org/v1/dataset/<dataset-id>/widget/<widget_id>/metadata' \
-H 'Content-Type: application/json'

Example response

{
    "data": [
        {
            "id": "595f836c0d9ed1000bc29a91",
            "type": "metadata",
            "attributes": {
                "dataset": "f2fe7588-6d1b-400e-b79c-0c86bf1273ea",
                "application": "rw",
                "resource": {
                    "id": "f2fe7588-6d1b-400e-b79c-0c86bf1273ea",
                    "type": "dataset"
                },
                "language": "en",
                "name": "Urban Population with Access to an Improved Water Source",
                "description": "The Percentage of Urban Population with Access to an Improved Water Source is derived by ...",
                "source": "UN WHO/WHO UNICEF JMP WSS",
                "info": {
                    "data_download_link": "null",
                    "frequency_of_updates": "Annual",
                    "date_of_content": "1990-present",
                    "spatial_resolution": "Tabular: National",
                    "geographic_coverage": "Global",
                    "link_to_linense": "http://data.worldbank.org/summary-terms-of-use",
                    "license": "Open: You are free to copy, distribute, adapt, display, or include ...",
                    "citation": "World Bank. 2015. \"World Development Indicators: Improved Water Source (% of Population with Access).\" Retrieved from http://data.worldbank.org/indicator/SH.H2O.SAFE.ZS. Accessed through Resource Watch on [date]. www.resourcewatch.org.",
                    "cautions": "The data on access to an improved water source measure the ...",
                    "source_organization_link": "null",
                    "source_organization": "United Nations World Health Organization (UN WHO)/World Health Organization and United Nations Children's Fund Joint Monitoring Programme for Water Supply and Sanitation (WHO UNICEF JMP WSS)",
                    "function": "This data set displays the percentage of urban population with access to an improved drinking water source in a dwelling or located within a convenient distance from the user's dwelling.",
                    "functions": "This data set displays the percentage of urban population with access to an improved drinking water source in a dwelling or located within a convenient distance from the user's dwelling.",
                    "name": "Urban Population with Access to an Improved Water Source",
                    "technical_title": "Percentage of Urban Population with Access to an Improved Water Source (WHO/UNICEF)"
                },
                "columns": {
                    "year": {
                        "description": "Measured year",
                        "alias": "Year"
                    },
                    "value": {
                        "alias": "Value"
                    },
                    "country": {
                        "alias": "Country Name"
                    },
                    "iso": {
                        "alias": "ISO-3 Country Code"
                    }
                },
                "createdAt": "2017-07-07T12:49:48.721Z",
                "updatedAt": "2017-08-28T14:30:17.701Z",
                "status": "published"
            }
        }
    ]
}

These endpoints allow you to get metadata for a single dataset, widget or layer. By default, metadata for all languages and applications is returned, but you can use optional query parameters to filter that result.

Application and language filters

Getting a list of all metadata for a given dataset, belonging to the RW application and written in either English or Spanish

curl -L -X GET 'https://api.resourcewatch.org/v1/dataset/<dataset-id>/metadata?application=rw&language=en,es' \
-H 'Content-Type: application/json' \

You can filter by application and language of the metadata by passing query arguments with the same name in your call to this endpoint. You can filter by multiple values at the same time, separating them using using commas.

Limit

Getting a list of all metadata for a given dataset, up to 10 results

curl -L -X GET 'https://api.resourcewatch.org/v1/dataset/<dataset-id>/metadata?limit=10' \
-H 'Content-Type: application/json' \

Using the limit query parameter you can specify the maximum number of metadata to load in a single response.

Getting metadata for multiple datasets, layers or widgets

Getting metadata associated with multiple datasets

curl -X POST https://api.resourcewatch.org/v1/dataset/:dataset/metadata/find-by-ids \
-H "Content-Type: application/json"  -d \
 '{
   "ids": [<dataset ids>]
  }'

Getting metadata associated with multiple widgets

curl -X POST https://api.resourcewatch.org/v1/dataset/:dataset/layer/metadata/find-by-ids \
-H "Content-Type: application/json"  -d \
 '{
   "ids": [<layer ids>]
  }'

Getting metadata associated with multiple widgets

curl -X POST https://api.resourcewatch.org/v1/dataset/:dataset/widget/metadata/find-by-ids \
-H "Content-Type: application/json"  -d \
 '{
   "ids": [<widget ids>]
  }'

Response

{
    "data": [
        {
            "id": "595f836c0d9ed1000bc29a91",
            "type": "metadata",
            "attributes": {
                "dataset": "f2fe7588-6d1b-400e-b79c-0c86bf1273ea",
                "application": "rw",
                "resource": {
                    "id": "f2fe7588-6d1b-400e-b79c-0c86bf1273ea",
                    "type": "dataset"
                },
                "language": "en",
                "name": "Urban Population with Access to an Improved Water Source",
                "description": "The Percentage of Urban Population with Access to an Improved Water Source is derived by ...",
                "source": "UN WHO/WHO UNICEF JMP WSS",
                "info": {
                    "data_download_link": "null",
                    "frequency_of_updates": "Annual",
                    "date_of_content": "1990-present",
                    "spatial_resolution": "Tabular: National",
                    "geographic_coverage": "Global",
                    "link_to_linense": "http://data.worldbank.org/summary-terms-of-use",
                    "license": "Open: You are free to copy, distribute, adapt, display, or include ...",
                    "citation": "World Bank. 2015. \"World Development Indicators: Improved Water Source (% of Population with Access).\" Retrieved from http://data.worldbank.org/indicator/SH.H2O.SAFE.ZS. Accessed through Resource Watch on [date]. www.resourcewatch.org.",
                    "cautions": "The data on access to an improved water source measure the ...",
                    "source_organization_link": "null",
                    "source_organization": "United Nations World Health Organization (UN WHO)/World Health Organization and United Nations Children's Fund Joint Monitoring Programme for Water Supply and Sanitation (WHO UNICEF JMP WSS)",
                    "function": "This data set displays the percentage of urban population with access to an improved drinking water source in a dwelling or located within a convenient distance from the user's dwelling.",
                    "functions": "This data set displays the percentage of urban population with access to an improved drinking water source in a dwelling or located within a convenient distance from the user's dwelling.",
                    "name": "Urban Population with Access to an Improved Water Source",
                    "technical_title": "Percentage of Urban Population with Access to an Improved Water Source (WHO/UNICEF)"
                },
                "columns": {
                    "year": {
                        "description": "Measured year",
                        "alias": "Year"
                    },
                    "value": {
                        "alias": "Value"
                    },
                    "country": {
                        "alias": "Country Name"
                    },
                    "iso": {
                        "alias": "ISO-3 Country Code"
                    }
                },
                "createdAt": "2017-07-07T12:49:48.721Z",
                "updatedAt": "2017-08-28T14:30:17.701Z",
                "status": "published"
            }
        }
    ]
}

This group of endpoints allows you to access metadata for multiple resources of the same type with a single request. The result will be a flat list of metadata elements, not grouped by their associated resource - it's up to your application to implement this logic if it needs it.

Application and language filters

Getting a list of all metadata for multiple widgets, belonging to the RW application and written in either English or Spanish

curl -X POST https://api.resourcewatch.org/v1/dataset/:dataset/widget/metadata/find-by-ids?application=rw&language=en,es \
-H "Content-Type: application/json"  -d \
 '{
   "ids": [<widget ids>]
  }'

You can filter by application and language of the metadata by passing query arguments with the same name in your call to this endpoint. You can filter by multiple values at the same time, separating them using using commas.

Errors for getting metadata for multiple datasets, layers or widgets

Error code Error message Description
400 Missing 'ids' from request body The required ids field is missing in the request body.

Creating metadata

Creating a new metadata for a given dataset

curl -X POST 'https://api.resourcewatch.org/v1/dataset/<dataset-id>/metadata' \
-H "Authorization: Bearer <auth_token>" \
-H "Content-Type: application/json" \
-d '{
  "application": <application>,
  "language": <language>,
  "name": "metadata name"
}'

Creating a new metadata for a given layer

curl -X POST 'https://api.resourcewatch.org/v1/dataset/<dataset-id>/layer/<layer-id>/metadata' \
-H "Authorization: Bearer <auth_token>" \
-H "Content-Type: application/json" \
-d '{
  "application": <application>,
  "language": <language>,
  "name": "metadata name"
}'

Creating a new metadata for a given widget

curl -X POST 'https://api.resourcewatch.org/v1/dataset/<dataset-id>/widget/<widget-id>/metadata' \
-H "Authorization: Bearer <auth_token>" \
-H "Content-Type: application/json" \
-d '{
  "application": <application>,
  "language": <language>,
  "name": "metadata name"
}'

Example response

{
    "data": [
        {
            "id": "5f99b9317fe3c8001be2f272",
            "type": "metadata",
            "attributes": {
                "dataset": "44c7fa02-391a-4ed7-8efc-5d832c567d57",
                "application": "gfw",
                "resource": {
                    "id": "44c7fa02-391a-4ed7-8efc-5d832c567d57",
                    "type": "dataset"
                },
                "language": "es",
                "createdAt": "2020-10-28T18:32:17.464Z",
                "updatedAt": "2020-10-28T18:32:17.464Z",
                "status": "published"
            }
        }
    ]
}

This group of endpoints allows you to associate metadata with an existing dataset, layer or widget. To help make your resources easier to find, understand and reuse, we recommend creating the associated metadata right after you create your new dataset, layer or widget, but you can do it at any time if you want.

As we covered before, the RW API implementation of metadata aims for flexibility, so the only hard requirements when creating a new metadata is that you specify the associate resource id and type, their corresponding dataset id, and the language and application of the metadata (you should ensure that dataset id in the URL matches the dataset id of the resource you're creating metadata for). Everything else is up to you to decide if you want to define or not, but the effectiveness of your metadata will increase if you provide more details about your resources. You can learn more about the available fields in the metadata reference section.

If you want to create new metadata for your resources, you must have the necessary user account permissions. Specifically, you must:

Errors for creating metadata

Error code Error message Description
400 <field>: <field> can not be empty Your are missing a required field value.
400 <field>: empty or invalid <field> The provided value for <field> is invalid.
401 Unauthorized You are not authenticated.
403 Forbidden You are trying to create metadata for an application value that is not associated with your user account.

Updating metadata

Updating metadata for a given dataset

curl -X PATCH https://api.resourcewatch.org/v1/dataset/<dataset-id>/metadata \
-H "Authorization: Bearer <auth_token>" \
-H "Content-Type: application/json"  -d \
 '{
   "application": <application>,
   "language": <language>,
   "name": "updated metadata name"
  }'

Updating metadata for a given layer

curl -X PATCH https://api.resourcewatch.org/v1/dataset/<dataset-id>/layer/<layer-id>/metadata \
-H "Authorization: Bearer <auth_token>" \
-H "Content-Type: application/json"  -d \
 '{
   "application": <application>,
   "language": <language>,
   "name": "updated metadata name"
  }'

Updating metadata for a given widget

curl -X PATCH https://api.resourcewatch.org/v1/dataset/<dataset-id>/widget/<widget-id>/metadata \
-H "Authorization: Bearer <auth_token>" \
-H "Content-Type: application/json"  -d \
 '{
   "application": <application>,
   "language": <language>,
   "name": "updated metadata name"
  }'

Example response

{
  "data": [
    {
      "id": "942b3f38-9504-4273-af51-0440170ffc86-dataset-942b3f38-9504-4273-af51-0440170ffc86-rw-en",
      "type": "metadata",
      "attributes": {
        "dataset": "942b3f38-9504-4273-af51-0440170ffc86",
        "application": "rw",
        "resource": {
          "type": "dataset",
          "id": "942b3f38-9504-4273-af51-0440170ffc86"
        },
        "language": "en",
        "name": "Cloud Computing Market - USA - 2016",
        "source": "http://www.forbes.com/",
        "info": {
          "summary": "These and many other insights are from the latest series of cloud computing forecasts and market estimates produced by IDC, Gartner, Microsoft and other research consultancies. Amazon’s decision to break out AWS revenues and report them starting in Q1 FY2015 is proving to be a useful benchmark for tracking global cloud growth.  In their latest quarterly results released on January 28, Amazon reported that AWS generated $7.88B in revenues and attained a segment operating income of $1.863B. Please see page 8 of the announcement for AWS financials.  For Q4, AWS achieved a 28.5% operating margin (% of AWS net sales).",
          "author": "Louis Columbus",
          "date": "MAR 13, 2016 @ 10:42 PM",
          "link": "http://www.forbes.com/sites/louiscolumbus/2016/03/13/roundup-of-cloud-computing-forecasts-and-market-estimates-2016/#5875cf0074b0"
        },
        "createdAt": "2017-01-20T08:07:53.272Z",
        "updatedAt": "2017-01-20T08:40:30.190Z",
        "status": "published"
      }
    }
  ]
}

To update an existing metadata, you need to issue a PATCH request to the endpoint that matches your resource type and id, specify the new values you want to use. You can update most of the fields listed in the metadata reference section, apart from:

One important detail is that you MUST specify, in your request body, both the application and language values of the metadata you're trying to update. These fields will not be used as new values, as you would expect, but are used to pinpoint exactly which metadata entry will be updated - remember that each resource may have multiple metadata associated with it, but only one per application-language pair.

Also keep in mind that, when updating object type fields, your new value will overwrite the previous value for that field entirely - it's up to you to implement any sort of data merge logic you'd like to see happen.

To perform this operation, the following conditions must be met:

Errors for updating metadata

Error code Error message Description
401 Unauthorized You need to be logged in to be able to update metadata.
403 Forbidden You need to either have the ADMIN role, or have role MANAGER and be the metadata owner (through the userId field of the metadata).
403 Forbidden You are trying to update metadata with an application value that is not associated with your user account.
404 Metadata of resource : doesn't exist Metadata matching the provided resource data, language and application does not exist.

Cloning dataset metadata

Cloning metadata for a given dataset

curl -X POST 'https://api.resourcewatch.org/v1/dataset/<dataset-id>/metadata/clone' 
-H 'Content-Type: application/json' \
-H "Authorization: Bearer <auth_token>" -d \
'{
    "newDataset": "<targer dataset>",
    "application": "<application>"
}'

Example response

{
  "data": [
    {
      "id": "942b3f38-9504-4273-af51-0440170ffc86-dataset-942b3f38-9504-4273-af51-0440170ffc86-rw-en",
      "type": "metadata",
      "attributes": {
        "dataset": "942b3f38-9504-4273-af51-0440170ffc86",
        "application": "rw",
        "resource": {
          "type": "dataset",
          "id": "942b3f38-9504-4273-af51-0440170ffc86"
        },
        "language": "en",
        "name": "Cloud Computing Market - USA - 2016",
        "source": "http://www.forbes.com/",
        "info": {
          "summary": "These and many other insights are from the latest series of cloud computing forecasts and market estimates produced by IDC, Gartner, Microsoft and other research consultancies. Amazon’s decision to break out AWS revenues and report them starting in Q1 FY2015 is proving to be a useful benchmark for tracking global cloud growth.  In their latest quarterly results released on January 28, Amazon reported that AWS generated $7.88B in revenues and attained a segment operating income of $1.863B. Please see page 8 of the announcement for AWS financials.  For Q4, AWS achieved a 28.5% operating margin (% of AWS net sales).",
          "author": "Louis Columbus",
          "date": "MAR 13, 2016 @ 10:42 PM",
          "link": "http://www.forbes.com/sites/louiscolumbus/2016/03/13/roundup-of-cloud-computing-forecasts-and-market-estimates-2016/#5875cf0074b0"
        },
        "createdAt": "2017-01-20T08:07:53.272Z",
        "updatedAt": "2017-01-20T08:40:30.190Z",
        "status": "published"
      }
    }
  ]
}

This endpoint allows you to clone all the existing metadata associated with a dataset, as new metadata associated with a different dataset. Note that this will not clone metadata for widgets or layers associated with the defined dataset; only dataset metadata will be cloned.

When calling this endpoint, you must provide two body parameters:

A successful cloning will return a list of all metadata created in this process.

To perform this operation, the following conditions must be met:

Errors for cloning metadata

Error code Error message Description
400 - newDataset: newDataset can not be empty. - You need to specify the newDataset body parameter.
400 Metadata of resource dataset: , application: and language: already exists The target dataset already has metadata associated with it, and cloning the metadata from the source dataset would cause it to have more than one metadata per language and application.
401 Unauthorized You need to be logged in to be able to update metadata.
403 Forbidden You need to either have the ADMIN role, or have role MANAGER and be the metadata owner (through the userId field of the metadata).
403 Forbidden You are trying to clone metadata with an application value that is not associated with your user account.
404 Metadata of resource : doesn't exist Metadata matching the provided resource data, language and application does not exist.

Deleting metadata

Deleting metadata for a given dataset

curl -X DELETE https://api.resourcewatch.org/v1/dataset/<dataset-id>/metadata?application=<application>&language=<language> \
-H "Authorization: Bearer <auth_token>" 

Deleting metadata for a given layer

curl -X DELETE https://api.resourcewatch.org/v1/dataset/<dataset-id>/layer/<layer-id>/metadata?application=<application>&language=<language> \
-H "Authorization: Bearer <auth_token>" 

Deleting metadata for a given widget

curl -X DELETE https://api.resourcewatch.org/v1/dataset/<dataset-id>/widget/<widget-id>/metadata?application=<application>&language=<language> \
-H "Authorization: Bearer <auth_token>" 

Example response

{
  "data": [
    {
      "id": "942b3f38-9504-4273-af51-0440170ffc86-dataset-942b3f38-9504-4273-af51-0440170ffc86-rw-en",
      "type": "metadata",
      "attributes": {
        "dataset": "942b3f38-9504-4273-af51-0440170ffc86",
        "application": "rw",
        "resource": {
          "type": "dataset",
          "id": "942b3f38-9504-4273-af51-0440170ffc86"
        },
        "language": "en",
        "name": "Cloud Computing Market - USA - 2016",
        "source": "http://www.forbes.com/",
        "info": {
          "summary": "These and many other insights are from the latest series of cloud computing forecasts and market estimates produced by IDC, Gartner, Microsoft and other research consultancies. Amazon’s decision to break out AWS revenues and report them starting in Q1 FY2015 is proving to be a useful benchmark for tracking global cloud growth.  In their latest quarterly results released on January 28, Amazon reported that AWS generated $7.88B in revenues and attained a segment operating income of $1.863B. Please see page 8 of the announcement for AWS financials.  For Q4, AWS achieved a 28.5% operating margin (% of AWS net sales).",
          "author": "Louis Columbus",
          "date": "MAR 13, 2016 @ 10:42 PM",
          "link": "http://www.forbes.com/sites/louiscolumbus/2016/03/13/roundup-of-cloud-computing-forecasts-and-market-estimates-2016/#5875cf0074b0"
        },
        "createdAt": "2017-01-20T08:07:53.272Z",
        "updatedAt": "2017-01-20T08:40:30.190Z",
        "status": "published"
      }
    }
  ]
}

The metadata delete endpoint allows you to delete a single metadata at a time, provided you have the necessary permissions. Besides the details provided in the URL itself, you must also specify, as query parameters, both the application and language values of the metadata you're trying to delete. These fields will be used to pinpoint exactly which metadata entry will be deleted - remember that each resource may have multiple metadata associated with it, but only one per application-language pair.

To perform this operation, the following conditions must be met:

Errors for deleting metadata

Error code Error message Description
400 Bad request Your request does not include the application or language query parameters.
401 Unauthorized You need to be logged in to be able to delete metadata.
403 Forbidden You need to either have the ADMIN role, or have role MANAGER and be the metadata owner (through the userId field of the metadata).
403 Forbidden You are trying to delete metadata with an application value that is not associated with your user account.
404 Metadata of resource : doesn't exist Metadata matching the provided resource data, language and application does not exist.

Metadata reference

This section gives you a complete view at the properties that are maintained as part of metadata objects. When interacting with metadata objects (on get, on create, etc) you will find most of these properties available to you, although they may be organized in a slightly different structure (ie: on get, everything but the id is nested inside an attributes object).

You can find more details in the source code.

Field name Type Required Default value Description
id String Yes (autogenerated) Unique Id of the metadata. Auto generated on creation. Cannot be modified by users.
dataset String Yes Id of the dataset to which the metadata object corresponds. Set on metadata creation, cannot be modified.
application Array Yes Applications associated with this metadata. Read more about this field here.
resource.id String Yes Id of the resource associated with the metadata.
resource.type String Yes Type of the resource associated with the metadata.
userId String Yes (autopopulated) Id of the user who created the metadata. Set automatically on creation. Cannot be modified by users.
language String Yes Language in which the metadata details are written. While not enforced, we strongly recommend using 2 character language codes.
name String No Name of the metadata.
description String No User defined description of the metadata.
status String No published Publication status of the metadata. Defaults to published, can alternatively be set to unpublished.
source String No Source information about the associated resource
citation String No Citation information about the associated resource
license String No License named used for the associated resource
units Object No Free-form object mapping each of the associated resource's fields to a unit
info Object No Free-form object for custom information about the associated resource
columns Object No Free-form object mapping each of the associated resource's fields to a free-form object containing more details.
applicationProperties Object No Free-form object containing application-specific information about the associated resource
createdAt Date No (autogenerated) Automatically maintained date of when the metadata was created. Cannot be modified by users.
updatedAt Date No (autogenerated) Automatically maintained date of when the metadata was last updated. Cannot be modified by users.

Vocabularies and tags

What are vocabularies and tags?

Vocabularies and tags concepts are covered in their dedicated section, and we strongly recommend you read that section before diving into the details of the respective endpoints. In it, we explain in detail what is a tag and a vocabulary, and why you should use them to empower different use cases of the RW API.

Simply put, a tag is a keyword that describes a resource (we'll talk in depth about what these are in the next section). A vocabulary is a group of tags and has a name (also called and used as an id for the vocabulary) that should define the scope or context of the tags it contains.

It's important to keep in mind that these associations between a resource and a vocabulary have an application associated with them. Putting this in an example, dataset AAA may be associated with vocabulary BBB for application rw, but not for application gfw. Most endpoints will allow you explicitly define which application you are referring to (some will even require it), and a rw default value will be assumed when no explicit value is provided.

What are resources?

Throughout this section, we'll refer multiple times to resources. Simply put, a resource is either a dataset, a widget, or a layer. Tags and vocabularies work in a similar fashion for each of these 3 types of RW API entity, so often we'll refer to resources instead, for convenience.

We assume that, at this point, you are already familiar with the concepts of dataset, layer or widget (ideally you are familiar with the 3). If that's not the case, we strongly encourage you to learn about those concepts first, and we also recommend you take some time to explore and experiment using actual dataset, layer, or widget endpoints before proceeding. Vocabularies and tags exist to improve and empower your use cases of those resources, so it should only be used by applications and users that are already comfortable with the basics, and want to take their knowledge of the RW API to the next level.

The behavior of vocabulary and tags endpoints aims to be, as much as possible, independent from the type of the target resource it references. In the detailed endpoint documentation below we'll cover the different endpoints in depth, and highlight the differences in behavior when handling different resource types, but you can safely assume that, for most of it, the behavior described for a type of resource will be the same for all 3 types.

A note on resources

Creating a new vocabulary/tag for a widget

curl -X POST https://api.resourcewatch.org/v1/dataset/AAA/widget/BBB/vocabulary/VVV \
-H "Content-Type: application/json"  -d \
 '{
   "application": <application>,
   "tags": [<tags>]
  }'

In the context of the vocabulary/tag service, widgets and layers are identified not only by their own id but also by the id you specify as being their associated dataset. Using the side example as reference, this API request would create a vocabulary VVV for the resource widget BBB associated with dataset AAA. If you later reference the same widget id, but as belonging to a different dataset, it will be treated as a different resource altogether, and thus will have different vocabularies and tags. Keep in mind that widgets and layers should only be associated with a single dataset, so this behavior is described as a pitfall, and you should only rely on vocabularies/tags for widgets/layers properly associated with their correct dataset.

The special knowledge_graph vocabulary

Throughout the whole vocabulary/tags service, there is a special vocabulary named knowledge_graph. When used, this vocabulary acts as any other vocabulary but has additional logic built-in for the purpose of integrating vocabulary/tags with the graph available as part of the RW API.

Whenever you create or clone a vocabulary named knowledge_graph for a resource, the dataset, layer or widget node is added to the graph if not already present, and the tags are associated to it. Updating the knowledge_graph vocabulary also updates the corresponding tags associated to it on the graph side, and deleting the vocabulary also deletes the corresponding tags in the graph.

For more details on the graph, its purpose, and how to use it, please refer its dedicated concept and reference documentation.

Associations between vocabularies, tags and resources

Vocabularies and resources

Despite not being 100% accurate, it's useful to think that a vocabulary is uniquely identified by a tuple of 3 values:

Putting it in other words: you can think of a vocabulary as being associated with only one resource at a time. So, if you create, update or delete a vocabulary, you are only doing so for that resource. You can safely modify the vocabularies for a resource without fear of affecting vocabularies and tags for other resources.

Further down, we'll cover endpoints that allow you to discover resources by performing searches based on vocabularies and tags. These endpoints are able to aggregate these different vocabularies and tags from multiple resources, and produce a unified response - making it look like vocabularies are shared across resources, and thus producing meaningful results.

If you find the above slightly confusing, we advise you explore these docs and learn more about the different endpoints available - maybe even try to add vocabularies and tags to one of your resources - and then come back and see if your newly gained knowledge helps you get a deeper understanding of how vocabularies and tags work on the RW API.

Vocabularies and tags

Tags are simply strings associated with an individual vocabulary. They have no direct connection to a resource and have no logic or complexity within the context of a vocabulary. Tags that have the same value but belong to different vocabularies are not matched or related in any way.

Endpoint overview

In broad terms, there are two types of endpoints for manipulating vocabulary/tags: endpoints that allow to CRUD vocabulary/tags for a given resource, and endpoints that allow you to query for resources for a given vocabulary/tag.

We'll start by covering how you can manipulate associations between vocabulary/tags and resources, and further down will cover how to list vocabulary/tags, and their associated resources.

Getting vocabulary/tags for a resource

There are two types of endpoints that will allow you to get vocabularies and tags for a resource: one to retrieve all vocabularies and their tags, and another to retrieve all tags for a given vocabulary.

Getting all vocabularies and tags for a resource

Getting vocabularies and tags associated with a dataset

curl -L -X GET 'https://api.resourcewatch.org/dataset/<dataset-id>/vocabulary' \
-H 'Content-Type: application/json'

Getting vocabularies and tags associated with a layer

curl -L -X GET 'https://api.resourcewatch.org/v1/dataset/<dataset-id>/layer/<layer_id>/vocabulary' \
-H 'Content-Type: application/json'

Getting vocabularies and tags associated with a widget

curl -L -X GET 'https://api.resourcewatch.org/v1/dataset/<dataset-id>/widget/<widget_id>/vocabulary' \
-H 'Content-Type: application/json'

Example response

{
    "data": [
        {
            "id": "testVocabulary1",
            "type": "vocabulary",
            "attributes": {
                "tags": [
                    "tag1",
                    "tag2"
                ],
                "name": "testVocabulary1",
                "application": "rw"
            }
        },
        {
            "id": "testVocabulary2",
            "type": "vocabulary",
            "attributes": {
                "tags": [
                    "tag3",
                    "tag2"
                ],
                "name": "testVocabulary2",
                "application": "rw"
            }
        }
    ]
}

These endpoints allow you to get vocabulary/tags for a single dataset, widget, or layer. By default, vocabulary/tags for the rw application are returned, but you can use the optional app or application query parameters to load data for a different application.

Getting a single vocabulary and its tags for a resource

Getting a single vocabulary and tags associated with a dataset

curl -L -X GET 'https://api.resourcewatch.org/dataset/<dataset-id>/vocabulary/<vocabulary-id>' \
-H 'Content-Type: application/json'

Getting a single vocabulary and tags associated with a layer

curl -L -X GET 'https://api.resourcewatch.org/v1/dataset/<dataset-id>/layer/<layer_id>/vocabulary/<vocabulary-id>' \
-H 'Content-Type: application/json'

Getting a single vocabulary and tags associated with a widget

curl -L -X GET 'https://api.resourcewatch.org/v1/dataset/<dataset-id>/widget/<widget_id>/vocabulary/<vocabulary-id>' \
-H 'Content-Type: application/json'

Example response

{
    "data": [
        {
            "id": "test1",
            "type": "vocabulary",
            "attributes": {
                "tags": [
                    "tag1",
                    "tag2"
                ],
                "name": "test1",
                "application": "rw"
            }
        }
    ]
}

These endpoints allow you to get a single vocabulary and its tags for a single dataset, widget, or layer. By default, vocabulary/tags for the rw application are returned, but you can use the optional app or application query parameters to load data for a different application.

Getting vocabularies and tags for multiple resources

Getting vocabularies and tags for multiple datasets

curl -X POST https://api.resourcewatch.org/v1/dataset/vocabulary/find-by-ids \
-H "Content-Type: application/json"  -d \
 '{
   "ids": [<ids>]
  }'

Getting vocabularies and tags for multiple widgets

curl -X POST https://api.resourcewatch.org/v1/dataset/<dataset-id>/widget/vocabulary/find-by-ids \
-H "Content-Type: application/json"  -d \
 '{
   "ids": [<ids>]
  }'

Getting vocabularies and tags for multiple layers

curl -X POST https://api.resourcewatch.org/v1/dataset/<dataset-id>/layer/vocabulary/find-by-ids \
-H "Content-Type: application/json"  -d \
 '{
   "ids": [<ids>]
  }'

Example response

{
    "data": [
        {
            "type": "vocabulary",
            "attributes": {
                "resource": {
                    "id": "7fa6ec77-5ab0-43f4-9a4c-a3d19bed1e90",
                    "type": "dataset"
                },
                "tags": [
                    "tag1",
                    "tag5"
                ],
                "name": "vocabulary1",
                "application": "cw"
            }
        },
        {
            "type": "vocabulary",
            "attributes": {
                "resource": {
                    "id": "ca6817fd-130c-47d4-8a95-303083b2cffa",
                    "type": "dataset"
                },
                "tags": [
                    "tag3",
                    "tag2"
                ],
                "name": "test2",
                "application": "gfw"
            }
        }
    ]
}

This group of endpoints allows you to retrieve the vocabularies for multiple resources of the same type using a single request. It expects a body containing an ids value, which can either be an array of ids, or a string containing multiple ids separated by commas.

When retrieving widgets or layers using these endpoints, the dataset id passed in the URL is ignored, and will not affect the result of the endpoint.

These endpoints return vocabularies for all applications by default, but you can pass an optional application value as a query parameter to filter by a specific application.

Errors for getting vocabularies and tags for multiple resources

Error code Error message Description
404 Bad request - Missing 'ids' from request body Your request body is missing the ids field

Creating vocabularies/tags for a resource

There are two types of endpoints for associating vocabulary/tags with resources: one allows you to create a single vocabulary (and its tags) for a resource, while the other supports creating multiple vocabularies/tags for a single resource. The primary use case for these endpoints is when you just created a new dataset/layer/widget, and want to add vocabularies/tags to them.

Creating a single vocabulary/tags for a resource

Creating a new vocabulary/tag for a dataset

curl -X POST https://api.resourcewatch.org/v1/dataset/<dataset-id>/vocabulary/<vocabulary-id> \
-H "Content-Type: application/json"  -d \
 '{
   "application": <application>,
   "tags": [<tags>]
  }'

Creating a new vocabulary/tag for a widget

curl -X POST https://api.resourcewatch.org/v1/dataset/<dataset-id>/widget/<widget-id>/vocabulary/<vocabulary-id> \
-H "Content-Type: application/json"  -d \
 '{
   "application": <application>,
   "tags": [<tags>]
  }'

Creating a new vocabulary/tag for a layer

curl -X POST https://api.resourcewatch.org/v1/dataset/<dataset-id>/layer/<layer-id>/vocabulary/<vocabulary-id> \
-H "Content-Type: application/json"  -d \
 '{
   "application": <application>,
   "tags": [<tags>]
  }'

Example response

{
    "data": [
        {
            "id": "testVocabulary1",
            "type": "vocabulary",
            "attributes": {
                "tags": [
                    "tag1",
                    "tag2"
                ],
                "name": "testVocabulary1",
                "application": "rw"
            }
        },
        {
            "id": "testVocabulary2",
            "type": "vocabulary",
            "attributes": {
                "tags": [
                    "tag3",
                    "tag2"
                ],
                "name": "testVocabulary2",
                "application": "rw"
            }
        }
    ]
}

This set of endpoints will allow you to create a new vocabulary/tags for a resource.

The request body must contain both an array of tags and the application under which the vocabulary/tags are being created. If a vocabulary with the same name already exists for the specified application, you will get an error message

Assuming the creation was successful, the response will contain a list of all vocabularies and their respective tags associated with the specified resource, for all applications.

If you want to create new vocabulary/tags for your resources, you must have the necessary user account permissions. Specifically:

An important note: When creating vocabulary/tags for a resource, the dataset id specified in the URL is validated, and the requests fail if a dataset with the given id does not exist. When creating a vocabulary for a widget or layer, you should ensure you specify the dataset id that matches that of the widget/layer, as that validation is not done automatically - this is a known limitation of the current implementation, and may be modified at any time, and invalid resources (those where the layer's/widget's dataset id does not match the dataset id defined in the resource) may be purged without prior warning.

Errors for creating a single vocabulary/tags for a resource

Error code Error message Description
400 This relationship already exists The resource already has a vocabulary with the same name for the specified application
400 - tags: tags can not be empty. - tags body fields is empty
400 - tags: tags check failed. - Either the tags or applications body fields are missing or have an invalid value
401 Unauthorized You are not authenticated.
403 Forbidden You are trying to create a vocabulary for a resource whose application value is not associated with your user account.
404 404 - {\"errors\":[{\"status\":404,\"detail\":\"Dataset with id <dataset id> doesn't exist\"}]} You are trying to create a vocabulary for a dataset that doesn't exist.

Creating multiple vocabularies/tags for a resource

Creating new vocabularies/tags for a dataset

curl -X POST https://api.resourcewatch.org/v1/dataset/<dataset-id>/vocabulary \
-H "Content-Type: application/json"  -d \
 '{
    "vocabulary1": {
        "tags":["tag1", "tag2"],
        "application": "rw"
    },
    "vocabulary2": {
        "tags":["tag3", "tag4"],
        "application": "rw"
    }
  }'

Creating new vocabularies/tags for a widget

curl -X POST https://api.resourcewatch.org/v1/dataset/<dataset-id>/widget/<widget-id>/vocabulary \
-H "Content-Type: application/json"  -d \
'{
    "vocabulary1": {
        "tags":["tag1", "tag2"],
        "application": "rw"
    },
    "vocabulary2": {
        "tags":["tag3", "tag4"],
        "application": "rw"
    }
}'

Creating new vocabularies/tags for a layer

curl -X POST https://api.resourcewatch.org/v1/dataset/<dataset-id>/layer/<layer-id>/vocabulary \
-H "Content-Type: application/json"  -d \
'{
    "vocabulary1": {
        "tags":["tag1", "tag2"],
        "application": "rw"
    },
    "vocabulary2": {
        "tags":["tag3", "tag4"],
        "application": "rw"
    }
}'

Example response

{
    "data": [
        {
            "id": "vocabulary1",
            "type": "vocabulary",
            "attributes": {
                "tags": [
                    "tag1",
                    "tag2"
                ],
                "name": "vocabulary1",
                "application": "rw"
            }
        },
        {
            "id": "vocabulary2",
            "type": "vocabulary",
            "attributes": {
                "tags": [
                    "tag3",
                    "tag4"
                ],
                "name": "vocabulary2",
                "application": "rw"
            }
        }
    ]
}

This set of endpoints will allow you to create multiple vocabularies/tags for a single resource in a single request.

The request body must contain at least one key, each of them corresponding to the names of the vocabularies you want to create. Each of these keys must have an object-type value, which in turn must contain the following keys:

You can create different vocabularies for different applications in a single request.

Assuming the creation was successful, the response will contain a list of all vocabularies and their respective tags associated with the specified resource, for all applications.

If you want to create new vocabulary/tags for your resources, you must have the necessary user account permissions. Specifically:

An important note: When creating vocabularies/tags for a resource, the dataset id specified in the URL is validated, and the requests fail if a dataset with the given id does not exist. When creating a vocabulary for a widget or layer, you should ensure you specify the dataset id that matches that of the widget/layer, as that validation is not done automatically - this is a known limitation of the current implementation, and may be modified at any time, and invalid resources (those where the layer's/widget's dataset id does not match the dataset id defined in the resource) may be purged without prior warning.

Errors for creating a single vocabulary/tags for a resource

Error code Error message Description
400 This relationship already exists The resource already has one or more vocabularies with the same name(s) for the specified application(s)
400 - <value>: <value> check failed. - The body object has a <value> key which content is invalid (is not an object or is missing tags and/or application).
401 Unauthorized You are not authenticated.
403 Forbidden You are trying to create a vocabulary for a resource whose application value is not associated with your user account.
404 404 - {\"errors\":[{\"status\":404,\"detail\":\"Dataset with id <dataset id> doesn't exist\"}]} You are trying to create a vocabulary for a dataset that doesn't exist.

Updating vocabularies/tags

If you have already associated vocabularies and tags to your resources and would like to modify those tags, the next set of endpoints is for you.

There are three types of endpoints for updating existing vocabulary/tags:

Updating a single vocabulary/tags for a resource

Updating a vocabulary for a dataset

curl -X PATCH https://api.resourcewatch.org/v1/dataset/<dataset-id>/vocabulary/<vocabulary-id> \
-H "Content-Type: application/json"  -d \
 '{
   "application": <application>,
   "tags": [<tags>]
  }'

Updating a vocabulary for a widget

curl -X PATCH https://api.resourcewatch.org/v1/dataset/<dataset-id>/widget/<widget-id>/vocabulary/<vocabulary-id> \
-H "Content-Type: application/json"  -d \
 '{
   "application": <application>,
   "tags": [<tags>]
  }'

Updating a vocabulary for a layer

curl -X PATCH https://api.resourcewatch.org/v1/dataset/<dataset-id>/layer/<layer-id>/vocabulary/<vocabulary-id> \
-H "Content-Type: application/json"  -d \
 '{
   "application": <application>,
   "tags": [<tags>]
  }'

Example response

{
    "data": [
        {
            "id": "vocabularyNameOne",
            "type": "vocabulary",
            "attributes": {
                "tags": [
                    "tag1",
                    "tag2",
                    "tag3"
                ]
            }
        },
        {
            "id": "science",
            "type": "vocabulary",
            "attributes": {
                "tags": [
                    "maths",
                    "astronomy"
                ]
            }
        },
        {
            "id": "aaa",
            "type": "vocabulary",
            "attributes": {
                "tags": [
                    "biology",
                    "chemistry"
                ]
            }
        }
    ]
}

This set of endpoints will allow you to update the tags of an existing vocabulary/tags for a resource.

The request body must contain the application of the vocabulary you want to update, and it will fail if you specify a vocabulary name/application pair that does not exist. Additionally, it must contain a tags array of strings with a list of new tags to use. Any existing tags that already existed for that vocabulary (for that resource and application) will be deleted, and replaced with the values you provide through this request.

Assuming the update was successful, the response will contain a list of all vocabularies and their respective tags associated with the specified resource, for all applications.

If you want to update vocabulary/tags for your resources, you must have the necessary user account permissions. Specifically:

An important note: When updating vocabulary/tags for a resource, the dataset id specified in the URL is validated, and the requests fail if a dataset with the given id does not exist. When updating a vocabulary for a widget or layer, you should ensure you specify the dataset id that matches that of the widget/layer, as that validation is not done automatically - this is a known limitation of the current implementation, and may be modified at any time, and invalid resources (those where the layer's/widget's dataset id does not match the dataset id defined in the resource) may be purged without prior warning.

Errors for updating a single vocabulary/tags for a resource

Error code Error message Description
400 - <value>: <value> check failed. - The body object has a <value> key which content is invalid (is not an object, or is missing tags and/or application).
401 Unauthorized You are not authenticated.
403 Forbidden You are trying to update a vocabulary for a resource whose application value is not associated with your user account.
404 404 - {\"errors\":[{\"status\":404,\"detail\":\"Dataset with id <dataset id> doesn't exist\"}]} You are trying to create a vocabulary for a dataset that doesn't exist.
404 Relationship between undefined and dataset - <dataset id> and dataset: <dataset id> doesn't exist You are trying to update a vocabulary that doesn't exist. Check your vocabulary name and application

Updating multiple vocabularies/tags for a dataset

Updating multiple vocabularies/tags for a dataset

curl -X PUT https://api.resourcewatch.org/v1/dataset/<dataset-id>/vocabulary \
-H "Content-Type: application/json"  -d \
 '{
    "vocabulary1": {
        "tags":["tag1", "tag2"],
        "application": "rw"
    },
    "vocabulary2": {
        "tags":["tag3", "tag4"],
        "application": "rw"
    }
  }'

Example response

{
    "data": [
        {
            "id": "vocabulary1",
            "type": "vocabulary",
            "attributes": {
                "tags": [
                    "tag1",
                    "tag2"
                ],
                "name": "vocabulary1",
                "application": "rw"
            }
        },
        {
            "id": "vocabulary2",
            "type": "vocabulary",
            "attributes": {
                "tags": [
                    "tag3",
                    "tag4"
                ],
                "name": "vocabulary2",
                "application": "rw"
            }
        }
    ]
}

Know issue warning There's a known issue where you may experience a 400 - This relationship already exists error when using this endpoint. There's currently no ETA for its resolution. As a workaround, we suggest updating vocabularies individually.

This endpoint will allow you to update multiple vocabularies/tags for a single dataset in a single request.

The request body must contain at least one key, each of them corresponding to the names of the vocabularies you want to update. Each of these keys must have an object-type value, which in turn must contain the following keys:

You can update different vocabularies for different applications in a single request.

Assuming the update was successful, the response will contain a list of all vocabularies and their respective tags associated with the specified dataset, for all applications.

If you want to update vocabulary/tags for your datasets, you must have the necessary user account permissions. Specifically:

Errors for updating multiple vocabularies/tags for a dataset

Error code Error message Description
400 - tags: tags can not be empty. - tags body fields is empty
400 - tags: tags check failed. - Either the tags or applications body fields are missing or have an invalid value.
401 Unauthorized You are not authenticated.
403 Forbidden You are trying to update a vocabulary for a resource whose application value is not associated with your user account.
404 404 - {\"errors\":[{\"status\":404,\"detail\":\"Dataset with id <dataset id> doesn't exist\"}]} You are trying to create a vocabulary for a dataset that doesn't exist.
404 Relationship between undefined and dataset - <dataset id> and dataset: <dataset id> doesn't exist You are trying to update a vocabulary that doesn't exist. Check your vocabulary name and application

Concatenating tags to a dataset vocabulary

Concatenating tags to a dataset vocabulary

curl -X POST https://api.resourcewatch.org/v1/dataset/<dataset-id>/vocabulary/<vocabulary-id>/concat \
-H "Content-Type: application/json"  -d \
'{
    "tags":["tag1", "tag2"],
    "application": "rw"
}'

Example response

{
    "data": [
        {
            "id": "vocabulary1",
            "type": "vocabulary",
            "attributes": {
                "tags": [
                    "tag1",
                    "tag2"
                ],
                "name": "vocabulary1",
                "application": "rw"
            }
        },
        {
            "id": "vocabulary2",
            "type": "vocabulary",
            "attributes": {
                "tags": [
                    "tag3",
                    "tag4"
                ],
                "name": "vocabulary2",
                "application": "rw"
            }
        }
    ]
}

This endpoint allows you to add more tags to an existing vocabulary for a dataset. The dataset is identified by the id provided in the URL, while the specific vocabulary to update is determined by the vocabulary id in the URL and the application value in the POST body - if no matching vocabulary is found, a new one is created. The body should also contain an array of tags which will be appended to the target vocabulary. The endpoint validates and requires that a dataset with the provided id exists. Any tags that exist both in the request and in the vocabulary prior to the concat are merged - the resulting tags list won't have duplicated values.

Should the request be successful, the response will have a complete list of vocabularies/tags for the dataset, for all applications.

Errors for concatenating tags to a dataset vocabulary

Error code Error message Description
400 - tags: tags can not be empty. - tags body fields is empty
400 - tags: tags check failed. - Either the tags or applications body fields are missing or have an invalid value.
401 Unauthorized You are not authenticated.
403 Forbidden You are trying to concatenate a vocabulary for a dataset whose application value is not associated with your user account.
404 404 - {\"errors\":[{\"status\":404,\"detail\":\"Dataset with id <dataset id> doesn't exist\"}]} The dataset specified in the request URL doesn't exist.

Cloning vocabularies/tags for a dataset

Cloning vocabularies/tags for a dataset

curl -X POST https://api.resourcewatch.org/v1/dataset/<dataset-id>/vocabulary/clone/dataset \
-H "Content-Type: application/json"  -d \
 '{
    "newDataset": "<target-dataset-id>"
  }'

Example response

{
    "data": [
        {
            "id": "vocabulary1",
            "type": "vocabulary",
            "attributes": {
                "tags": [
                    "tag1",
                    "tag2"
                ],
                "name": "vocabulary1",
                "application": "rw"
            }
        },
        {
            "id": "vocabulary2",
            "type": "vocabulary",
            "attributes": {
                "tags": [
                    "tag3",
                    "tag4"
                ],
                "name": "vocabulary2",
                "application": "rw"
            }
        }
    ]
}

This endpoint allows you to clone all vocabularies/tags for all applications, for a single dataset.

The URL should include the id of the source dataset, while the POST body should include a newDataset field containing the id of the target dataset. The target dataset id is not validated - the cloning will still occur even if the target id doesn't correspond to an existing dataset.

The dataset you use as the target dataset can have existing vocabularies - the cloning operation is an additive, and will not update nor destroy any existing vocabulary that may have already been associated with the target dataset. However, the cloning operation will fail if it tries to overwrite a vocabulary (ie. if the target dataset already has a vocabulary with the same name and application as one being created as part of the cloning). This failure is not atomic - the target dataset may end up with some of the vocabularies of the source dataset. It's up to you, as the RW API user, to both manage these collisions, and recover from them should they happen.

Assuming the cloning was successful, the response will contain a list of all vocabularies (both newly cloned and preexisting) and their respective tags, for all applications, for the target dataset.

If you want to clone vocabularies/tags for your datasets, you must have the necessary user account permissions. Specifically:

An important note: When cloning vocabularies/tags for a dataset, the source dataset id specified in the URL is validated, and the requests fails if a dataset with the given id does not exist. When creating a vocabulary for a widget or layer, you should ensure you specify the dataset id that matches that of the widget/layer, as that validation is not done automatically - this is a known limitation of the current implementation, and may be modified at any time, and invalid resources (those where the layer's/widget's dataset id does not match the dataset id defined in the resource) may be purged without prior warning.

Errors for cloning vocabularies/tags for a dataset

Error code Error message Description
400 This relationship already exists The target dataset already has one or more vocabularies with the same name(s) and application(s) as the source dataset.
400 - newDataset: newDataset can not be empty. - The body object must have a newDataset key with the id of the target dataset.
401 Unauthorized You are not authenticated.
403 Forbidden You are trying to clone vocabulary for a source dataset whose application value is not associated with your user account.
404 404 - {\"errors\":[{\"status\":404,\"detail\":\"Dataset with id <dataset id> doesn't exist\"}]} You are trying to clone a vocabularies for a source dataset that doesn't exist.

Deleting vocabularies/tags for a resource

There are two types of endpoints for deleting vocabularies/tags: one allows you to delete a single vocabulary (and its tags) for a resource, while the other supports deleting all the vocabularies/tags for a single resource. Some use cases for these include deleting vocabularies prior to deleting the actual resource, or typical housekeeping tasks you may want to carry out on your data.

Deleting a single vocabulary/tags for a resource

Deleting a single vocabulary/tag for a dataset

curl -X DELETE https://api.resourcewatch.org/v1/dataset/<dataset-id>/vocabulary/<vocabulary-id>

Deleting a single vocabulary/tag for a widget

curl -X DELETE https://api.resourcewatch.org/v1/dataset/<dataset-id>/widget/<widget-id>/vocabulary/<vocabulary-id>

Deleting a single vocabulary/tag for a layer

curl -X DELETE https://api.resourcewatch.org/v1/dataset/<dataset-id>/layer/<layer-id>/vocabulary/<vocabulary-id>

Example response

{
    "data": [
        {
            "id": "country",
            "type": "vocabulary",
            "attributes": {
                "tags": [
                    "Spain",
                    "Italy",
                    "Portugal"
                ]
            }
        },
        {
            "id": "color",
            "type": "vocabulary",
            "attributes": {
                "tags": [
                    "red",
                    "green",
                    "blue"
                ]
            }
        }
    ]
}

This set of endpoints will allow you to delete a single vocabulary and its tags, for a resource.

As a query param, you can optionally provide an app or application values, to identify the application of the vocabulary to delete - by default, rw is assumed.

Assuming the operation was successful, the response will contain a list of all vocabularies and their respective tags associated with the specified resource, for all applications - including the vocabulary that was deleted.

If you want to delete vocabularies/tags for your resources, you must have the necessary user account permissions. Specifically:

An important note: When deleting vocabulary/tags for a resource, the dataset id specified in the URL is validated, and the requests fail if a dataset with the given id does not exist. When deleting a vocabulary for a widget or layer, you should ensure you specify the dataset id that matches that of the widget/layer, as that validation is not done automatically - this is a known limitation of the current implementation and may be modified at any time.

Errors for deleting a single vocabulary/tags for a resource

Error code Error message Description
401 Unauthorized You are not authenticated.
403 Forbidden You are trying to delete a vocabulary for a resource whose application value is not associated with your user account.
404 404 - {\"errors\":[{\"status\":404,\"detail\":\"Dataset with id <dataset id> doesn't exist\"}]} You are trying to create a vocabulary for a dataset that doesn't exist.
404 Relationship between <vocabulary-id> and dataset - and dataset: ` doesn't exist You are trying to delete a vocabulary that doesn't exist.

Deleting all vocabulary/tags for a resource

Deleting all vocabularies/tag for a dataset

curl -X DELETE https://api.resourcewatch.org/v1/dataset/<dataset-id>/vocabulary

Deleting all vocabularies/tag for a widget

curl -X DELETE https://api.resourcewatch.org/v1/dataset/<dataset-id>/widget/<widget-id>/vocabulary

Deleting all vocabularies/tag for a layer

curl -X DELETE https://api.resourcewatch.org/v1/dataset/<dataset-id>/layer/<layer-id>/vocabulary

Example response

{
    "data": [
        {
            "id": "country",
            "type": "vocabulary",
            "attributes": {
                "tags": [
                    "Spain",
                    "Italy",
                    "Portugal"
                ]
            }
        },
        {
            "id": "color",
            "type": "vocabulary",
            "attributes": {
                "tags": [
                    "red",
                    "green",
                    "blue"
                ]
            }
        }
    ]
}

Know issue warning There's a known issue where you may experience a 404 - Relationship between undefined and dataset - <dataset id> and dataset: <dataset id> doesn't exist error when using these endpoints. If you experience this issue, keep in mind that some vocabularies may have already been deleted, despite the error message. Those are not recoverable. There's currently no ETA for its resolution. As a workaround, we suggest deleting vocabularies individually.

This set of endpoints will allow you to delete all vocabularies and their tags for a resource.

Assuming the operation was successful, the response will contain a list of all vocabularies and their respective tags associated with the specified resource, for all applications - all of which were already deleted.

If you want to delete vocabularies/tags for your resources, you must have the necessary user account permissions. Specifically:

An important note: When deleting vocabulary/tags for a resource, the dataset id specified in the URL is validated, and the requests fail if a dataset with the given id does not exist. When deleting vocabularies for a widget or layer, you should ensure you specify the dataset id that matches that of the widget/layer, as that validation is not done automatically - this is a known limitation of the current implementation and may be modified at any time.

Errors for deleting all vocabularies/tags for a resource

Error code Error message Description
401 Unauthorized You are not authenticated.
403 Forbidden You are trying to delete vocabularies for a resource whose application value is not associated with your user account.
404 404 - {\"errors\":[{\"status\":404,\"detail\":\"Dataset with id <dataset id> doesn't exist\"}]} You are trying to delete vocabularies for a dataset that doesn't exist.

Getting vocabularies and tags across resources

There are several endpoints you can use to retrieve vocabularies and their details, independently from the resources to which they are associated

Getting all vocabularies

Getting all vocabularies, their resources and tags

curl -X GET https://api.resourcewatch.org/v1/vocabulary

Example response

{
    "data": [
        {
            "id": "test1",
            "type": "vocabulary",
            "attributes": {
                "resources": [
                    {
                        "tags": [
                            "tag1",
                            "tag2"
                        ],
                        "id": "7fa6ec77-5ab0-43f4-9a4c-a3d19bed1e90",
                        "dataset": "7fa6ec77-5ab0-43f4-9a4c-a3d19bed1e90",
                        "type": "dataset"
                    },
                    {
                        "tags": [
                            "tag1",
                            "tag2"
                        ],
                        "id": "0002ed77-f07d-4231-b4eb-cfda77eeafe5",
                        "dataset": "7fa6ec77-5ab0-43f4-9a4c-a3d19bed1e90",
                        "type": "layer"
                    },
                    {
                        "tags": [
                            "tag1",
                            "tag2"
                        ],
                        "id": "0002ed77-f07d-4231-b4eb-cfda77eeafe5",
                        "dataset": "7fa6ec77-5ab0-43f4-9a4c-a3d19bed1e91",
                        "type": "layer"
                    }
                ],
                "name": "test1",
                "application": "rw"
            }
        },
        {
            "id": "forestChange",
            "type": "vocabulary",
            "attributes": {
                "resources": [],
                "name": "forestChange",
                "application": "gfw"
            }
        }
    ]
}

This endpoint will give you a list of vocabularies. Inside each, you'll find a list of resources, identifying the resource id, type, associated dataset (if the resource is a dataset, the dataset id will be equal to the resource id)and the tags that said vocabulary associates to that resource

You can optionally pass a limit integer value as a query parameter if you wish to limit the number of vocabularies returned by calls to this endpoint. There is not full blown pagination support for this endpoint.

Getting a single vocabulary

Getting a single vocabulary, all its resources and tags

curl -X GET https://api.resourcewatch.org/v1/vocabulary/<vocabulary-id>

Example response

{
    "data": [
        {
            "id": "test1",
            "type": "vocabulary",
            "attributes": {
                "resources": [
                    {
                        "tags": [
                            "tag1",
                            "tag2"
                        ],
                        "id": "7fa6ec77-5ab0-43f4-9a4c-a3d19bed1e90",
                        "dataset": "7fa6ec77-5ab0-43f4-9a4c-a3d19bed1e90",
                        "type": "dataset"
                    },
                    {
                        "tags": [
                            "tag1",
                            "tag2"
                        ],
                        "id": "0002ed77-f07d-4231-b4eb-cfda77eeafe5",
                        "dataset": "7fa6ec77-5ab0-43f4-9a4c-a3d19bed1e90",
                        "type": "layer"
                    },
                    {
                        "tags": [
                            "tag1",
                            "tag2"
                        ],
                        "id": "0002ed77-f07d-4231-b4eb-cfda77eeafe5",
                        "dataset": "7fa6ec77-5ab0-43f4-9a4c-a3d19bed1e91",
                        "type": "layer"
                    }
                ],
                "name": "test1",
                "application": "rw"
            }
        }
    ]
}

This endpoint will give you the details for a single vocabulary, identified by name. In it, you'll find a list of resources, identified by the resource id, type, associated dataset (if the resource is a dataset, the dataset id will be equal to the resource id) and the tags that said vocabulary associates to that resource.

Keep in mind that there's an implicit application filter applied to the data returned - only vocabularies and associations for the corresponding application are returned. By default, this filter uses the rw value, but you can modify it with the application or app query parameters.

Getting tags for single vocabulary

Getting the tags for a single vocabulary

curl -X GET https://api.resourcewatch.org/v1/vocabulary/<vocabulary-id>/tags

Example response

{
    "data": [
        "tag11",
        "tag21",
        "tag1",
        "tag2"
    ]
}

This endpoint will give you a flat list of all the tags associated with the specified vocabulary.

Keep in mind that there's an implicit application filter applied to the data returned - only tags for the corresponding application are returned. By default, this filter uses the rw value, but you can modify it with the application or app query parameters.

Getting resources by vocabulary and tag

Getting datasets by vocabulary and tag

curl -X GET https://api.resourcewatch.org/v1/dataset/vocabulary/find?<vocabulary-id>=<tag>

Getting widgets by vocabulary and tag

curl -X GET https://api.resourcewatch.org/v1/dataset/<dataset-id>/widget/vocabulary/find?<vocabulary-id>=<tag>

Getting layers by vocabulary and tag

curl -X GET https://api.resourcewatch.org/v1/dataset/<dataset-id>/layer/vocabulary/find?<vocabulary-id>=<tag>

Example response

{
    "data": [
        {
            "type": "vocabulary",
            "attributes": {
                "resources": [
                    {
                        "id": "7fa6ec77-5ab0-43f4-9a4c-a3d19bed1e90",
                        "dataset": "7fa6ec77-5ab0-43f4-9a4c-a3d19bed1e90",
                        "type": "dataset"
                    },
                    {
                        "id": "7fa6ec77-5ab0-43f4-9a4c-a3d19bed1e92",
                        "dataset": "7fa6ec77-5ab0-43f4-9a4c-a3d19bed1e92",
                        "type": "dataset"
                    }
                ]
            }
        }
    ]
}

This is perhaps the most useful endpoint when it comes to data discovery - it allows you to specify a vocabulary name and a tag or set of tags, and see resources that match that search criteria.

All three endpoints require at least one query parameter, in the format <vocabulary-id>=<tag>. This will return all resources of that type, associated with a vocabulary with the name vocabulary-id, and having a tag with value tag for that vocabulary.

You can expand these filters by specifying multiple tags for a single vocabulary, using the <vocabulary-id>=<tag1>,<tag2> syntax. This type of filter will return resources that have either tag1 or tag2 for vocabulary vocabulary-id

You can also filter by multiple vocabularies using multiple query parameters with the formats described above. The result will contain any resource that matches either vocabulary/tags filters.

The filters described above do not take into account the application for which the vocabularies were defined. If you wish to only see results matching the vocabulary of a specific application, you can pass either an app or application query parameter with the value of the application you wish to filter by.

Errors for getting resources by vocabulary and tag

Error code Error message Description
400 Vocabulary and Tags are required in the queryParams You must specify at least one vocabulary/tag to filter by.

Geostore

What is Geostore

If you are new to the RW API, or want to learn more about the concept of a geostore, we strongly encourage you to read the geostore concept documentation first. It gives you a brief and clear description of what a geostore is, and what it can do for you.

Once you've read that section, you can come back here to learn more details about using the RW API Geostore feature, which aims to provide a comprehensive way to communicate geographic vector-data structures described using GeoJSON between platforms and microservices.

Geostore objects, describing things like the boundaries of countries, protected areas or land use types, have been uploaded by WRI, its partner organizations, or by API users like you. They are particularly useful for combining with the range of datasets available in the RW API, for example to create national summaries or for making a specific analysis within your own user-defined region.

To find out more about accessing the geostore objects already available on the RW API, check out the documentation on getting geostore objects. A quick, visual way to view an existing geostore is by using the /geostore/:id/view endpoint.

You can also create you own geostore objects on the RW API, if you'd like to share your data with the world, or if you are looking to use the RW API and its features to gain insights into your data.

What are Geostore objects

Geostore objects contain GeoJSON FeatureCollection objects (geojson), with a single Feature whose Geometry has been checked for geometric validity, and have been assigned an identifier (id, hash) upon creation.

This identifier is a 128-bit hash generated by passing the pre-processed GeoJSON string through the MD5 message-digest algorithm. This means that each identifier is a unique fingerprint of the GeoJSON string.

If you add an exact copy of your GeoJSON string, it will generate the same hash. But if any GeoJSON property is changed in any way, the generated hash will be different. Hence, the Geostore identifier provides the RW API a way to ensure that platforms and microservices are using exactly the same geographic structures. This also means that Geostore objects are static and cannot be modified.

To prevent overwriting of existing geostore objects, they contain a field indicated if the object is locked to editing (lock); which can be set when creating geostore objects.

Also, during object creation the minimum bounding box enclosing all geometries in the GeoJSON (bbox), and, if the geometries are type (Multi) Polygon, total surface area in hectares of the geometries (areaHa) are added to the geostore. Note these values are not calculated if supplied when creating a geostore.

Geostore objects can also be created by getting a GeoJSON from provider API; in which case the geostore will also include an object which gives information used to connect to the provider data source (provider). At present the only provider definition supported is a Carto table, using "type": "carto".

Finally, all geostore objects have a property for storing application specific attributes (info), which has no formalized schema. Here, fields used for indexing, and metadata, related to use on different platforms are added.

Overview of a geostore object

Field Type Description
id string A unique identifier for the geostore object in the form of a 128 bit MD5 hash generated from the GeoJSON object.
hash string A unique identifier for the geostore object in the form of a 128 bit MD5 hash generated from the GeoJSON object.
geojson object A valid FeatureCollection, Feature, or Geometry GeoJSON object.
provider object Optional provider definition used to fetch GeoJSON data from APIs.
lock string Optional indication if the object is locked for editing
areaHa number Optional total surface area in hectares of all Polygon and MultiPolygon geometries in the GeoJSON object.
bbox array Array describing the minimum bounding box enclosing all of the geometries in the GeoJSON object, expressed as an array of the form min Longitude , min Latitude , max Longitude , max Latitude.
info object Object that defines application specific properties, for example used for indexing or related to editing of the geostore object.

Overview of available endpoints

The Geostore API consists of a number of endpoints to help users interact with geostore objects. Many of them are essentially helpers to make it easy to access geometries from useful data sources, such as:

As these data sets are periodically updated, these "helper" endpoints are updated to use the latest data. So unless you really need an older version of a data set, such as GADM, you should always use the latest endpoint version. See the table below to get an overview of what can be done; click on the description to get more details.

Comparison of endpoint versions

Version Description
v1 GADM version 2.8.
v2 GADM version 3.6.

Overview of endpoints

Method Path Description
POST /v1/geostore Create a geostore object
GET /v2/geostore/:id Get a geostore object by Geostore id
POST /v2/geostore/find-by-ids Get geostore objects by Geostore ids
GET /v2/geostore/:id/view Get a geostore object by Geostore id and view at GeoJSON.io
GET /v2/geostore/admin/list Get all Geostore ids, names and country codes
GET /v2/geostore/admin/:iso Get a geostore object by country code
GET /v2/geostore/admin/:iso/:id1 Get a geostore object by country code and GADM admin 1 id
GET /v2/geostore/admin/:iso/:id1/:id2 Get a geostore object by country code, GADM admin 1 and admin 2 ids
GET /v2/geostore/wdpa/:id Get a geostore object by WDPA id
GET /v2/geostore/use/:name/:id Get a geostore object by Land Use Type name and id
POST /v1/geostore/area Calculate the area of a provided Geostore object

Create a geostore object

Geostore objects can be created in the RW API Geostore using a valid GeoJSON object or by selecting a row from a Carto table.

Errors for creating a geostore object

Error code Error message Description
400 <field>: <field> can not be empty Your are missing a required field value.
400 <field>: empty or invalid <field> The provided value for <field> is invalid. This is usually happens if an invalid value type is provided, but certain fields use more advanced validation rules, that may produce this error message if validation fails (ie: geojson, which must be type: FeatureCollection, Feature, or Geometry).
400 provider: must be valid Your provider type value is invalid. The <list of valid providers> will contain the list of providers that are supported.

Create using a GeoJSON

Geostore objects can be created via the POST geostore endpoint, which accepts as body a GeoJSON object (<geojson>). This must be a FeatureCollection, Feature or Geometry. If the object is correctly added to the Geostore a 200 response is returned, as well as the new geostore object.

Example request pattern

curl -X POST https://api.resourcewatch.org/v1/geostore/ \
     -H "Content-Type: application/json" \
     -d '{"geojson": <geojson>}'

Example URL request

curl --location --request POST 'https://api.resourcewatch.org/v1/geostore' \
--header 'Content-Type: application/json' \
--data-raw '{
   "geojson":{
      "type":"FeatureCollection",
      "features":[
         {
            "type":"Feature",
            "properties":{

            },
            "geometry":{
               "type":"Polygon",
               "coordinates":[
                  [
                     [
                        -4.4549560546875,
                        40.84706035607122
                     ],
                     [
                        -4.4549560546875,
                        41.30257109430557
                     ],
                     [
                        -3.5211181640624996,
                        41.30257109430557
                     ],
                     [
                        -3.5211181640624996,
                        40.84706035607122
                     ],
                     [
                        -4.4549560546875,
                        40.84706035607122
                     ]
                  ]
               ]
            }
         }
      ]
   }
}'

Example response

{
    "data": {
        "type": "geoStore",
        "id": "4b25676360d8bbd5106a022103e0cd28",
        "attributes": {
            "geojson": {
                "crs": {},
                "type": "FeatureCollection",
                "features": [
                    {
                        "geometry": {
                            "coordinates": [
                                [
                                    [
                                        -4.454956055,
                                        40.847060356
                                    ],
                                    [
                                        -4.454956055,
                                        41.302571094
                                    ],
                                    [
                                        -3.521118164,
                                        41.302571094
                                    ],
                                    [
                                        -3.521118164,
                                        40.847060356
                                    ],
                                    [
                                        -4.454956055,
                                        40.847060356
                                    ]
                                ]
                            ],
                            "type": "Polygon"
                        },
                        "type": "Feature"
                    }
                ]
            },
            "hash": "4b25676360d8bbd5106a022103e0cd28",
            "provider": {},
            "areaHa": 397372.34118232,
            "bbox": [
                -4.454956055,
                40.847060356,
                -3.521118164,
                41.302571094
            ],
            "lock": false,
            "info": {
                "use": {}
            }
        }
    }
}

Create using a provider definition

Geostore objects can be created via the POST geostore endpoint, which accepts as body a provider definition object (<provider>), the API then fetches a GeoJSON from the provider, and adds it to the Geostore. If the object is correctly added to the Geostore a 200 response is returned, as well as the new geostore object. At present the only provider definition supported is a Carto table, using "type": "carto".

If the specified table, user, or filter is not recognized a 400 response is returned with the error message "Geojson not found".

Overview of provider object

Field Type Description
type string Keyword of the provider
table string Name of the provider table
user string Provider username
filter string Provider specific filter

Example request pattern

curl -X POST https://api.resourcewatch.org/v1/geostore \
-H "Content-Type: application/json" \
-d '{"provider": <provider>}'

Example URL request

curl -X POST https://api.resourcewatch.org/v1/geostore \
-H "Content-Type: application/json" \
-d '{
        "provider":{
            "type": "carto",
            "table": "gfw_mining",
            "user": "wri-01",
            "filter": "cartodb_id=573"
        }
    }'

Example response

{
  "data": {
    "type": "geoStore",
    "id": "b3b2875affa75f145b4f3e5289fd47d7",
    "attributes": {
      "geojson": {
        "crs": {},
        "type": "FeatureCollection",
        "features": [
          {
            "geometry": {
              "coordinates": [
                [
                  14.26438308756265,
                  14.062500000000002
                ],
                [
                  5.266007882805498,
                  2.8125
                ],
                [
                  44.84029065139799,
                  16.523437500000004
                ],
                [
                  -7.362466865535738,
                  -3.1640625000000004
                ],
              ],
              "type": "MultiPoint"
            },
            "type": "Feature",
            "properties": null
          }
        ]
      },
      "hash": "b3b2875affa75f145b4f3e5289fd47d7",
      "provider": {
        "type": "carto",
        "table": "gfw_mining",
        "user": "wri-01",
        "filter": "cartodb_id=573"
      },
      "areaHa": 0,
      "bbox": [
        -102.65625,
        -29.688052749856787,
        45.87890625,
        57.79794388498275
      ],
      "lock": false,
      "info": {
        "use": {}
      }
    }
  }
}

Getting geostore objects

The fundamental way to read geometries from the RW APIs Geostore is by using Geostore ids. Using these identifiers you can ensure that you are always retrieving exactly the same Feature. If you add your own geostore objects you will be using these endpoints.

Alternatively you may prefer to get selected geometries from the datasets already added to the RW API Geostore, such as the latest administrative areas, protected areas, or land use types. Note, these are periodically updated, and potentially both geometries and ids may change between versions. By design this means that, for example, the Geostore ids of countries change between versions. These geometries can also be simplified when reading them from the Geostore, using the parameter ?simplify=<value>, where <value> is given to the simplification algorithm - 0.005 usually works well.

Get a geostore object by Geostore id

Geostore objects can be retrieved via the GET geostore/:id endpoint, which returns a single object selected from the Geostore using a single Geostore id (<id>).

Example request pattern

curl -X GET https://api.resourcewatch.org/v2/geostore/<id>

Example URL request

curl -X GET https://api.resourcewatch.org/v2/geostore/ca38fa80a4ffa9ac6217a7e0bf71e6df

Example response

{
    "data": {
        "type": "geoStore",
        "id": "ca38fa80a4ffa9ac6217a7e0bf71e6df",
        "attributes": {
            "geojson": {
                "crs": {},
                "type": "FeatureCollection",
                "features": [
                    {
                        "type": "Feature",
                        "geometry": {
                            "type": "Polygon",
                            "coordinates": [
                                [
                                    [
                                        -5.273512601852417,
                                        42.81137220349083
                                    ],
                                    [
                                        -5.273512601852417,
                                        42.811803118457306
                                    ],
                                    [
                                        -5.272732079029083,
                                        42.811803118457306
                                    ],
                                    [
                                        -5.272732079029083,
                                        42.81137220349083
                                    ],
                                    [
                                        -5.273512601852417,
                                        42.81137220349083
                                    ]
                                ]
                            ]
                        }
                    }
                ]
            },
            "hash": "ca38fa80a4ffa9ac6217a7e0bf71e6df",
            "provider": {},
            "areaHa": 0.3057556230214663,
            "bbox": [
                -5.273512601852417,
                42.81137220349083,
                -5.272732079029083,
                42.811803118457306
            ],
            "lock": false,
            "info": {
                "use": {}
            }
        }
    }
}

Errors for getting geostore objects by id

Error code Error message Description
404 Geostore not found. A geostore with the id provided was not found.

Get geostore by Geostore id and view at GeoJSON.io

Geostore objects can be retrieved and viewed via the GET geostore/:id/view endpoint, which returns a URL allowing viewing of a single geostore object selected by Geostore id (<id>) at GeoSON.io.

Example request pattern

curl -X GET https://api.resourcewatch.org/v2/geostore/<id>/view

Example URL request

curl -X GET https://api.resourcewatch.org/v2/geostore/ca38fa80a4ffa9ac6217a7e0bf71e6df/view

Example response

{
    "view_link": "http://geojson.io/#data=data:application/json,%7B%22crs%22%3A%7B%7D%2C%22type%22%3A%22FeatureCollection%22%2C%22features%22%3A%5B%7B%22type%22%3A%22Feature%22%2C%22geometry%22%3A%7B%22type%22%3A%22Polygon%22%2C%22coordinates%22%3A%5B%5B%5B-5.273512601852417%2C42.81137220349083%5D%2C%5B-5.273512601852417%2C42.811803118457306%5D%2C%5B-5.272732079029083%2C42.811803118457306%5D%2C%5B-5.272732079029083%2C42.81137220349083%5D%2C%5B-5.273512601852417%2C42.81137220349083%5D%5D%5D%7D%2C%22properties%22%3Anull%7D%5D%7D"
}

Errors for viewing geostore objects by id

Error code Error message Description
400 Geometry too large, please try again with a smaller geometry. The Geostore provided is too large (more than 150k chars when stringified) and cannot be viewed.
404 Geostore not found. A geostore with the id provided was not found.

Get geostore objects by Geostore ids

Many geostore objects can be retrieved via the POST geostore/find-by-ids endpoint, which returns an array of a geostore objects selected by an array of Geostore ids ([<id>, <id>]). In case of success, the returned response will contain an array with all of the geostore objects found and summary info is available in the root property info.

Example request pattern

curl -X POST https://api.resourcewatch.org/v2/geostore/find-by-ids \
     -H "Content-Type: application/json" \
     -d '{"geostores": [<id>, <id>]}'

Example URL request

curl -X POST https://api.resourcewatch.org/v2/geostore/find-by-ids \
     -H "Content-Type: application/json" \
     -d '{"geostores": ["35a6d982388ee5c4e141c2bceac3fb72", "8f77fe62cf15d5098ba0ee11c5126aa6"]}'

Example response (coordinates are truncated)

{
    "data": [
        {
            "geostoreId": "35a6d982388ee5c4e141c2bceac3fb72",
            "geostore": {
                "data": {
                    "type": "geoStore",
                    "id": "35a6d982388ee5c4e141c2bceac3fb72",
                    "attributes": {
                        "geojson": {
                            "crs": {},
                            "type": "FeatureCollection",
                            "features": [
                                {
                                    "geometry": {
                                        "coordinates": [
                                            ...
                                        ],
                                        "type": "MultiPolygon"
                                    },
                                    "type": "Feature"
                                }
                            ]
                        },
                        "hash": "35a6d982388ee5c4e141c2bceac3fb72",
                        "provider": {},
                        "areaHa": 50662609.25209112,
                        "bbox": [
                            -18.1604175567627,
                            27.6384716033936,
                            4.32819509506226,
                            43.7915267944337
                        ],
                        "lock": false,
                        "info": {
                            "use": {},
                            "iso": "ESP",
                            "name": "Spain"
                        }
                    }
                }
            }
        },
        {
            "geostoreId": "8f77fe62cf15d5098ba0ee11c5126aa6",
            "geostore": {
                "data": {
                    "type": "geoStore",
                    "id": "8f77fe62cf15d5098ba0ee11c5126aa6",
                    "attributes": {
                        "geojson": {
                            "crs": {},
                            "type": "FeatureCollection",
                            "features": [
                                {
                                    "geometry": {
                                        "coordinates": [
                                            ...
                                        ],
                                        "type": "MultiPolygon"
                                    },
                                    "type": "Feature"
                                }
                            ]
                        },
                        "hash": "8f77fe62cf15d5098ba0ee11c5126aa6",
                        "provider": {},
                        "areaHa": 54935531.53854849,
                        "bbox": [
                            -5.14375114440907,
                            41.3337516784668,
                            9.5604162216186,
                            51.08939743042
                        ],
                        "lock": false,
                        "info": {
                            "use": {},
                            "iso": "FRA",
                            "name": "France"
                        }
                    }
                }
            }
        }
    ],
    "info": {
        "found": 2,
        "foundIds": [
            "35a6d982388ee5c4e141c2bceac3fb72",
            "8f77fe62cf15d5098ba0ee11c5126aa6"
        ],
        "returned": 2
    }
}

Errors for getting multiple geostore objects by id

Error code Error message Description
404 Geostore not found. A geostore with the id provided was not found.

Get all Geostore ids, names and country codes

All of the Geostore ids, names, and country ISO 3166-1 alpha-3 code values available from the GADM data source in the Geostore can be retrieved via the GET geostore/admin/list endpoint, which returns an array of objects with the properties geostoreId, name, and iso.

Example URL request

curl -X GET https://api.resourcewatch.org/v2/geostore/admin/list

Example response

{
    "data": [{
        "geostoreId": "35a6d982388ee5c4e141c2bceac3fb72",
        "iso": "ESP",
        "name": "Spain"
    }, {
        "geostoreId": "8f77fe62cf15d5098ba0ee11c5126aa6",
        "iso": "FRA",
        "name": "France"
    }, {
        "geostoreId": "1d568c183033da6c17cc28c4aecf1bcf",
        "iso": "cod",
        "name": "Democratic Republic of the Congo"
    }]
}

Note - This endpoint does not return a unique array of iso codes and names.

Getting predefined geostores for commonly used geometries

The endpoints described below allow API users to retrieve geostores representative of the boundaries of countries, GADM admin regions, WDPA and land use areas. These endpoints can be used as utility methods to retrieve commonly used geometries.

Get geostore by country code

Example request pattern

curl -X GET https://api.resourcewatch.org/v2/geostore/admin/<iso>

Example URL request

curl -X GET https://api.resourcewatch.org/v2/geostore/admin/ESP

Example response (note coordinates are truncated)

{
    "data": {
        "type": "geoStore",
        "id": "56f9a919e061d5edd10c042a8fcd31b6",
        "attributes": {
            "geojson": {
                "crs": {},
                "type": "FeatureCollection",
                "features": [
                    {
                        "geometry": {
                            "coordinates": [
                                ...
                            ],
                            "type": "MultiPolygon"
                        },
                        "type": "Feature",
                        "properties": null
                    }
                ]
            },
            "hash": "56f9a919e061d5edd10c042a8fcd31b6",
            "provider": {},
            "areaHa": 50662609.2516529,
            "bbox": [
                -18.160417557,
                27.638471603,
                4.328195095,
                43.791526794
            ],
            "lock": false,
            "info": {
                "use": {},
                "iso": "ESP",
                "id1": null,
                "id2": null,
                "gadm": "2.8",
                "name": "Spain"
            }
        }
    }
}

Use the GET geostore/admin/:iso endpoint to retrieve a geostore object representative of the boundaries of the country with ISO 3166-1 alpha-3 code (<iso>). The returned geometries can be simplified using the parameter ?simplify=<value>. Where <value> is given to the simplification algorithm- 0.005 usually works well.

Note - The source of the geometries is GADM version 3.6.

Errors for getting geostore objects by country code

Error code Error message Description
404 Geostore not found. A geostore for the country ISO code provided was not found.

Get geostore by country code and GADM admin 1 id

Example request pattern

curl -X GET https://api.resourcewatch.org/v2/geostore/admin/<iso>/<id1>

Example URL request

curl -X GET https://api.resourcewatch.org/v2/geostore/admin/ESP/9

Example response (note coordinates are truncated)

{
    "data": {
        "type": "geoStore",
        "id": "7d1534d7c24b2f907c4ae37d11fc51fe",
        "attributes": {
            "geojson": {
                "crs": {},
                "type": "FeatureCollection",
                "features": [
                    {
                        "geometry": {
                            "coordinates": [
                                ...
                            ],
                            "type": "MultiPolygon"
                        },
                        "type": "Feature",
                        "properties": null
                    }
                ]
            },
            "hash": "7d1534d7c24b2f907c4ae37d11fc51fe",
            "provider": {},
            "areaHa": 1036273.8136673134,
            "bbox": [
                -2.500030994,
                41.909896851,
                -0.726752043,
                43.314189911
            ],
            "lock": false,
            "info": {
                "use": {},
                "iso": "ESP",
                "id1": 9,
                "id2": null,
                "gadm": "2.8"
            }
        }
    }
}

Use the GET geostore/admin/:iso/:id1 endpoint to retrieve a geostore object representative of the boundaries of a ISO 3166-1 alpha-3 code (<iso>) and GADM admin level 1 id (<id1>). The returned geometries can be simplified using the parameter ?simplify=<value>. Where <value> is given to the simplification algorithm- 0.005 usually works well.

Note - The source of the geometries is GADM version 3.6.

Errors for getting geostore objects by country code and GADM admin 1 id

Error code Error message Description
404 Geostore not found. A geostore for the combination of country ISO code and GADM admin 1 id provided was not found.

Get geostore by country code, GADM admin 1 and admin 2 ids

Example request pattern

curl -X GET https://api.resourcewatch.org/v2/geostore/admin/<iso>/<id1>/<id2>

Example URL request

curl -X GET https://api.resourcewatch.org/v2/geostore/admin/ESP/1/2

Example response

{
    "data": {
        "type": "geoStore",
        "id": "214e74a9e8702f78354ed5cb0297c10d",
        "attributes": {
            "geojson": {
                "crs": {},
                "features": [
                    {
                        "geometry": {
                            "coordinates": [...],
                            "type": "MultiPolygon"
                        },
                        "properties": null,
                        "type": "Feature"
                    }
                ],
                "type": "FeatureCollection"
            },
            "hash": "214e74a9e8702f78354ed5cb0297c10d",
            "provider": {},
            "areaHa": 744195.8099038196,
            "bbox": [
                -6.47347212,
                35.9995842,
                -5.08662891,
                37.05246735
            ],
            "lock": false,
            "info": {
                "use": {},
                "simplifyThresh": 0.00005,
                "gadm": "3.6",
                "name": "Cádiz",
                "id2": 2,
                "id1": 1,
                "iso": "ESP"
            }
        }
    }
}

Use the GET geostore/admin/:iso/:id1/:id2 endpoint to retrieve a geostore object representative of the boundaries of a ISO 3166-1 alpha-3 code (<iso>), GADM admin level 1 id (<id1>), and GADM admin level 2 id (<id2>). The returned geometries can be simplified using the parameter ?simplify=<value>. Where <value> is given to the simplification algorithm- 0.005 usually works well.

Note - The source of the geometries is GADM version 3.6.

Errors for getting geostore objects by country code, GADM admin 1 id and admin 2 id

Error code Error message Description
404 Geostore not found. A geostore for the combination of country ISO code, GADM admin 1 id and admin 2 id provided was not found.

Get geostore by World Database on Protected Areas id

Example request pattern

curl -X GET https://api.resourcewatch.org/v2/geostore/wdpa/<id>

Example URL request

curl -X GET https://api.resourcewatch.org/v2/geostore/wdpa/142809

Example response (note coordinates are truncated)

{
    "data": {
        "type": "geoStore",
        "id": "88db597b6bcd096fb80d1542cdc442be",
        "attributes": {
            "geojson": {
                "crs": {},
                "type": "FeatureCollection",
                "features": [
                    {
                        "geometry": {
                            "coordinates": [
                                ...
                                ],
                            "type": "MultiPolygon"
                        },
                        "type": "Feature",
                        "properties": null
                    }
                ]
            },
            "hash": "88db597b6bcd096fb80d1542cdc442be",
            "provider": {},
            "areaHa": 5081.838068566336,
            "bbox": [
                -6.031685272,
                36.160220287,
                -5.879245686,
                36.249656987
            ],
            "lock": false,
            "info": {
                "use": {},
                "wdpaid": 142809
            }
        }
    }
}

Use the GET geostore/admin/wdpa/:id endpoint to retrieve a geostore object representative of the boundaries of a World Database on Protected Areas (WDPA) with id (<id>) provided. To find valid WDPA id values check the link above.

Note marine protected areas are NOT included

Errors for getting geostore objects by WDPA id

Error code Error message Description
404 Geostore not found. A geostore for the WDPA id provided was not found.

Get geostore by Land Use Type keyword and id

Example request pattern

curl -X GET https://api.resourcewatch.org/v2/geostore/use/<name>/<id>

Example URL request

curl -X GET https://api.resourcewatch.org/v2/geostore/use/logging/1

Example response (note coordinates are truncated)

{
    "data": {
        "type": "geoStore",
        "id": "bd5feac1b0dd4e73f3a1553889807622",
        "attributes": {
            "geojson": {
                "crs": {},
                "type": "FeatureCollection",
                "features": [
                    {
                        "geometry": {
                            "coordinates": [...],
                            "type": "MultiPolygon"
                        },
                        "type": "Feature",
                        "properties": null
                    }
                ]
            },
            "hash": "bd5feac1b0dd4e73f3a1553889807622",
            "provider": {},
            "areaHa": 45978.43408272762,
            "bbox": [
                102.691404026,
                -0.248440312,
                103.036606,
                -0.071735991
            ],
            "lock": false,
            "info": {
                "use": {
                    "use": "gfw_logging",
                    "id": 1
                },
                "simplify": false
            }
        }
    }
}

Use the GET geostore/admin/use/:name/:id endpoint to retrieve a geostore object representative of the boundaries of a Land Use Type keyword (<name>) and Land Use Type object id (<id>).

Geostore objects for five land use types are available:

The returned geometries can be simplified using the parameter ?simplify=<value>. Where <value> is given to the simplification algorithm- 0.005 usually works well.

Note - each of the land use types actually represents an individual dataset, each with different geographical extents and temporal coverage, see the dataset urls for details

Errors for getting geostore objects by land use type

Error code Error message Description
404 Geostore not found. A geostore for the specified <name> and <id> was not found.

Calculate the area of a geostore object

If you have a GeoJSON geometry and you intend to know the area that your geometry occupies or what is the bounding box for your geometry, you can use the POST v2/geostore/area endpoint to calculate the area of your geometry.

Example request pattern

curl -X POST https://api.resourcewatch.org/v2/geostore/area \
  -d '{"geojson": <geojson>}'

Example URL request

curl -X POST https://api.resourcewatch.org/v2/geostore/area \
  -d '{
      "geojson":{
        "type": "Polygon",
        "coordinates": [
            [
                [-0.1758,51.2894],
                [8.4375,51.1793],
                [6.8555,47.5172],
                [-0.1758,51.2894]
            ]
        ]
    }}'

Example response:

{
    "data": {
        "type": "geomArea",
        "attributes": {
            "bbox": [
                -0.1758,
                47.5172,
                8.4375,
                51.2894
            ],
            "areaHa": 12797498.414088473
        }
    }
}

Errors for calculating the area of a geostore object

Error code Error message Description
400 geojson, esrijson or provider required. You need to provide the GeoJSON for the geometry you intend to calculate the area.

Subscriptions

What is a subscription?

Note: We strongly recommend that you read the dataset concept and dataset endpoints sections before proceeding.

A subscription allows you to get notified of updates on a datasets' data - either for every update, or for updates restricted to geographical areas of your interest. For example, you can use subscriptions to subscribe to deforestation alerts (GLAD alerts dataset) in the Amazon forest, or track fire alerts (VIIRS fire alerts dataset) in your area of residence.

In the following sections, we will cover how you can interact and manage subscriptions in the RW API. We will see how you can customize subscriptions so that we only get notified for changes in a dataset's data for specific geographic regions. You will learn how to use them to get notified via email or calls to a URL you provide. We will also dive into subscription lifecycle, and understand how we can confirm subscriptions, resend confirmation emails and how to unsubscribe and stop receiving notifications.

Subscription lifecycle

In this section, you will learn about the lifecycle of a subscription. This will help you understand how you can best use subscriptions to meet your goals. The first step for using subscriptions is understanding which data you want to subscribe - for this, we recommend searching the existing datasets in the WRI API (or maybe even creating a new one). Once you are certain of the dataset you wish to subscribe, the next step is ensuring that this dataset is subscribable.

Subscribable datasets

Example of a subscribable dataset

{
  "name": "Example dataset",
  "application": ["app"],
  "provider": "carto",
  ...
  "subscribable": {
    "test": {
      "dataQuery": "SELECT * FROM dataset-name  WHERE 'reported_date' >= '{{begin}}' AND 'reported_date' <= '{{end}}' AND 'number_dead' > 0 ORDER BY reported_date DESC LIMIT 10",
      "subscriptionQuery": "SELECT COUNT(*) FROM dataset-name WHERE 'reported_date' >= '{begin}' AND 'reported_date' <= '{end}' AND 'number' > 0"
    }
  }
}

While you can create a subscription for any dataset, some conditions must be met by the dataset for its corresponding subscriptions to be functional and actually work as described here.

In order to support a functional subscription, a dataset must have some queries defined in its subscribable property. In this property, of type object, one (or many) sub-objects should be declared. Please note that you can define multiple keys in the subscribable object, and each key will be evaluated separately and trigger its own updates. Each object inside the subscribable property must define two queries:

The example on the side defines the subscribable object for an example dataset, and this object contains a the key test, including both a dataQuery and a subscriptionQuery. For more details on how you can modify the subscribable property of a dataset, check out the documentation on updating a dataset. The keys in the subscribable object (e.g. test) are just for organizational purposes, and they won't be used in any way from the subscription's perspective.

Both queries can contain two special keywords: {begin} and {end}. These will be replaced with ISO-formatted dates on runtime, with the datetime in which the subscription was last evaluated, and the datetime at the time of evaluation, respectively.

Please note that, for readability purposes, the special characters in example on the side are not properly escaped. Don't forget all special characters must be properly escaped for the queries to be correctly executed.

Creating and confirming the subscription

You have your dataset ready to be subscribed. The next steps would be to actually create the subscription - check the docs for creating subscriptions for detailed information on how to do that.

After creating the subscription, an email is sent with a confirmation link. You need to click this link in order to confirm the notification and start receiving notifications. You can check if the subscription is confirmed or not by looking at the confirmed field of the subscription object. Check more information about confirming subscriptions in the confirming a subscription section.

If, for some reason, you have lost the confirmation email, you can check the resending confirmation emails section for more information on how to resend the confirmation email.

At any point, you might want to stop receiving email or webhook notifications - if that is the case, you can check the unsubscribing section for details on how to stop receiving notifications for your subscriptions.

The same subscription can subscribe to multiple datasets - for that, you just need to provide all the dataset ids you intend to subscribe in either the datasets or datasetsQuery fields of the subscription on creation. However, a subscription can only notify a single email at a time - if you intend to receive subscription notifications on multiple emails, you'll need to create multiple subscriptions.

How are subscription notifications sent?

Example of POST body data for a webhook notification:

{
  "value": 5,
  "downloadUrls": {
    "csv": "https://production-api.globalforestwatch.org/glad-alerts/download/?period=2020-02-22,2020-03-04&gladConfirmOnly=False&aggregate_values=False&aggregate_by=False&geostore=423e5dfb0448e692f97b590c61f45f22&format=csv",
    "json": "https://production-api.globalforestwatch.org/glad-alerts/download/?period=2020-02-22,2020-03-04&gladConfirmOnly=False&aggregate_values=False&aggregate_by=False&geostore=423e5dfb0448e692f97b590c61f45f22&format=json"
  },
  "alerts": [
    {
      "alert_type": "GLAD",
      "date": "10/10/2019 00:10 UTC"
    },
    {
      "alert_type": "GLAD",
      "date": "11/10/2019 00:10 UTC"
    },
    {
      "alert_type": "GLAD",
      "date": "12/10/2019 00:10 UTC"
    },
    {
      "alert_type": "GLAD",
      "date": "13/10/2019 00:10 UTC"
    },
    {
      "alert_type": "GLAD",
      "date": "14/10/2019 00:10 UTC"
    },
    {
      "alert_type": "GLAD",
      "date": "15/10/2019 00:10 UTC"
    }
  ],
  "layerSlug": "glad-alerts",
  "alert_name": "Subscription for Amazônia, Brazil",
  "selected_area": "Amazônia, Brazil",
  "unsubscribe_url": "https://production-api.globalforestwatch.org/subscriptions/5ea996383efbd0119327b372/unsubscribe?redirect=true&lang=en",
  "subscriptions_url": "https://www.globalforestwatch.org/my-gfw?lang=en",
  "dashboard_link": "https://www.globalforestwatch.org/dashboards/aoi/5ea996383efbd0119327b372?lang=en",
  "alert_link": "https://www.globalforestwatch.org/map/aoi/5ea996383efbd0119327b372?lang=en&map%5BcanBound%5D=true&map%5Bdatasets%5D%5B0%5D%5Bdataset%5D=bfd1d211-8106-4393-86c3-9e1ab2ee1b9b&map%5Bdatasets%5D%5B0%5D%5Blayers%5D%5B0%5D=8e4a527d-1bcd-4a12-82b0-5a108ffec452&map%5Bdatasets%5D%5B0%5D%5BtimelineParams%5D%5BstartDate%5D=2020-04-15&map%5Bdatasets%5D%5B0%5D%5BtimelineParams%5D%5BendDate%5D=2020-04-22&map%5Bdatasets%5D%5B0%5D%5BtimelineParams%5D%5BtrimEndDate%5D=2020-04-22&map%5Bdatasets%5D%5B1%5D%5Bdataset%5D=0b0208b6-b424-4b57-984f-caddfa25ba22&map%5Bdatasets%5D%5B1%5D%5Blayers%5D%5B0%5D=b45350e3-5a76-44cd-b0a9-5038a0d8bfae&map%5Bdatasets%5D%5B1%5D%5Blayers%5D%5B1%5D=cc35432d-38d7-4a03-872e-3a71a2f555fc&mainMap%5BshowAnalysis%5D=true",
  "alert_date_begin": "2020-04-15",
  "alert_date_end": "2020-04-22"
}

Subscriptions support two types of notifications: emails or webhook requests is performed. Both notifications are checked and sent every day, assuming that the dataset data has changed since the last notification sent.

Webhook notifications are sent as POST requests to the URL saved in the subscription. You can check on the side an example of the data that is sent in the body of the POST call. Please note that the webhook POST body data can change, based on the dataset chosen to receive notifications.

You can see in the image below an example of an email notification for GLAD deforestation alerts:

Subscription email example

Summary of the subscription lifecycle

Getting subscriptions owned by the request user

Getting the subscriptions for the request user:

curl -X GET "https://api.resourcewatch.org/v1/subscriptions" \
-H "Authorization: Bearer <your-token>"

Example response:

{
  "data": [
    {
      "type": "subscription",
      "id": "587cc014f3b3f6280058e478",
      "attributes": {
        "name": "Test subscription",
        "createdAt": "2020-01-16T12:45:08.434Z",
        "userId": "57a063da096c4eda523e99ae",
        "resource": {
          "type": "EMAIL",
          "content": "example@wri.org"
        },
        "datasets": ["viirs-active-fires"],
        "datasetsQuery": [],
        "params": {
          "geostore": "50601ff9257df221e808af427cb47701"
        },
        "confirmed": false,
        "language": "en",
        "env": "production"
      }
    }
  ]
}

This endpoint will allow you to get all the subscriptions owned by the user who performed the request (identified by the access token). To use this endpoint, you must be logged in (i.e. a token must be provided). In the sections below, we’ll explore how you can customize this endpoint call to match your needs.

For a detailed description of each field, check out the Subscription reference section.

Filters

The v1/subscriptions endpoint supports the following optional query parameters as filters:

Field Description Type Default value
application Application to which the subscription is associated. Read more about this field here. String 'gfw'
env The environment to which the subscription is associated. Read more about this field in the Environments concept section. String 'production'

Deprecation notice: the default value for the application filter (currently, gfw) will be removed and the application filter will then have no default value. We recommend reviewing your application to ensure you set and load the correct application explicitly.

Errors for getting subscriptions

Error code Error message Description
401 Unauthorized No valid token was provided in the request headers.

Getting a subscription by id

Example call for getting a subscription by its id:

curl -X GET "https://api.resourcewatch.org/v1/subscriptions/<subscription_id>" \
-H "Authorization: Bearer <your-token>"

Response:

{
  "data": {
    "type": "subscription",
    "id": "587cc014f3b3f6280058e478",
    "attributes": {
      "name": "Test subscription",
      "createdAt": "2020-01-16T12:45:08.434Z",
      "userId": "57a063da096c4eda523e99ae",
      "resource": {
        "type": "EMAIL",
        "content": "example@wri.org"
      },
      "datasets": ["viirs-active-fires"],
      "datasetsQuery": [],
      "params": {
        "geostore": "50601ff9257df221e808af427cb47701"
      },
      "confirmed": false,
      "language": "en",
      "env": "production"
    }
  }
}

If you know the id of a subscription, then you can access it directly by performing a GET request to the v1/subscriptions/:id endpoint. Keep in mind that this will only match subscriptions that are owned by the user who performed the request.

Errors for getting subscriptions by id

Error code Error message Description
400 ID is not valid The id provided is not a valid subscription id.
401 Unauthorized No valid token was provided in the request headers.
404 Subscription not found Either no subscription exists with the provided id, or the subscription with the id provided is not owned by the user who performed the request.

Creating a subscription

Example POST request to create a subscription providing the bare minimum body fields:

curl -X POST "https://api.resourcewatch.org/v1/subscriptions" \
-H "Authorization: Bearer <your-token>" \
-H "Content-Type: application/json"  -d \
 '{
    "datasets": "20cc5eca-8c63-4c41-8e8e-134dcf1e6d76",
    "resource": {
      "type": "EMAIL",
      "content": "example@wri.org"
    },
    "params": {},
    "application": "gfw",
    "language": "en"
  }'

Example response:

{
  "data": {
    "type": "subscription",
    "id": "5eea1e6cfd754e001b28cb2b",
    "attributes": {
      "createdAt": "2020-06-17T13:45:16.222Z",
      "userId": "5ed75dd2a82a420010ed066b",
      "resource": {
        "type": "EMAIL",
        "content": "example@wri.org"
      },
      "datasets": ["20cc5eca-8c63-4c41-8e8e-134dcf1e6d76"],
      "params": {},
      "confirmed": false,
      "language": "en",
      "datasetsQuery": [],
      "env": "production"
    }
  }
}

This section will guide you through the process of creating a basic subscription in the RW API. Creating a subscription can be done by any logged user using a POST request and passing the relevant data as body fields. The supported body fields are as defined on the subscription reference section, but the minimum field list you must specify for all subscriptions are:

If the creation of the subscription is successful, the HTTP response code will be 200 OK, and the response body will contain the created subscription object. Please note that subscriptions must be confirmed before they become active - refer to the subscription lifecycle for more details on this.

Errors for creating subscriptions

Error code Error message Description
400 <field> required You didn't provide one of the required fields.
401 Unauthorized No valid token was provided in the request headers.

Defining the datasets

You will need to provide the dataset ids to which your subscription will watch for updates. In order to do so, you'll need to provide one of two fields when creating a subscription:

Customizing the geographic area for the subscription

When it comes to geo-referenced data, subscriptions are intrinsically tied to a geographic area of interest. This association enables users to create subscriptions to be notified of changes in the data of a dataset, but only if there are changes in the data of the dataset relative to the concrete geographic area of the world they are interested in. The specification of the geographic information for the subscription should be done in the params field of the subscription.

Subscribing to an area of interest

Creating a subscription providing the id of an area of interest in the params field:

curl -X POST "https://api.resourcewatch.org/v1/subscriptions" \
-H "Authorization: Bearer <your-token>" \
-H "Content-Type: application/json"  -d \
 '{
    "datasets": ["<dataset-id>"],
    "params": {
      "area": "35a6d982388ee5c4e141c2bceac3fb72"
    },
    "application": "gfw",
    "language": "en",
    "env": "production",
    "resource": {
      "type": "EMAIL",
      "content": "email@address.com"
    }
  }'

A subscription can refer to a specific area of interest that has been created using the RW API Areas service. If this is the case, you should first create your area of interest, grab its id and provide it in the params.area field of the request body when creating the subscription.

Field Description Type
params Geographic area of the subscription Object
params.area Id of area of interest from the RW API Areas service String

Subscribing to a country, country region or subregion

Creating a subscription to a whole country:

curl -X POST "https://api.resourcewatch.org/v1/subscriptions" \
-H "Authorization: Bearer <your-token>" \
-H "Content-Type: application/json"  -d \
 '{
    "datasets": ["<dataset-id>"],
    "params": {
      "iso": {
        "country": "BRA"
      }
    },
    "application": "gfw",
    "language": "en",
    "env": "production",
    "resource": {
      "type": "EMAIL",
      "content": "email@address.com"
    }
  }'

Creating a subscription to a country subregion:

curl -X POST "https://api.resourcewatch.org/v1/subscriptions" \
-H "Authorization: Bearer <your-token>" \
-H "Content-Type: application/json"  -d \
 '{
    "datasets": ["<dataset-id>"],
    "params": {
      "iso": {
        "country": "BRA",
        "region": "1",
        "subregion": "2"
      }
    },
    "application": "gfw",
    "language": "en",
    "env": "production",
    "resource": {
      "type": "EMAIL",
      "content": "email@address.com"
    }
  }'

A subscription can refer to a country, one of its regions, or a subregion within a region. Countries are identified by their ISO 3166-1 alpha-3 code - check here for a list of all the available country codes. Regions and subregions are identified by their respective GADM id, which can be obtained from GADM's dataset here. When creating a subscription for a region, the country ISO must be specified. For subscribing to a subregion, both region and country ISO must be provided.

Field Description Type
params.iso.country ISO 3-letter code of the country to subscribe String
params.iso.region Region id to subscribe String
params.iso.subregion Subregion id to subscribe (optional) String

Subscribing to a protected area from World Database on Protected Areas

Creating a subscription providing a WDPA id in the params field:

curl -X POST "https://api.resourcewatch.org/v1/subscriptions" \
-H "Authorization: Bearer <your-token>" \
-H "Content-Type: application/json"  -d \
 '{
    "datasets": ["<dataset-id>"],
    "params": {
      "wdpaid": "32054"
    },
    "application": "gfw",
    "language": "en",
    "env": "production",
    "resource": {
      "type": "EMAIL",
      "content": "email@address.com"
    }
  }'

A subscription can refer to a specific protected area by the id of that area in the World Database on Protected Areas. If this is the case, you should provide the WDPA id in the params.wdpaid field when creating the subscription. IDs of protected areas worldwide can be obtained from the Protected Planet website.

Field Description Type
params.wdpaid Id of the protected area in the WDPA String

Subscribing to a RW API geostore

Creating a subscription providing the id of a geostore obtained from the RW API in the params field:

curl -X POST "https://api.resourcewatch.org/v1/subscriptions" \
-H "Authorization: Bearer <your-token>" \
-H "Content-Type: application/json"  -d \
 '{
    "datasets": ["<dataset-id>"],
    "params": {
      "geostore": "35a6d982388ee5c4e141c2bceac3fb72"
    },
    "application": "gfw",
    "language": "en",
    "env": "production",
    "resource": {
      "type": "EMAIL",
      "content": "email@address.com"
    }
  }'

A subscription can refer to a specific geostore that has been created using the RW API Geostore service. If this is the case, you should create your geostore and use its id in the params.geostore field of the request body when creating the subscription.

Field Description Type
params.geostore Id of the RW API geostore to subscribe to. String

Subscribing to a GFW Data API geostore

Creating a subscription providing the id of a geostore obtained from the GFW Data API in the params field:

curl -X POST "https://api.resourcewatch.org/v1/subscriptions" \
-H "Authorization: Bearer <your-token>" \
-H "Content-Type: application/json"  -d \
 '{
    "datasets": ["<dataset-id>"],
    "params": {
      "geostoreDataApi": "35a6d982388ee5c4e141c2bceac3fb72"
    },
    "application": "gfw",
    "language": "en",
    "env": "production",
    "resource": {
      "type": "EMAIL",
      "content": "email@address.com"
    }
  }'

A subscription can refer to a specific geostore that has been created using the GFW Data API. If this is the case, you should check the docs for the GFW Data API and create your geostore, then use its id in the params.geostoreDataApi field of the request body when creating the subscription.

Field Description Type
params.geostoreDataApi Id of the GFW Data API geostore to subscribe to. String

Subscribing to land use areas

Creating a subscription providing the id of a land use area in the params field:

curl -X POST "https://api.resourcewatch.org/v1/subscriptions" \
-H "Authorization: Bearer <your-token>" \
-H "Content-Type: application/json"  -d \
 '{
    "datasets": ["<dataset-id>"],
    "params": {
      "use": "mining",
      "useid": "234"
    },
    "application": "gfw",
    "language": "en",
    "env": "production",
    "resource": {
      "type": "EMAIL",
      "content": "email@address.com"
    }
  }'

A subscription can refer to a land use area provided by different datasets. At this point, the following land use datasets are supported: mining for mining areas, logging for Congo Basin logging roads, oilpalm for palm oil plantations or fiber for wood fiber plantations. If this is the case, you should provide the name of the land use dataset you wish to use in the params.use field, and the id of the area in the params.useid field of the request body when creating the subscription.

The ids to be used for land use areas can be obtained from the following CartoDB datasets:

Field Description Type
params.use The type of land use you want to subscribe to. Can be one of mining, logging, oilpalm or fiber. String
params.useid The id of the land use area you want to subscribe to. String

Updating a subscription

Example PATCH request for updating a subscription by id:

curl -X PATCH "https://api.resourcewatch.org/v1/subscriptions/<subscription_id>" \
-H "Authorization: Bearer <your-token>"
-H "Content-Type: application/json"  -d \
 '{
    "datasets": ["20cc5eca-8c63-4c41-8e8e-134dcf1e6d76"],
    "params": {
      "geostore": "35a6d982388ee5c4e141c2bceac3fb72"
    },
    "application": "rw",
    "language": "fr",
    "env": "staging",
    "resource": {
      "type": "EMAIL",
      "content": "email@address.com"
    }
  }'

Example response:

{
  "data": {
    "type": "subscription",
    "id": "5ee79291a67d9a001b11043a",
    "attributes": {
      "createdAt": "2020-06-15T15:24:01.806Z",
      "userId": "5ed75dd2a82a420010ed066b",
      "resource": {
        "type": "EMAIL",
        "content": "email@address.com"
      },
      "datasets": ["20cc5eca-8c63-4c41-8e8e-134dcf1e6d76"],
      "params": {
        "geostore": "35a6d982388ee5c4e141c2bceac3fb72"
      },
      "confirmed": true,
      "language": "fr",
      "datasetsQuery": [],
      "env": "staging"
    }
  }
}

You can update subscriptions associated with you user account by using the PATCH v1/subscriptions/:id endpoint. Updating a subscription follows the same validations as when creating a new one - i.e. all required field values must be provided, even if they remain the same. Values for fields other than the following are optional. The minimum fields list you must specify to update a subscription is:

If the update of the subscription is successful, the HTTP response code will be 200 OK, and the response body will contain the updated subscription object.

Note: Updating a subscription does not require confirming it. A confirmed subscription will stay confirmed after an update.

Errors for updating subscriptions

Error code Error message Description
400 <field> required You didn't provide one of the required fields.
400 Id is not valid The id provided is not valid.
401 Unauthorized No valid token was provided in the request headers.
404 Subscription not found Either a subscription with the id provided does not exist or it is not owned by the user who performed the request.

Deleting subscriptions

Example DELETE request for deleting a subscription by its id:

curl -X DELETE "https://api.resourcewatch.org/v1/subscriptions/<subscription_id>" \
-H "Authorization: Bearer <your-token>"

Example response:

{
  "data": {
    "type": "subscription",
    "id": "5ee79291a67d9a001b11043a",
    "attributes": {
      "createdAt": "2020-06-15T15:24:01.806Z",
      "userId": "5ed75dd2a82a420010ed066b",
      "resource": {
        "type": "EMAIL",
        "content": "email@address.com"
      },
      "datasets": ["20cc5eca-8c63-4c41-8e8e-134dcf1e6d76"],
      "params": {
        "geostore": "35a6d982388ee5c4e141c2bceac3fb72"
      },
      "confirmed": true,
      "language": "fr",
      "datasetsQuery": [],
      "env": "staging"
    }
  }
}

To delete a subscription associated with your user account, you should use the DELETE v1/subscriptions/:id endpoint. If the deletion of the subscription is successful, the HTTP response code will be 200 OK, and the response body will contain the deleted subscription object.

Errors for deleting subscriptions

Error code Error message Description
400 Id is not valid The id provided is not valid.
401 Unauthorized No valid token was provided in the request headers.
404 Subscription not found Either a subscription with the id provided does not exist or it is not owned by the user who performed the request.

Confirming a subscription

Example GET request to confirm a subscription:

curl -X GET "https://api.resourcewatch.org/v1/subscriptions/<subscription_id>/confirm"

Upon creation of the subscription, a confirmation email is sent to the email of the user who created the subscription. This email will contain a link, which you will need to click in order to confirm the subscription. You can also confirm the subscription by performing a GET request to the v1/subscriptions/:id/confirm endpoint, as exemplified on the side.

Manually calling this endpoint will redirect you to the GFW application.

Resending the subscription confirmation email

Example GET request to resend the confirmation email for a subscription:

curl -X GET "https://api.resourcewatch.org/v1/subscriptions/<subscription_id>/send_confirmation" \
-H "Authorization: Bearer <your-token>"

For convenience, the RW API offers an additional endpoint to resend the confirmation email. In order to do this, you should perform a GET request to the v1/subscriptions/:id/send_confirmation. As with most of the other subscription endpoints, please keep in mind that you must be authenticated in order to use this endpoint.

This endpoint does not change the subscription - i.e. if the subscription was already confirmed, it stays that way. The confirmation email will always be sent, regardless if the subscription is confirmed or not.

Manually calling this endpoint will redirect you to the GFW application.

Unsubscribing

Example GET request to unsubscribe:

curl -X GET "https://api.resourcewatch.org/v1/subscriptions/<subscription_id>/unsubscribe" \
-H "Authorization: Bearer <your-token>"

Note: When you unsubscribe, the underlying subscription resource is deleted..

You can use the endpoint v1/subscriptions/:id/unsubscribe (exemplified on the side) for unsubscribing from a subscription. As with most of the other subscription endpoints, please keep in mind that you must be authenticated in order to use this endpoint.

Subscription statistics

The following section details the endpoints that can be used to access statistics on the usage of subscriptions.

The usage of the following endpoints is restricted to ADMIN users.

General subscription statistics

Example GET request to obtain general subscription statistics:

curl -X GET "https://api.resourcewatch.org/v1/subscriptions/statistics?start=:start&end=:end" \
-H "Authorization: Bearer <your-token>"

Example response:

{
  "topSubscriptions": {
    "geostore": 1000,
    "country": 30,
    "region": 20,
    "wdpa": 10,
    "use": 1
  },
  "info": {
    "numSubscriptions": 1000,
    "totalSubscriptions": 6000,
    "usersWithSubscriptions": 1000,
    "totalEmailsSentInThisQ": 0,
    "totalEmailsSended": 0
  },
  "usersWithSubscription": 119,
  "newUsers": 210,
  "groupStatistics": {
    "glad-alerts": {
      "country": 15,
      "region": 28,
      "use": 1,
      "wdpa": 9,
      "geostore": 1305,
      "countries": {
        "CHL": 1,
        "IDN": 3,
        ...
      },
      "regions": {
        "1": 1,
        "2": 2,
        ...
      },
      "wdpas": {
        "130": 1,
        "34043": 5,
        ...
      },
      "countryTop": {
        "name": "IDN",
        "value": 3
      },
      "regionTop": {
        "nameRegion": 12,
        "nameCountry": "IDN",
        "value": 2
      },
      "wdpaTop": {
        "id": 34043,
        "value": 5
      }
    },
    "prodes-loss": {...},
    "umd-loss-gain": {...},
    "terrai-alerts": {...},
    "viirs-active-fires": {...},
    "imazon-alerts": {...},
    "forma250GFW": {...},
    "forma-alerts": {...},
    "story": {...},
    "63f34231-7369-4622-81f1-28a144d17835": {...}
  }
}

The v1/subscriptions/statistics endpoint can be used to access all the data regarding the subscription notifications that have been sent.

Filters

This endpoint supports the following query parameters as filters:

Field Description Type Default Example
start The start of the date range to fetch the statistics. This parameter is required. String None 01-01-2020
end The end of the date range to fetch the statistics. This parameter is required. String None 02-20-2020
application The application for which the statistics will be fetched. Read more about this field here. String 'gfw' 'rw'

Grouped subscription statistics

Example GET request to obtain grouped subscription statistics:

curl -X GET "https://api.resourcewatch.org/v1/subscriptions/statistics-group?start=:start&end=:end" \
-H "Authorization: Bearer <your-token>"

Example response:

{
  "glad-alerts": {
    "country": 15,
    "region": 28,
    "use": 1,
    "wdpa": 9,
    "geostore": 1305,
    "countries": {
      "CHL": 1,
      "IDN": 3,
      ...
    },
    "regions": {
      "1": 1,
      "2": 2,
      ...
    },
    "wdpas": {
      "130": 1,
      "34043": 5,
      ...
    },
    "countryTop": {
      "name": "IDN",
      "value": 3
    },
    "regionTop": {
      "nameRegion": 12,
      "nameCountry": "IDN",
      "value": 2
    },
    "wdpaTop": {
      "id": 34043,
      "value": 5
    }
  },
  "prodes-loss": {...},
  "umd-loss-gain": {...},
  "terrai-alerts": {...},
  "viirs-active-fires": {...},
  "imazon-alerts": {...},
  "forma250GFW": {...},
  "forma-alerts": {...},
  "story": {...},
  "63f34231-7369-4622-81f1-28a144d17835": {...}
}

The v1/subscriptions/statistics-group endpoint can be used to access data regarding the subscription notifications that have been sent, grouped by the the dataset of the subscription. The output of this endpoint is a subset of the output of the v1/subscriptions/statistics endpoint.

Filters

This endpoint supports the following query parameters as filters:

Field Description Type Default Example
start The start of the date range to fetch the statistics. This parameter is required. String None 01-01-2020
end The end of the date range to fetch the statistics. This parameter is required. String None 02-20-2020
application The application for which the statistics will be fetched. Read more about this field here. String 'gfw' 'rw'

Subscription reference

This section gives you a complete view at the properties that are maintained as part of a subscription. When interacting with a subscription (on get, on create, etc) you will find most of these properties available to you, although they may be organized in a slightly different structure (ie: on get, everything but the id is nested inside an attributes object).

You can find more details in the source code.

Filter Type Required Default value Description
id String Yes (auto-generated) Unique Id of the subscription. Auto generated on creation. Cannot be modified by users.
name String No The name of the subscription.
confirmed Boolean No false If the subscription is confirmed or not. Cannot be modified by users, only through the usage of the confirm and unsubscribe endpoints. (TODO: missing refs!)
resource Object Yes An object containing the data for who (or what) should be notified on dataset data changes.
resource.type Enum Yes The type of resource to be notified. Can take the values of EMAIL (for an email notification) or URL for a webhook notification.
resource.content String Yes The object to be notified: should be a valid email case resource.type is EMAIL, and a valid URL case resource.type is URL.
datasets Array No [] An array of dataset ids that this subscription is tracking.
datasetsQuery Array No [] An alternative way of stating the datasets that this subscription is tracking. This field is an array of objects, check the rows below to see which properties each object should have.
datasetsQuery[0].id String No An identifier for the dataset being subscribed.
datasetsQuery[0].type String No A type for the dataset being subscribed.
datasetsQuery[0].threshold Number No 0 The threshold to be considered when checking for updates in the dataset's data. By default, it takes the value the value 0, but you can customize it to only get notified if there are at least (for instance) 5 updates to the dataset's data.
datasetsQuery[0].lastSentDate Date No (auto-generated) Value automatically updated to have set the last date when updates were detected in this dataset.
datasetsQuery[0].lastSentDate Date No (auto-generated) This value is automatically updated with the historical data of all the updates detected in the dataset's data.
params Object No {} Determines the area of interest that this subscription should track. Can contain information to narrow the updates being tracked (especially in the case of geo-referenced data).
userId String Yes (auto-populated) Id of the user who owns the subscription. Set automatically on creation. Cannot be modified by users.
language String No 'en' The language for this subscription. Useful for customizing email notifications according to the language of the subscription. Possible values include 'en', 'es', 'fr', 'pt' or 'zh'.
application String Yes 'gfw' Applications associated with this subscription. Read more about this field here.
env String Yes 'production' Environment to which the subscription belongs. Read more about this field in the Environments concept section.
createdAt Date No (auto-populated) Automatically maintained date of when the subscription was created. Cannot be modified by users.
updatedAt Date No (auto-populated) Automatically maintained date of when the subscription was last updated. Cannot be modified by users.

Favorites

The users can save their own favorites resources of the API.

Field Description Type
id Name Text
resourceId Id of the resource Text
resourceType Type of resource Text (dataset, layer, widget)
userId Id of the owner user Text
createdAt Creation date Date

Create Favorite

To create a favorite, you need to define all next fields in the request body. The required fields that compose a favorite are:

Field Description Type
resourceId Id of the resource Text
resourceType Type of resource Text (dataset, layer, widget)

To create a favorite, you have to do a POST with the following body:

curl -X POST https://api.resourcewatch.org/v1/favourite \
-H "Authorization: Bearer <your-token>" \
-H "Content-Type: application/json"  -d \
 '{
   "resourceType":"<resourceType>",
   "resourceId": "<resourceId>"
  }'

Get favorites

This endpoint returns the favorites of the logged user.

To get all favorite of the logged user, you have to do a GET request:

curl -X GET https://api.resourcewatch.org/v1/favourite \
-H "Authorization: Bearer <your-token>"

You can also retrieve all data about the resources by including the query parameter "include=true" in the request.

curl -X GET https://api.resourcewatch.org/v1/favourite?include=true \
-H "Authorization: Bearer <your-token>"

Get favorite by id

This endpoint returns the favorite with id of the param. If the favorite belongs to other user or not exist, the endpoint returns 400.

To get the favorite by id, you have to do a GET request:

curl -X GET https://api.resourcewatch.org/v1/favourite/:id \
-H "Authorization: Bearer <your-token>"

Delete favorite

This endpoint deletes the favorite with id of the param. If the favorite belongs to other user or not exist, the endpoint returns 400.

To delete the favorite by id, you have to do a DELETE request:

curl -X DELETE https://api.resourcewatch.org/v1/favourite/:id \
-H "Authorization: Bearer <your-token>"

Graph

The following section details the endpoints you can use to interact with graph information about the RW API. If you are new to the RW API or want to learn more about what the RW API graph can do for you, we strongly encourage you to read the graph concept documentation first.

Before proceeding, let's look at some concepts that will be used across the graph endpoint documentation.

What is a resource

Throughout this section, we'll refer multiple times to resources. Simply put, a resource is either a dataset, a widget, a layer, or a metadata entry. Graph nodes represent in a similar fashion these 4 types of RW API entity, so often we'll refer to resources instead, for convenience.

We assume that, at this point, you are already familiar with the concepts of dataset, layer, widget or metadata (ideally you are familiar with the 4). If that's not the case, we strongly encourage you to learn about those concepts first, and we also recommend you take some time to explore and experiment using actual dataset, layer, widget, or metadata endpoints before proceeding. The RW API Graph service builds on top of these concepts and empowers your use cases of those resources, so it should only be used by applications and users that are already comfortable with the basics, and want to take their knowledge of the RW API to the next level.

In the context of the RW API Graph service, resources are represented as graph nodes. They can be associated (using graph edges) with concepts to create relationships of relevance between the two entities.

What is a concept

Similarly, we'll refer multiple times to concepts. A concept is a keyword used to describe a resource (e.g. health, society, solar_power, etc.). It shares some similarities with tags, in the sense it can be associated with resources of different types (datasets, layers, or widgets).

As with resources, in the context of the RW API Graph service, concepts are represented as graph nodes. They can be associated (using graph edges) with resources to create relationships of relevance between the two entities.

Bird's-eye view of the graph service

As an API user, you will surely be glad to hear that most of the management of graph entities is performed automatically. As you will discover by reading the sections on creating or deleting graph resources, graph nodes for resources are automatically created and deleted when you create or delete your resources, respectively. This means that, as an API user, you are abstracted from these processes and the only thing you need to worry about is actually managing relationships between graph resources and concepts.

To do so, you will need to interact with vocabulary endpoints, using a specific vocabulary called knowledge_graph. You can tag your resources using said vocabulary, and the tags you add will be added as graph concepts and associated with your resources. You can read more about this process in the section on relationships between graph nodes and concepts. Some concepts have been pre-loaded into the graph service, and you can use them to associate your resources with widely-used concepts. However, you are also encouraged to create your own concepts - which, once again, is performed automatically when managing your associations using the vocabulary endpoints.

You may come across some hierarchical concepts in the following sections, such as "ancestors", "parent concepts" or "descendants". These were initially added with the intention of supporting hierarchy between graph concepts, but such features were not completed. As such, it is recommended that, for now, you ignore and do not rely on any type of hierarchy between graph concepts. This may, however, change in the future.

Lastly, a note: none of the endpoints below are paginated. Most of the endpoints interact with a single resource (dataset, layer, widget, or metadata), which contributes to a healthy size for most of the Graph service endpoint responses, as long as you keep your associations between graph resources and concepts to a reasonable amount. However, some of the endpoints aim at retrieving full lists of, for instance, graph concepts - please ensure that you take into consideration the impact of using such endpoints in the performance of your applications.

List concepts

Request to list concepts:

curl -X GET https://api.resourcewatch.org/v1/graph/query/list-concepts

Example response:

{
    "data": [
        {
            "id": "society",
            "label": "Society",
            "synonyms": ["People"],
            "labels": ["CONCEPT", "TOPIC"],
            "numberOfDatasetsTagged": 1,
            "datasets": ["4458eb12-8572-45d1-bf07-d5a3ee097021"]
        },
    ]
}

This endpoint does not return a paginated list - you will receive a full list of all the concepts available in the graph. Additionally, the returned response can only be filtered by application, not searched - which means that it's very unlikely that you will receive a reduced payload by using this endpoint. As such, you should avoid using this specific endpoint since it might harm the performance of your application, should the graph increase significantly in size. You can find alternative endpoints in the sections below that allow you to navigate the graph by similarity of concepts, which is the recommended approach to navigating the graph.

This endpoint returns the list of concepts available in the graph. If successful, the response will have status 200 OK, containing a list of elements in the data index, each containing the information about one concept. Check out the Graph concept reference for details on each of the fields of the returned response.

Filters

Filtering concepts by application:

curl -X GET https://api.resourcewatch.org/v1/graph/query/list-concepts?application=gfw

This endpoint supports the following filters as query string parameters:

Filter Description Type Default value
application Applications associated to this