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

JWT tokens

Most RW API endpoints are public, but some actions require user authentication. Each endpoint's documentation will specify whether authentication is required and under what 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 JWT tokens. For all authenticated requests, you must provide your JWT using the header Authorization: Bearer <your token>. Please note that your JWT tokens act like passwords, so you should never share or expose them publicly. Doing so may allow other users to impersonate your RW API user account, and may grant them permissions over your datasets, applications, etc.

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.

API Keys

Besides JWT tokens, the RW API also uses API keys to identify the client application issuing the request. This is done for moderation and analytical purposes, ensuring it's available to everyone for fair use. Unlike the JWT tokens described above, API keys are not used to grant permissions over data. While it's not critical to keep them private, you should have a different API key for each application you create that uses the RW API.

An API key is generated automatically once you register a client application, which you can learn more about in the corresponding section of the reference docs.

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 \
-H "x-api-key: <your-api-key>"

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": "https://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": "https://api.resourcewatch.org/v1/dataset?page[number]=1&page[size]=10",
    "first": "https://api.resourcewatch.org/v1/dataset?page[number]=1&page[size]=10",
    "last": "https://api.resourcewatch.org/v1/dataset?page[number]=99&page[size]=10",
    "prev": "https://api.resourcewatch.org/v1/dataset?page[number]=1&page[size]=10",
    "next": "https://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 \
-H "x-api-key: <your-api-key>"

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 \
-H "x-api-key: <your-api-key>"

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 \
-H "x-api-key: <your-api-key>"

Matching vocabulary tags

curl -X GET https://api.resourcewatch.org/v1/dataset?vocabulary[legacy]=umd \
-H "x-api-key: <your-api-key>"

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. ** Please keep in mind that, due to the limitations of the underlying endpoint used to find user ids by role, the performance of the request while using this filter might be degraded.** 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 \
-H "x-api-key: <your-api-key>"

Sorting datasets by multiple criteria

curl -X GET https://api.resourcewatch.org/v1/dataset?sort=name,description \
-H "x-api-key: <your-api-key>"

Sort by name descending, description ascending

curl -X GET https://api.resourcewatch.org/v1/dataset?sort=-name,+description \
-H "x-api-key: <your-api-key>"

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

curl -X GET https://api.resourcewatch.org/v1/dataset?sort=user.role \
-H "x-api-key: <your-api-key>"

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.

Please also keep in mind that, due to the limitations of the underlying endpoint used to find user ids by name or role, the performance of the request while using this sort might be degraded.

Special sorting criteria

Sorting datasets with special criteria

curl -X GET https://api.resourcewatch.org/v1/dataset?sort=-most-favorited \
-H "x-api-key: <your-api-key>"
curl -X GET https://api.resourcewatch.org/v1/dataset?sort=relevance&status=saved&search=agriculture \
-H "x-api-key: <your-api-key>"

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 \
-H "x-api-key: <your-api-key>"
{
  "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": "https://api.resourcewatch.org/v1/dataset?includes=widget%2Cmetadata&page[number]=1&page[size]=10",
    "first": "https://api.resourcewatch.org/v1/dataset?includes=widget%2Cmetadata&page[number]=1&page[size]=10",
    "last": "https://api.resourcewatch.org/v1/dataset?includes=widget%2Cmetadata&page[number]=223&page[size]=10",
    "prev": "https://api.resourcewatch.org/v1/dataset?includes=widget%2Cmetadata&page[number]=1&page[size]=10",
    "next": "https://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 https://api.resourcewatch.org/dataset?includes=layer \
-H "x-api-key: <your-api-key>"

Loading the information about the user who authored the dataset

curl -X GET https://api.resourcewatch.org/v1/dataset?includes=user \
-H "x-api-key: <your-api-key>"

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

If you specified an env filter and would like to also filter the included entities, you can provide the filterIncludesByEnv=true query parameter. This is only supported for included widget and layer.

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" \
-H "x-api-key: <your-api-key>"

Getting a dataset by slug:

curl -X GET "https://api.resourcewatch.org/v1/dataset/Timber-Production-RDC" \
-H "x-api-key: <your-api-key>"

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": "https://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 \
-H "x-api-key: <your-api-key>"

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"  \
-H "x-api-key: <your-api-key>" -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 provideryou 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 "x-api-key: <your-api-key>" \
-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.

GFW datasets

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

curl -X POST https://api.resourcewatch.org/v1/dataset \
-H "Authorization: Bearer <your-token>" \
-H "x-api-key: <your-api-key>" \
-H "Content-Type: application/json"  -d \
'{
  "dataset": {
    "name":"RADD Deforestation Alerts",
    "connectorType":"rest",
    "provider":"gfw",
    "connectorUrl":"https://data-api.globalforestwatch.org/dataset/wur_radd_alerts/latest",
    "application":[
      "gfw", 
      "rw"
    ]
  }
}'

To create a dataset connected to a GFW 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 gfw. gfw
connectorUrl The URL for the GFW table or file that this dataset will be using. https://data-api.globalforestwatch.org/dataset/wur_radd_alerts/latest

The RW API will use the information above to directly query the GFW 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:

The tableName value of a GFW-based dataset will automatically be filled with the name of the GFW table or raster file corresponding to the dataset.

The latest path parameter in connectionUrl requests the most recent public version of the requested dataset in GFW. Alternatively, you may request a dataset by the version number if known.

When creating a GFW-based dataset, the RW API will try to validate the connectorUrl by trying to connect to the corresponding GFW table or raster file - 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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-H 'Content-Type: application/json' -d \
'{
   "dataset": {
     "application": [
       "rw"
     ],
     "name": "Seasonal variability",
     "connectorType": "wms",
     "provider":"wms",
     "connectorUrl":"https://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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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. https://gis-gfw.wri.org/arcgis/rest/services/prep/nex_gddp_indicators/MapServer/6?f=pjson
sources List of URLs from which to source data. ['https://gis-gfw.wri.org/arcgis/rest/services/prep/nex_gddp_indicators/MapServer/6?f=pjson','https://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>" \
-H "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>"
-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

Example request for deleting a dataset

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

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:

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.

Deleting datasets by user id

Example request for deleting datasets by user id

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

Example response:

{
    "deletedDatasets": [
      {
        "id": "aef2be42-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": "https://gfw2-data.s3.amazonaws.com/alerts-tsv/glad_headers.csv",
          "sources": [],
          "tableName": "data",
          "status": "pending",
          "published": true,
          "protected": false,
          "overwrite": false,
          "env": "production",
          "geoInfo": false,
          "legend": {
            "date": [],
            "region": [],
            "country": []
          },
          "clonedHost": {},
          "errorMessage": null,
          "updatedAt": "2017-01-13T10:45:46.368Z",
          "widgetRelevantProps": [],
          "layerRelevantProps": []
        }
      }
    ],
    "protectedDatasets": [
      {
        "id": "00f2be42-1ee8-4069-a55a-16a988f2b762",
        "type": "dataset",
        "attributes": {
          "name": "Fires data",
          "slug": "fires-data-1490086842163",
          "type": null,
          "subtitle": null,
          "application": [
            "data4sdgs"
          ],
          "dataPath": null,
          "attributesPath": null,
          "connectorType": "document",
          "provider": "csv",
          "userId": "58333dcfd9f39b189ca44c75",
          "connectorUrl": "https://gfw2-data.s3.amazonaws.com/alerts-tsv/fires.csv",
          "sources": [],
          "tableName": "data",
          "status": "pending",
          "published": true,
          "protected": true,
          "overwrite": false,
          "env": "production",
          "geoInfo": false,
          "legend": {
            "date": [],
            "region": [],
            "country": []
          },
          "clonedHost": {},
          "errorMessage": null,
          "updatedAt": "2017-01-13T10:45:46.368Z",
          "widgetRelevantProps": [],
          "layerRelevantProps": []
        }
      }
    ]
}

Use this endpoint if you wish to delete all datasets associated with a user. Deleting datasets 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.

Unlike what happens when deleting a single dataset by id, deleting all datasets for a user does not validate if the datasets belong to different applications and prevents their actual deletion based on that - datasets will be deleted even if they are part of applications that the user is not associated with.

Besides deleting the datasets themselves, this endpoint also deletes graph vocabularies, layers, widgets and metadata related with the datasets themselves. For each dataset, these delete operations are issued in this order, and prior to deleting the dataset itself, but are not atomic - if one of them fails, the following ones are canceled, but the already deleted elements are not restored. Any other datasets associated with the given user may or may not be deleted, as the operation occurs internally in an asynchronous fashion.

Any microservice or user with ADMIN role can use this endpoint. Regular users can use this endpoint to delete the datasets they own.

The response includes two lists of datasets: - deletedDatasets: an unpaginated list of all datasets that were deleted as part of this operation. - protectedDatasets: an unpaginated list of all datasets associated with the provided user, that have protected status set to true, and thus were not deleted.

Errors for deleting datasets by user id

Error code Error message Description
401 Unauthorized You need to be logged in to be able to delete datasets.
403 Forbidden You are trying to delete the datasets of an user that is not the same logged user, not an ADMIN user or a microservice

Dataset automatic synchronization

curl -X POST https://api.resourcewatch.org/v1/dataset \
-H "Authorization: Bearer <your-token>" \
-H "x-api-key: <your-api-key>" \
-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>" \
-H "x-api-key: <your-api-key>"

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>" \
-H "x-api-key: <your-api-key>"

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> \
-H "x-api-key: <your-api-key>"

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.

GFW

Example fields response for a GFW dataset

{
    "fields": [
        {
            "field_name": "umd_glad_landsat_alerts__date_conf",
            "field_alias": null,
            "field_description": null,
            "field_values": null
        },
        {
            "field_name": "umd_glad_landsat_alerts__date",
            "field_alias": null,
            "field_description": null,
            "field_values": null
        },
        {
            "field_name": "umd_glad_landsat_alerts__confidence",
            "field_alias": null,
            "field_description": null,
            "field_values": [
                "nominal",
                "high",
                "highest",
                "not_detected"
            ]
        },
        {
            "field_name": "gfw_integrated_alerts__date_conf",
            "field_alias": null,
            "field_description": null,
            "field_values": null
        },
        {
            "field_name": "gfw_integrated_alerts__date",
            "field_alias": null,
            "field_description": null,
            "field_values": null
        },
        {
            "field_name": "gfw_integrated_alerts__confidence",
            "field_alias": null,
            "field_description": null,
            "field_values": [
                "nominal",
                "high",
                "highest",
                "not_detected"
            ]
        },
        {
            "field_name": "umd_glad_sentinel2_alerts__date_conf",
            "field_alias": null,
            "field_description": null,
            "field_values": null
        },
        {
            "field_name": "umd_glad_sentinel2_alerts__date",
            "field_alias": null,
            "field_description": null,
            "field_values": null
        },
        {
            "field_name": "umd_glad_sentinel2_alerts__confidence",
            "field_alias": null,
            "field_description": null,
            "field_values": [
                "nominal",
                "high",
                "highest",
                "not_detected"
            ]
        },
        {
            "field_name": "wur_radd_alerts__date_conf",
            "field_alias": null,
            "field_description": null,
            "field_values": null
        },
        {
            "field_name": "wur_radd_alerts__date",
            "field_alias": null,
            "field_description": null,
            "field_values": null
        },
        {
            "field_name": "wur_radd_alerts__confidence",
            "field_alias": null,
            "field_description": null,
            "field_values": [
                "nominal",
                "high",
                "highest",
                "not_detected"
            ]
        }
    ]
}

The fields endpoint for GFW dataset returns an array of objects with each object containing field attributes including name, description and alias. Vector dataset fields include additional attributes indicating whether field is feature info and filter. Fields for raster dataset map to individual raster files associated with a dataset. For example, RADD Deforestation Alerts dataset has confidence field mapping to the primary raster dataset with possible values defined in field_values attribute and additional fields such as is__landmark_indigenous_and_community_lands, is__gfw_oil_palm, etc that correspond to contextual raster datasets used to conduct analysis on the alerts data.

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>' \
-H "x-api-key: <your-api-key>"

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' \
-H "x-api-key: <your-api-key>"

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' \
-H "x-api-key: <your-api-key>"

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>" \
-H "x-api-key: <your-api-key>"

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' \
-H "x-api-key: <your-api-key>"

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' \
-H "x-api-key: <your-api-key>"
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' \
-H "x-api-key: <your-api-key>"

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' \
-H "x-api-key: <your-api-key>"
curl -i -X POST 'https://api.resourcewatch.org/v1/query/9be3bf63-97fc-4bb0-b913-775ccae3cf9e' \
-H "x-api-key: <your-api-key>" \
-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' \
-H "x-api-key: <your-api-key>"

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' \
-H "x-api-key: <your-api-key>"

curl -i -X POST 'https://api.resourcewatch.org/v1/query' \
-H "x-api-key: <your-api-key>" \
-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' \
-H "x-api-key: <your-api-key>"
curl -i -X GET 'https://api.resourcewatch.org/v1/query/9be3bf63-97fc-4bb0-b913-775ccae3cf9e?sql=SELECT alert__date FROM data limit 10' \
-H "x-api-key: <your-api-key>"

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>' \
-H "x-api-key: <your-api-key>"

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' \
-H "x-api-key: <your-api-key>"

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' \
-H "x-api-key: <your-api-key>"

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' \
-H "x-api-key: <your-api-key>"

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 "x-api-key: <your-api-key>" \
-H "Authorization: Bearer <your-token>" \
-H "x-api-key: <your-api-key>"

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' \
-H "x-api-key: <your-api-key>"

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' \
-H "x-api-key: <your-api-key>"
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' \
-H "x-api-key: <your-api-key>"

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' \
-H "x-api-key: <your-api-key>"
curl -i -X POST 'https://api.resourcewatch.org/v1/download/9be3bf63-97fc-4bb0-b913-775ccae3cf9e' \
-H "x-api-key: <your-api-key>" \
-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' \
-H "x-api-key: <your-api-key>"

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' \
-H "x-api-key: <your-api-key>"

curl -i -X POST 'https://api.resourcewatch.org/v1/download' \
-H "x-api-key: <your-api-key>" \
-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' \
-H "x-api-key: <your-api-key>"
curl -i -X GET 'https://api.resourcewatch.org/v1/download/9be3bf63-97fc-4bb0-b913-775ccae3cf9e?sql=SELECT alert__date FROM data limit 10' \
-H "x-api-key: <your-api-key>"

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' \
-H "x-api-key: <your-api-key>"
curl -i -X GET 'https://api.resourcewatch.org/v1/query/:dataset_id?sql=DELETE FROM index_bf86b945c4ec41d2b5b7af00f3f61423 WHERE x = "y"' \
-H "x-api-key: <your-api-key>"

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

GFW Datasets

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

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 wdpa_protected_area__iso, area__ha FROM data LIMIT 5
NO SELECT: Selecting DISTINCT values for specific columns SELECT DISTINCT wdpa_protected_area__iso FROM data LIMIT 5
NO SELECT: Selecting columns AND counting all rows SELECT wdpa_protected_area__iso, count(*) FROM data LIMIT 5
YES SELECT: Aliasing aggregate function results such as AVG in SELECT SELECT AVG(area__ha) as alias FROM data LIMIT 5
YES SELECT: Usage of aggregate functions (AVG) in SELECT SELECT AVG(area__ha) FROM data LIMIT 5
YES SELECT: Usage of aggregate functions (MAX) in SELECT SELECT MAX(area__ha) FROM data LIMIT 5
YES SELECT: Usage of aggregate functions (MIN) in SELECT SELECT MIN(area__ha) FROM data LIMIT 5
YES SELECT: Usage of aggregate functions (SUM) in SELECT SELECT SUM(area__ha) FROM data LIMIT 5
YES FROM: Using dataset id in FROM statement SELECT * FROM 94e2d0e4-4a13-4822-99ea-607175080e5d LIMIT 5
YES FROM: Using dataset slug in FROM statement SELECT * FROM GADM-Burned-Areas-Adm2 LIMIT 5
YES FROM: Using dataset tableName in FROM statement SELECT * FROM data LIMIT 5
YES WHERE: Greater than filtering SELECT * FROM data WHERE area__ha > 1000 LIMIT 5
YES WHERE: Greater than or equal filtering SELECT * FROM data WHERE area__ha >= 1000 LIMIT 5
YES WHERE: Equality filtering SELECT * FROM data WHERE area__ha = 3000 LIMIT 5
YES WHERE: Lower than filtering SELECT * FROM data WHERE area__ha < 50 LIMIT 5
YES WHERE: Lower than or equal filtering SELECT * FROM data WHERE area__ha <= 50 LIMIT 5
NO WHERE: Conjunction (AND) filtering SELECT * FROM data WHERE area__ha <= 50 AND {{numericColumn2}} > 0.1 LIMIT 5
NO WHERE: Disjunction (OR) filtering SELECT * FROM data WHERE area__ha <= 50 OR {{numericColumn2}} > 0.1 LIMIT 5
YES WHERE: BETWEEN filtering SELECT * FROM data WHERE area__ha BETWEEN 1000 AND 50 LIMIT 5
NO WHERE: LIKE filtering SELECT * FROM data WHERE wdpa_protected_area__iso LIKE 'Design%' LIMIT 5
YES GROUP BY: Group results by a single column SELECT wdpa_protected_area__iso FROM data GROUP BY wdpa_protected_area__iso LIMIT 5
YES GROUP BY: Group results by multiple columns SELECT wdpa_protected_area__iso, area__ha FROM data GROUP BY wdpa_protected_area__iso, area__ha LIMIT 5
YES GROUP BY: Aggregate functions used with GROUP BY statements SELECT wdpa_protected_area__iso, COUNT(*) as count FROM data GROUP BY wdpa_protected_area__iso LIMIT 5
NO GROUP BY: Special grouping by range function SELECT count(*) FROM data GROUP BY range(area__ha, 0,1,2,3,4) LIMIT 5
YES ORDER BY: Ordering results by one column SELECT wdpa_protected_area__iso FROM data ORDER BY wdpa_protected_area__iso LIMIT 5
YES ORDER BY: Ordering results by one column descending SELECT wdpa_protected_area__iso FROM data ORDER BY wdpa_protected_area__iso DESC LIMIT 5
YES ORDER BY: Ordering results by multiple column SELECT wdpa_protected_area__iso, area__ha FROM data ORDER BY wdpa_protected_area__iso, area__ha LIMIT 5
YES ORDER BY: Ordering results by multiple column descending SELECT wdpa_protected_area__iso, area__ha FROM data ORDER BY wdpa_protected_area__iso, area__ha DESC LIMIT 5
YES LIMIT: Limit the number of returned results SELECT wdpa_protected_area__iso FROM data LIMIT 5
NO OFFSET: Offset the returned results SELECT wdpa_protected_area__iso FROM data LIMIT {{limit}} OFFSET {{offset}}
NO OFFSET: Offset the returned results using short syntax SELECT wdpa_protected_area__iso FROM data LIMIT {{limit}}, {{offset}}

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.

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 "x-api-key: <your-api-key>" \
  -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' \
-H "x-api-key: <your-api-key>"

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' \
-H "x-api-key: <your-api-key>"

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" \
-H "x-api-key: <your-api-key>"

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" \
-H "x-api-key: <your-api-key>"

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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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" \
-H "x-api-key: <your-api-key>"

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" \
-H "x-api-key: <your-api-key>"

Return the layers filtered by dataset

curl -X GET "https://api.resourcewatch.org/v1/layer?dataset=11de2bc1-368b-42ed-a207-aaff8ece752b" \
-H "x-api-key: <your-api-key>"
curl -X GET "https://api.resourcewatch.org/v1/dataset/11de2bc1-368b-42ed-a207-aaff8ece752b/layer" \
-H "x-api-key: <your-api-key>"


> Filter layers by published status

```shell
curl -X GET "https://api.resourcewatch.org/v1/layer?published=false" \
-H "x-api-key: <your-api-key>"

Filter layers by environment

curl -X GET "https://api.resourcewatch.org/v1/layer?env=staging" \
-H "x-api-key: <your-api-key>"

Return the layers filtered by those whose applications contain rw

curl -X GET "https://api.resourcewatch.org/v1/layer?app=rw" \
-H "x-api-key: <your-api-key>"

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" \
-H "x-api-key: <your-api-key>"

Sorting layers by multiple criteria

curl -X GET "https://api.resourcewatch.org/v1/layer?sort=name,slug" \
-H "x-api-key: <your-api-key>"

Explicit order of sorting

curl -X GET "https://api.resourcewatch.org/v1/layer?sort=-name,+slug" \
-H "x-api-key: <your-api-key>"

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

curl -X GET "https://api.resourcewatch.org/v1/layer?sort=user.role" \
-H "x-api-key: <your-api-key>"

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.

Please also keep in mind that, due to the limitations of the underlying endpoint used to find user ids by name or role, the performance of the request while using this sort might be degraded.

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" \
-H "x-api-key: <your-api-key>"

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.

Please keep in mind that, due to the limitations of the underlying endpoint used to find users by ids, the performance of the request while including user information might be degraded.

curl -X GET "https://api.resourcewatch.org/v1/layer?includes=user" \
-H "x-api-key: <your-api-key>"

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" \
-H "x-api-key: <your-api-key>"

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>" \
-H "x-api-key: <your-api-key>"
curl -X GET "https://api.resourcewatch.org/v1/layer/<layer_id>" \
-H "x-api-key: <your-api-key>"

Getting a layer by slug:

curl -X GET "https://api.resourcewatch.org/v1/dataset/<dataset-id>/layer/<layer_slug>" \
-H "x-api-key: <your-api-key>"
curl -X GET "https://api.resourcewatch.org/v1/layer/<layer_slug>" \
-H "x-api-key: <your-api-key>"

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>" \
-H "x-api-key: <your-api-key>" \
-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.

Layer thumbnails

Preview of the thumbnail of a layer

curl -X GET "https://resourcewatch.org/embed/layer/<layer_id>" \
-H "x-api-key: <your-api-key>"

When a layer 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 layer uses the same approach as the RW website for declaring its layers. Searching for layers 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 layer 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 layer creation or update process.

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 "x-api-key: <your-api-key>" \
-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:

Layer thumbnails

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

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 "x-api-key: <your-api-key>" \
-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.

Deleting layers by user id

Example request for deleting layers by user id

curl -X DELETE "https://api.resourcewatch.org/v1/layer/by-user/<user_id>" \
-H "Authorization: Bearer <your-token>" \
-H "x-api-key: <your-api-key>" \
-H "Content-Type: application/json"

Response:

{
  "deletedLayers": [
    {
      "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"
      }
    }
  ],
  "protectedLayers": [
    {
      "id": "1a8a36df-2e52-4b2d-b7be-a48bdcd7c769",
      "type": "layer",
      "attributes": {
        "name": "Fire impact",
        "slug": "fire_impact_7",
        "dataset": "1ae6ec77-5ab0-43f4-9a4c-a3d19bed1e90",
        "description": "fire impact",
        "application": [
          "rw"
        ],
        "iso": [],
        "userId": "5dbadb06df2dc74d2ad054fb",
        "default": false,
        "protected": true,
        "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 all layers from associated with a user. 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 layers themselves, this endpoint also deletes graph vocabularies and metadata related to the layers. These delete operations are issued after each 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 themselves. For example, is the metadata service is temporarily unavailable when you issue your delete layers request, the layers themselves will be deleted, but the associated metadata will continue to exist. The response will not reflect the failure to delete metadata in any way.

Any microservice or user with ADMIN role can use this endpoint. Regular users can use this endpoint to delete the layers they own.

The response includes two lists of layers:

Errors for deleting layers by user id

Error code Error message Description
401 Unauthorized You need to be logged in to be able to delete layers.
403 Forbidden You are trying to delete the layers of an user that is not the same logged user, not an ADMIN user or a microservice

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.

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" \
-H "x-api-key: <your-api-key>"

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" \
-H "x-api-key: <your-api-key>"

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": "https://api.resourcewatch.org/v1/dataset/06c44f9a-aae7-401e-874c-de13b7764959/widget?page[number]=1&page[size]=10",
    "first": "https://api.resourcewatch.org/v1/dataset/06c44f9a-aae7-401e-874c-de13b7764959/widget?page[number]=1&page[size]=10",
    "last": "https://api.resourcewatch.org/v1/dataset/06c44f9a-aae7-401e-874c-de13b7764959/widget?page[number]=2&page[size]=10",
    "prev": "https://api.resourcewatch.org/v1/dataset/06c44f9a-aae7-401e-874c-de13b7764959/widget?page[number]=1&page[size]=10",
    "next": "https://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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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" \
-H "x-api-key: <your-api-key>"

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" \
-H "x-api-key: <your-api-key>"

Return the widgets filtered by dataset

curl -X GET "https://api.resourcewatch.org/v1/widget?dataset=11de2bc1-368b-42ed-a207-aaff8ece752b" \
-H "x-api-key: <your-api-key>"
curl -X GET "https://api.resourcewatch.org/v1/dataset/11de2bc1-368b-42ed-a207-aaff8ece752b/widget" \
-H "x-api-key: <your-api-key>"

Filter widgets by default value

curl -X GET "https://api.resourcewatch.org/v1/widget?default=false" \
-H "x-api-key: <your-api-key>"

Filter widgets by environment

curl -X GET "https://api.resourcewatch.org/v1/widget?env=staging" \
-H "x-api-key: <your-api-key>"

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" \
-H "x-api-key: <your-api-key>"

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" \
-H "x-api-key: <your-api-key>"

Sorting widgets by multiple criteria

curl -X GET "https://api.resourcewatch.org/v1/widget?sort=name,slug" \
-H "x-api-key: <your-api-key>"

Explicit order of sorting

curl -X GET "https://api.resourcewatch.org/v1/widget?sort=-name,+slug" \
-H "x-api-key: <your-api-key>"

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

curl -X GET "https://api.resourcewatch.org/v1/widget?sort=user.role" \
-H "x-api-key: <your-api-key>"

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.

Please also keep in mind that, due to the limitations of the underlying endpoint used to find user ids by name or role, the performance of the request while using this sort might be degraded.

Include entities associated with the widgets

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

Include Vocabulary

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

curl -X GET "https://api.resourcewatch.org/v1/widget?includes=vocabulary" \
-H "x-api-key: <your-api-key>"

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"
            }
          }
        ]
      }
    }
  ]
}

Include User

curl -X GET "https://api.resourcewatch.org/v1/widget?includes=user" \
-H "x-api-key: <your-api-key>"

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.

Please keep in mind that, due to the limitations of the underlying endpoint used to find users by ids, the performance of the request while including user information might be degraded.

Include Metadata

curl -X GET "https://api.resourcewatch.org/v1/widget?includes=metadata" \
-H "x-api-key: <your-api-key>"

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" \
-H "x-api-key: <your-api-key>"

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>" \
-H "x-api-key: <your-api-key>"
curl -X GET "https://api.resourcewatch.org/v1/dataset/<dataset-id>/widget/<widget_id>" \
-H "x-api-key: <your-api-key>"

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" \
-H "x-api-key: <your-api-key>"

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" \
-H "x-api-key: <your-api-key>"

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" \
-H "x-api-key: <your-api-key>"

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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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>" \
-H "x-api-key: <your-api-key>"

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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-H "Content-Type: application/json"


curl -X DELETE "https://api.resourcewatch.org/v1/widget/<widget_id>" \
-H "Authorization: Bearer <your-token>" \
-H "x-api-key: <your-api-key>" \
-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:

Errors for deleting a widget

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

Deleting widgets by user id

Example request that deletes widgets by user id

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


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

Response

{
  "deletedLayers": [
    {
      "id": "7946bca1-6c2a-4329-a127-558ef9551eba",
      "type": "widget",
      "attributes": {
        "name": "water widget",
        "description": "description of the water widget",
        "dataset": "7fa6ec77-5ab0-43f4-9a4c-a3d19bed1e90",
        "slug": "water_widget",
        "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"
      }
    }
  ],
  "protectedLayers": [
    {
      "id": "6a46bca1-6c2a-4329-a127-558ef9551eba",
      "type": "widget",
      "attributes": {
        "name": "fires widget",
        "description": "description of the fires widget",
        "dataset": "7fa6ec77-5ab0-43f4-9a4c-a3d19bed1e90",
        "slug": "fires_widget",
        "userId": "5dbadb0adf2dc74d2ad05dfb",
        "application": [
          "gfw"
        ],
        "verified": false,
        "default": false,
        "protected": true,
        "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 all widgets from associated with a user. As a widget object does not store the actual data being displayed, this will only delete the widget settings, but the actual data will continue to be available at its source.

Besides deleting the widgets themselves, this endpoint also deletes graph vocabularies and metadata related to the widgets. These delete operations are issued after each widget 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 widget themselves. For example, is the metadata service is temporarily unavailable when you issue your delete widgets request, the widgets themselves will be deleted, but the associated metadata will continue to exist. The response will not reflect the failure to delete metadata in any way.

Any microservice or user with ADMIN role can use this endpoint. Regular users can use this endpoint to delete the widgets they own.

The response includes two lists of widgets:

Errors for deleting widgets by user id

Error code Error message Description
401 Unauthorized You need to be logged in to be able to delete widgets.
403 Forbidden You are trying to delete the widgets of an user that is not the same logged user, not an ADMIN user or a microservice

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 "x-api-key: <your-api-key>" \
-H "Content-Type: application/json"  -d \
 '{
    "name": "Collection name"
  }'

Example response:

{
  "data": [
    {
      "id": "5f56170c1fca55001ad51779",
      "type": "collection",
      "env": "production",
      "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 "x-api-key: <your-api-key>" \
-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",
        "env": "production",
        "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
env Environment to which the collection belongs. Read more about this field in the Environments concept section. 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 "x-api-key: <your-api-key>" \
-H "Content-Type: application/json"  -d \
 '{
    "name": "New name"
  }'

Example response:

{
  "data": [
    {
      "id": "5f56170c1fca55001ad51779",
      "type": "collection",
      "attributes": {
        "name": "New name",
        "ownerId": "5dd7b92abf56ca0011875ae2",
        "application": "rw",
        "env": "production",
        "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 "x-api-key: <your-api-key>" \
-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",
        "env": "production",
        "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

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>" \
-H "x-api-key: <your-api-key>"

Example response:

{
  "data": [
    {
      "id": "5f56170c1fca55001ad51779",
      "type": "collection",
      "attributes": {
        "name": "Collection name",
        "ownerId": "5dd7b92abf56ca0011875ae2",
        "application": "rw",
        "env": "production",
        "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>" \
-H "x-api-key: <your-api-key>"

Example response:

{
  "data": [
    {
      "id": "5f56170c1fca55001ad51779",
      "type": "collection",
      "attributes": {
        "name": "Collection name",
        "ownerId": "5dd7b92abf56ca0011875ae2",
        "application": "rw",
        "env": "production",
        "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>" \
-H "x-api-key: <your-api-key>"

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.

Filters

Filtering collections by environment

curl -X GET https://api.resourcewatch.org/v1/collection?env=custom \
-H "x-api-key: <your-api-key>"

The /v1/collection endpoint provides the following parameters to tailor the returned listing:

Field Description Type Example
env Environment to which the collection 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.
userId List collections for different user than the one making the request. Only available for ADMIN users or requests from other microservices. String any valid user id.

Sorting

Sorting collections

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

Sorting collections by multiple criteria

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

Explicit order of sorting

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

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>" \
-H "x-api-key: <your-api-key>"

Example response:

{
  "data": [
    {
      "id": "5f56170c1fca55001ad51779",
      "type": "collection",
      "attributes": {
        "name": "Collection name",
        "ownerId": "5dd7b92abf56ca0011875ae2",
        "application": "rw",
        "env": "production",
        "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>" \
-H "x-api-key: <your-api-key>"

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",
        "env": "production",
        "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>" \
-H "x-api-key: <your-api-key>"

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",
        "env": "production",
        "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.

Delete a collection by user id

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

curl -X DELETE https://api.resourcewatch.org/v1/collection/by-user/:userId \
-H "Authorization: Bearer <your-token>" \
-H "x-api-key: <your-api-key>"

In case of success, the deleted collections are returned in the response body:

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

This endpoint deletes the collections owned by the user with id userId. Any ADMIN user can use this endpoint to delete data for any user, while users with USER or MANAGER roles can only delete their own data.

Errors for deleting a collection by user id

Error code Error message Description
401 Unauthorized You need to be logged in to be able to delete collections.
403 Forbidden You need to either have the ADMIN role, or call this endpoint with your own user id

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"  \
-H "x-api-key: <your-api-key>" -d \
 '{
    "ids": ["5f56170c1fca55001ad51779"],
    "userId": "5dd7b92abf56ca0011875ae2"
  }'

Example response:

{
  "data": [
    {
      "id": "5f56170c1fca55001ad51779",
      "type": "collection",
      "attributes": {
        "name": "Collection name",
        "ownerId": "5dd7b92abf56ca0011875ae2",
        "application": "rw",
        "env": "production",
        "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"  \
-H "x-api-key: <your-api-key>" -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
env Environment to which the collection belongs. Read more about this field in the Environments concept section. 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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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

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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 \
-H "x-api-key: <your-api-key>"

Sorting metadata by multiple criteria

curl -X GET https://api.resourcewatch.org/v1/metadata?sort=name,description \
-H "x-api-key: <your-api-key>"

Sort by name descending, description ascending

curl -X GET https://api.resourcewatch.org/v1/metadata?sort=-name,+description \
-H "x-api-key: <your-api-key>"

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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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> \
-H "x-api-key: <your-api-key>"

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> \
-H "x-api-key: <your-api-key>"

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> \
-H "x-api-key: <your-api-key>"

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 \
-H "x-api-key: <your-api-key>"

Deleting all vocabularies/tag for a widget

curl -X DELETE https://api.resourcewatch.org/v1/dataset/<dataset-id>/widget/<widget-id>/vocabulary \
-H "x-api-key: <your-api-key>"

Deleting all vocabularies/tag for a layer

curl -X DELETE https://api.resourcewatch.org/v1/dataset/<dataset-id>/layer/<layer-id>/vocabulary \
-H "x-api-key: <your-api-key>"

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 \
-H "x-api-key: <your-api-key>"

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.

You can also optionally pass a env string value as a query parameter if you wish to filter the underlying lists of resources by their environment. You can filter by multiple env values (OR logic) using a comma separated list of values.

Getting a single vocabulary

Getting a single vocabulary, all its resources and tags

curl -X GET https://api.resourcewatch.org/v1/vocabulary/<vocabulary-id> \
-H "x-api-key: <your-api-key>"

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.

You can also optionally pass a env string value as a query parameter if you wish to filter the underlying lists of resources by their environment. You can filter by multiple env values (OR logic) using a comma separated list of values.

Getting tags for single vocabulary

Getting the tags for a single vocabulary

curl -X GET https://api.resourcewatch.org/v1/vocabulary/<vocabulary-id>/tags \
-H "x-api-key: <your-api-key>"

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> \
-H "x-api-key: <your-api-key>"

Getting widgets by vocabulary and tag

curl -X GET https://api.resourcewatch.org/v1/dataset/<dataset-id>/widget/vocabulary/find?<vocabulary-id>=<tag> \
-H "x-api-key: <your-api-key>"

Getting layers by vocabulary and tag

curl -X GET https://api.resourcewatch.org/v1/dataset/<dataset-id>/layer/vocabulary/find?<vocabulary-id>=<tag> \
-H "x-api-key: <your-api-key>"

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.

You can also optionally pass a env string value as a query parameter if you wish to filter the underlying lists of resources by their environment. You can filter by multiple env values (OR logic) using a comma separated list of values.

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 stringthrough 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 "x-api-key: <your-api-key>" \
     -H "Content-Type: application/json" \
     -d '{"geojson": <geojson>}'

Example URL request

curl --location --request POST 'https://api.resourcewatch.org/v1/geostore' \
-H "x-api-key: <your-api-key>" \
-H '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 "x-api-key: <your-api-key>" \
-H "Content-Type: application/json" \
-d '{"provider": <provider>}'

Example URL request

curl -X POST https://api.resourcewatch.org/v1/geostore \
-H "x-api-key: <your-api-key>" \
-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> \
-H "x-api-key: <your-api-key>"

Example URL request

curl -X GET https://api.resourcewatch.org/v2/geostore/ca38fa80a4ffa9ac6217a7e0bf71e6df \
-H "x-api-key: <your-api-key>"

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 \
-H "x-api-key: <your-api-key>"

Example URL request

curl -X GET https://api.resourcewatch.org/v2/geostore/ca38fa80a4ffa9ac6217a7e0bf71e6df/view \
-H "x-api-key: <your-api-key>"

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 "x-api-key: <your-api-key>" \
     -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 "x-api-key: <your-api-key>" \
     -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 \
-H "x-api-key: <your-api-key>"

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> \
-H "x-api-key: <your-api-key>"

Example URL request

curl -X GET https://api.resourcewatch.org/v2/geostore/admin/ESP \
-H "x-api-key: <your-api-key>"

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> \
-H "x-api-key: <your-api-key>"

Example URL request

curl -X GET https://api.resourcewatch.org/v2/geostore/admin/ESP/9 \
-H "x-api-key: <your-api-key>"

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> \
-H "x-api-key: <your-api-key>"

Example URL request

curl -X GET https://api.resourcewatch.org/v2/geostore/admin/ESP/1/2 \
-H "x-api-key: <your-api-key>"

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> \
-H "x-api-key: <your-api-key>"

Example URL request

curl -X GET https://api.resourcewatch.org/v2/geostore/wdpa/142809 \
-H "x-api-key: <your-api-key>"

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> \
-H "x-api-key: <your-api-key>"

Example URL request

curl -X GET https://api.resourcewatch.org/v2/geostore/use/logging/1 \
-H "x-api-key: <your-api-key>"

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 \
-H "x-api-key: <your-api-key>" \
  -d '{"geojson": <geojson>}'

Example URL request

curl -X POST https://api.resourcewatch.org/v2/geostore/area \
-H "x-api-key: <your-api-key>" \
  -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>" \
-H "x-api-key: <your-api-key>"

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>" \
-H "x-api-key: <your-api-key>"

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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>" \
-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 "x-api-key: <your-api-key>"
-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>" \
-H "x-api-key: <your-api-key>"

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.

Deleting subscriptions by user id

Example DELETE request for deleting subscriptions by user id:

curl -X DELETE "https://api.resourcewatch.org/v1/subscriptions/by-user/<user_id>" \
-H "Authorization: Bearer <your-token>" \
-H "x-api-key: <your-api-key>"

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"
      }
    }
  ]
}

To delete every subscription associated with a specific user account, the DELETE /v1/subscriptions/by-user/:userId endpoint can be used. If the deletion process is successful, the HTTP response code will be 200 OK, and the response body will contain all the deleted subscriptions. This endpoint requires microservice or ADMIN access, or being logged as the user that wants their subscriptions deleted.

Errors for deleting subscriptions by user id

Error code Error message Description
401 Unauthorized No valid token was provided in the request headers.
403 Forbidden Either the user logged is not the same as the user id that is going to be deleted or is not an ADMIN or microservice.

Confirming a subscription`

Example GET request to confirm a subscription:

curl -X GET "https://api.resourcewatch.org/v1/subscriptions/<subscription_id>/confirm" \
-H "x-api-key: <your-api-key>"

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>" \
-H "x-api-key: <your-api-key>"

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>" \
-H "x-api-key: <your-api-key>"

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>" \
-H "x-api-key: <your-api-key>"

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>" \
-H "x-api-key: <your-api-key>"

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 "x-api-key: <your-api-key>" \
-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>" \
-H "x-api-key: <your-api-key>"

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>" \
-H "x-api-key: <your-api-key>"

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>" \
-H "x-api-key: <your-api-key>"

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>" \
-H "x-api-key: <your-api-key>"

Delete a favourite by user id

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

curl -X DELETE https://api.resourcewatch.org/v1/favourite/by-user/:userId \
-H "Authorization: Bearer <your-token>" \
-H "x-api-key: <your-api-key>"

In case of success, the deleted favourites are returned in the response body:

{
  "data": [
    {
      "id": "5e6f6eb9bb494e001ab7e413",
      "type": "favourite",
      "attributes": {
        "userId": "57ac9f9e2930906323e573a2",
        "resourceType": "dataset",
        "resourceId": "1e56170c1fca55001ad51779",
        "createdAt": "2020-03-16T12:19:05.125Z",
        "application": "rw"
      }
    }
  ]
}

This endpoint deletes the favourites owned by the user with id userId. Any ADMIN user can use this endpoint to delete data for any user, while users with USER or MANAGER roles can only delete their own data.

Errors for deleting a favourites by user id

Error code Error message Description
401 Unauthorized You need to be logged in to be able to delete favourites.
403 Forbidden You need to either have the ADMIN role, or call this endpoint with your own user id

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 \
-H "x-api-key: <your-api-key>"

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 \
-H "x-api-key: <your-api-key>"

This endpoint supports the following filters as query string parameters:

Filter Description Type Default value
application Applications associated to this concept - read more about this field here. String "rw"

List concepts for a dataset

Request to list concepts for a dataset:

curl -X GET https://api.resourcewatch.org/v1/graph/query/list-concepts/:dataset \
-H "x-api-key: <your-api-key>"

Example response:

{
  "data": [
    {
      "id": "4458eb12-8572-45d1-bf07-d5a3ee097021",
      "type": "graph",
      "attributes": {
        "iso": "",
        "synonyms": [
          "Habitat"
        ],
        "id": "habitat",
        "label": "Habitats",
        "default_parent": "ecosystem"
      }
    },
    {
      "id": "4458eb12-8572-45d1-bf07-d5a3ee097021",
      "type": "graph",
      "attributes": {
        "iso": "",
        "synonyms": "",
        "id": "species",
        "label": "Species",
        "default_parent": "biodiversity"
      }
    }
  ]
}

This endpoint returns the list of relationships between the dataset with id provided in the URL path and concepts. If successful, the response will have status 200 OK, containing a list of elements in the data index, each containing the information about one graph relationship. Check out the Graph relationship reference for details on each of the fields of the returned response.

If the dataset id provided is not valid or not found, the response returned will contain an empty list in the data index.

Filters

Filtering concepts for a dataset by application:

curl -X GET https://api.resourcewatch.org/v1/graph/query/list-concepts/:dataset?application=gfw \
-H "x-api-key: <your-api-key>"

This endpoint supports the following filters as query string parameters:

Filter Description Type Default value
application Applications associated to this concept - read more about this field here. String "rw"

List concepts for multiple datasets

Request to list concepts for multiple datasets:

curl -X POST https://api.resourcewatch.org/v1/graph/find-by-ids \
-H "x-api-key: <your-api-key>" \
-H "Content-Type: application/json" \
-d \
'{
    "ids": [
        "37d04efc-0ab2-4499-a891-54dca1013c74",
        "0448c79d-0ee0-42ff-9331-aeee70cef301"
    ]
}'

Example response:

{
  "data": [
    {
      "type": "concept",
      "attributes": {
        "dataset": "37d04efc-0ab2-4499-a891-54dca1013c74",
        "iso": "",
        "synonyms": "",
        "id": "sanitation",
        "label": "Sanitation",
        "default_parent": "health"
      }
    },
    {
      "type": "concept",
      "attributes": {
        "dataset": "37d04efc-0ab2-4499-a891-54dca1013c74",
        "iso": "",
        "synonyms": [
          "city",
          "urban"
        ],
        "id": "urban",
        "label": "Cities",
        "default_parent": "settlements"
      }
    }
  ]
}

This endpoint returns the list of relationships between the datasets with ids provided in the body of the POST request. If successful, the response will have status 200 OK, containing a list of elements in the data index, each containing the information about one graph relationship. Check out the Graph relationship reference for details on each of the fields of the returned response.

Filters

Filtering concepts for multiple datasets by application:

curl -X GET https://api.resourcewatch.org/v1/graph/find-by-ids?application=gfw \
-H "x-api-key: <your-api-key>"

This endpoint supports the following filters as query string parameters:

Filter Description Type Default value
application Applications associated to this concept - read more about this field here. String "rw"

Errors for listing concepts for multiple datasets

Error code Error message Description
400 Bad Request The ids provided in the body of the request are not correctly formatted.

Infer concepts from other concepts

GET request to infer concepts related to the concepts passed as query parameters:

curl -X GET https://api.resourcewatch.org/v1/graph/query/concepts-inferred?concepts=society,urban \
-H "x-api-key: <your-api-key>" \
-H "Content-Type: application/json"

POST request to infer concepts related with the concepts passed in the request body:

curl -X POST https://api.resourcewatch.org/v1/graph/query/concepts-inferred \
-H "x-api-key: <your-api-key>" \
-H "Content-Type: application/json" \
-d \
'{ "concepts": ["society", "urban"] }'

Example response:

{
  "data": [
    {
      "id": "society",
      "label": "Society",
      "synonyms": [
        "People"
      ],
      "labels": [
        "CONCEPT",
        "TOPIC"
      ]
    },
    {
      "id": "urban",
      "label": "Cities",
      "synonyms": [
        "city",
        "urban"
      ],
      "labels": [
        "CONCEPT",
        "TOPIC"
      ]
    }
  ]
}

This endpoint lets API users discover concepts that have relationships in common with the list of concepts provided. You can use the GET version of the endpoint, providing the list of concepts as a comma-separated string query string parameter. Alternatively, you can use the POST version and provide the list of concepts in the concepts index of the POST request body.

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 inferred concepts by application:

curl -X GET https://api.resourcewatch.org/v1/graph/query/concepts-inferred?application=gfw \
-H "x-api-key: <your-api-key>"

This endpoint supports the following filters as query string parameters:

Filter Description Type Default value
application Applications associated to this concept - read more about this field here. String "rw"

Errors for listing concepts for multiple datasets

Error code Error message Description
400 Concepts are required. A list of concepts was not provided.

Query similar datasets

GET request to find out similar datasets to a dataset with id provided:

curl -X GET https://api.resourcewatch.org/v1/graph/query/similar-dataset/:dataset \
-H "x-api-key: <your-api-key>" \
-H "Content-Type: application/json"

Alternative syntax, providing the dataset id as query string parameter:

curl -X GET https://api.resourcewatch.org/v1/graph/query/similar-dataset?dataset=:dataset \
-H "x-api-key: <your-api-key>" \
-H "Content-Type: application/json"

Example response:

{
  "data": [
    {
      "dataset": "1b97e47e-ca18-4e50-9aae-a2853acca3f0",
      "concepts": [
        "health",
        "urban"
      ]
    },
    {
      "dataset": "51159bdb-4904-4101-a88e-ca7bd4f67cb0",
      "concepts": [
        "infrastructure"
      ]
    }
  ]
}

This endpoint lets API users discover datasets that share concepts with the dataset with id provided in the URL path. If successful, the response will have status 200 OK, containing a list of elements in the data index, each containing the id of the dataset that is related and a list of concepts that are shared.

The results returned are sorted by their degree of similarity, meaning the datasets with the higher number of shared concepts are higher on the list.

Filters

Filtering similar datasets by application:

curl -X GET https://api.resourcewatch.org/v1/graph/query/similar-dataset/:dataset?application=gfw \
-H "x-api-key: <your-api-key>"

This endpoint supports the following filters as query string parameters:

Filter Description Type Default value
application Applications associated with this concept - read more about this field here. String "rw"
env Only list datasets that have the specified environment. String (can be a comma separated list of env values) none

Errors for querying similar datasets

Error code Error message Description
400 Dataset query param required You must provide a valid dataset id.

Query similar datasets including descendants

GET request to find out similar datasets including descendants to a dataset with id provided:

curl -X GET https://api.resourcewatch.org/v1/graph/query/similar-dataset-including-descendant/:dataset \
-H "x-api-key: <your-api-key>" \
-H "Content-Type: application/json"

Alternative syntax, providing the dataset id as query string parameter:

curl -X GET https://api.resourcewatch.org/v1/graph/query/similar-dataset-including-descendant?dataset=:dataset \
-H "x-api-key: <your-api-key>" \
-H "Content-Type: application/json"

Example response:

{
  "data": [
    {
      "dataset": "37d04efc-0ab2-4499-a891-54dca1013c74",
      "concepts": [
        "urban",
        "health",
        "sanitation"
      ],
      "numberOfOcurrences": 1
    },
    {
      "dataset": "223b936e-06b8-4970-abd9-4f123904d95d",
      "concepts": [
        "hunger",
        "famine",
        "health"
      ],
      "numberOfOcurrences": 1
    }
  ]
}

This endpoint lets API users discover datasets that share concepts with the dataset with id provided in the URL path. The difference from the endpoint above is that this endpoint also looks at the ancestor concepts from the dataset with id provided - datasets returned might have ancestor concepts in common, but not necessarily the same exact concepts in common.

If successful, the response will have status 200 OK, containing a list of elements in the data index, each containing the id of the dataset that is related and a list of concepts that are shared. Each list item also contains a numberOfOcurrences field, containing the count of common concepts. The results returned are sorted by their degree of similarity, meaning the datasets with the higher number of shared concepts (numberOfOcurrences) are higher on the list.

Filters

Filtering similar datasets including descendants by application:

curl -X GET https://api.resourcewatch.org/v1/graph/query/similar-dataset-including-descendant/:dataset?application=gfw \
-H "x-api-key: <your-api-key>"

This endpoint supports the following filters as query string parameters:

Filter Description Type Default value
application Applications associated to this concept - read more about this field here. String "rw"
env Only list datasets that have the specified environment. String (can be a comma separated list of env values) none

Errors for querying similar datasets

Error code Error message Description
400 Dataset query param required You must provide a valid dataset id.

Search datasets by concepts

GET request to search datasets by concepts:

curl -X GET https://api.resourcewatch.org/v1/graph/query/search-datasets?concepts[0][0]=:concept \
-H "x-api-key: <your-api-key>" \
-H "Content-Type: application/json"

POST request to search datasets by concepts provided in the request body:

curl -X POST https://api.resourcewatch.org/v1/graph/query/search-datasets \
-H "x-api-key: <your-api-key>" \
-H "Content-Type: application/json" \
-d '{ "concepts": [[":concept"]] }'

Providing multiple sets of concepts as GET request:

curl -X GET https://api.resourcewatch.org/v1/graph/query/search-datasets?concepts[0][0]=spain,concepts[0][1]=europe,concepts[1][0]=water,concepts[2][0]=raster,concepts[2][1]=geospatial \
-H "x-api-key: <your-api-key>" \
-H "Content-Type: application/json"

Providing multiple sets of concepts as POST request:

curl -X GET https://api.resourcewatch.org/v1/graph/query/search-datasets \
-H "x-api-key: <your-api-key>" \
-H "Content-Type: application/json" \
-d '{ 
  "concepts": [
    ["spain", "europe"],
    ["water"],
    ["raster", "geospatial"]
  ] 
}'

Example response:

{
  "data": [
    "11f43558-d703-4b9d-aff0-f2354a11b359",
    "12510410-1eb3-4af0-844f-8a05be50b1c1",
    "1b8f1592-2a92-4dd5-bd85-6d231c7d3229",
    "1b97e47e-ca18-4e50-9aae-a2853acca3f0",
    "371e700e-bc9a-4526-af92-335d888de309",
    "4b000ded-5f4d-4dbd-83c9-03f2dfcd36db",
    "5be16fea-5b1a-4daf-a9e9-9dc1f6ea6d4e",
    "60be01b0-99fb-459c-8a08-b934270f8c4b",
    "63a7a997-695d-4629-b6e9-9b169f5c69bf",
    "795a7ceb-ebc1-4479-95ad-76ea4d045ad3"
  ]
}

This endpoint lets API users discover datasets related to the lists of concepts provided. Note that, either in the GET or POST forms for this endpoint, concepts must be provided as a list of sets. AND logical operators (&&) are applied among the list of sets, while OR (||) is used for set elements. You can provide up to three sets of concepts to search for - the example on the side exemplifies a request to this endpoint given the following sets of concepts:

In this specific case, the datasets returned would be related with "spain" OR "europe", "water", and "raster" or "geospatial". Or, expressed as a logical condition: ("spain" || "europe") && "water" && ("raster" || "geospatial").

If successful, the response will have status 200 OK, containing a list of dataset ids that are related to the concepts provided in the data index. Also, note that ancestor concepts are also taken into account in the search.

Filters

Filtering searched datasets by application:

curl -X GET https://api.resourcewatch.org/v1/graph/query/search-datasets/:dataset?application=gfw \
-H "x-api-key: <your-api-key>"

This endpoint supports the following filters as query string parameters:

Filter Description Type Default value
application Applications associated with this concept - read more about this field here. String "rw"
depth Limits the depth of the graph search. Number 15
env Only list datasets that have the specified environment. String (can be a comma separated list of env values) none

Errors for searching datasets by concepts

Error code Error message Description
400 Concepts query params are required You must provide the list of sets of concepts.

Search datasets by concepts and their synonyms

GET request to search datasets by concepts and their synonyms:

curl -X GET https://api.resourcewatch.org/v1/graph/query/search-by-label-synonyms?search=:search \
-H "x-api-key: <your-api-key>" \
-H "Content-Type: application/json"

Example providing multiple concepts in one request:

curl -X GET https://api.resourcewatch.org/v1/graph/query/search-by-label-synonyms?search=health society \
-H "x-api-key: <your-api-key>" \
-H "Content-Type: application/json"

Example response:

{
  "data": [
    "11f43558-d703-4b9d-aff0-f2354a11b359",
    "12510410-1eb3-4af0-844f-8a05be50b1c1",
    "1b8f1592-2a92-4dd5-bd85-6d231c7d3229",
    "1b97e47e-ca18-4e50-9aae-a2853acca3f0",
    "371e700e-bc9a-4526-af92-335d888de309",
    "4b000ded-5f4d-4dbd-83c9-03f2dfcd36db",
    "5be16fea-5b1a-4daf-a9e9-9dc1f6ea6d4e",
    "60be01b0-99fb-459c-8a08-b934270f8c4b",
    "63a7a997-695d-4629-b6e9-9b169f5c69bf",
    "795a7ceb-ebc1-4479-95ad-76ea4d045ad3"
  ]
}

This endpoint finds datasets in the graph that are related to the concepts provided or any of its synonyms. If successful, the response will have status 200 OK, containing a list of dataset ids in the data index. You can provide multiple concepts by splitting them with blank spaces.

Filters

Filtering searched datasets by application:

curl -X GET https://api.resourcewatch.org/v1/graph/query/search-by-label-synonyms?application=gfw \
-H "x-api-key: <your-api-key>"

This endpoint supports the following filters as query string parameters:

Filter Description Type Default value
application Applications associated to this concept - read more about this field here. String "rw"
env Only list datasets that have the specified environment. String (can be a comma separated list of env values) none

Errors for searching datasets by concepts and their synonyms

Error code Error message Description
400 Search query param required You must provide the search query parameter.

Most liked datasets

GET request to find out which are the most liked datasets:

curl -X GET https://api.resourcewatch.org/v1/graph/query/most-liked-datasets \
-H "x-api-key: <your-api-key>" \
-H "Content-Type: application/json"

Example response:

{
  "data": [
    {
      "id": "c36c3108-2581-4b68-852a-c929fc758001",
      "count": {
        "low": 6,
        "high": 0
      }
    },
    {
      "id": "20cc5eca-8c63-4c41-8e8e-134dcf1e6d76",
      "count": {
        "low": 5,
        "high": 0
      }
    }
  ]
}

This endpoint returns a list of dataset sorted by the number of times these datasets were marked as favorite by users. The returned list is sorted descending, from the datasets with higher favorite count to the ones with a lower count.

If successful, this endpoint will return 200 OK, containing the list of sorted datasets in the data index of the response body. Each element of the list contains the dataset id in the id property and the number of times the dataset was marked as favorite by a user in the count.low property.

Filters

Filtering most liked datasets by application:

curl -X GET https://api.resourcewatch.org/v1/graph/query/most-liked-datasets?application=gfw \
-H "x-api-key: <your-api-key>"

This endpoint supports the following filters as query string parameters:

Filter Description Type Default value
application Applications associated to this concept - read more about this field here. String "rw"
env Only list datasets that have the specified environment. String (can be a comma separated list of env values) none

Most viewed datasets

GET request to find out which are the most viewed datasets:

curl -X GET https://api.resourcewatch.org/v1/graph/query/most-viewed \
-H "x-api-key: <your-api-key>" \
-H "Content-Type: application/json"

Example response:

{
  "data": [
    {
      "dataset": "0087944f-871c-44bc-b4d9-cd5acfc27023",
      "views": 76
    },
    {
      "dataset": "00abb46f-34e2-4bf7-be30-1fb0b1de022f",
      "views": 39
    }
  ]
}

This endpoint returns a list of dataset sorted by the number of times these datasets were viewed by users. The returned list is sorted descending, from the datasets with higher view count to the ones with a lower count.

If successful, this endpoint will return 200 OK, containing the list of sorted datasets in the data index of the response body. Each element of the list contains the dataset id in the dataset property and the number of times the dataset was viewed in the views property.

Note that the concept of view might differ from one application to another. In order to increase the view count of a dataset, an application has to explicitly increment the count for that dataset by calling the increment view endpoint.

Filters

Filtering most viewed datasets by application:

curl -X GET https://api.resourcewatch.org/v1/graph/query/most-viewed?application=gfw \
-H "x-api-key: <your-api-key>"

Limiting the number of returned results:

curl -X GET https://api.resourcewatch.org/v1/graph/query/most-viewed?limit=3 \
-H "x-api-key: <your-api-key>"

This endpoint supports the following filters as query string parameters:

Filter Description Type Default value
application Applications associated with this concept - read more about this field here. String "rw"
limit Limits the number of results returned in the response. Number No limit applied - all results are returned.
env Only list datasets that have the specified environment. String (can be a comma separated list of env values) none

Most viewed datasets by user

GET request to find out which are the most viewed datasets for the token user:

curl -X GET https://api.resourcewatch.org/v1/graph/query/most-viewed \
-H "Authorization: Bearer <your-token>" \
-H "x-api-key: <your-api-key>" \
-H "Content-Type: application/json"

Example response:

{
  "data": [
    {
      "dataset": "0087944f-871c-44bc-b4d9-cd5acfc27023",
      "views": 76
    },
    {
      "dataset": "00abb46f-34e2-4bf7-be30-1fb0b1de022f",
      "views": 39
    }
  ]
}

This endpoint returns a list of dataset sorted by the number of times these datasets were viewed by the user of the token provided in the request headers. The returned list is sorted descending, from the datasets with higher view count to the ones with a lower count.

If successful, this endpoint will return 200 OK, containing the list of sorted datasets in the data index of the response body. Each element of the list contains the dataset id in the dataset property and the number of times the dataset was viewed in the views property.

As in the case of the most-viewed endpoint, please keep in mind that the concept of view might differ from one application to another. In order to increase the view count of a dataset, an application has to explicitly increment the count for that dataset by calling the increment view endpoint.

Filters

Filtering most viewed datasets by the token user by application:

curl -X GET https://api.resourcewatch.org/v1/graph/query/most-viewed-by-user?application=gfw \
-H "x-api-key: <your-api-key>"

Limiting the number of returned results:

curl -X GET https://api.resourcewatch.org/v1/graph/query/most-viewed-by-user?limit=3 \
-H "x-api-key: <your-api-key>"

This endpoint supports the following filters as query string parameters:

Filter Description Type Default value
application Applications associated with this concept - read more about this field here. String "rw"
limit Limits the number of results returned in the response. Number No limit applied - all results are returned.
env Only list datasets that have the specified environment. String (can be a comma separated list of env values) none

Errors for getting most viewed datasets by user

Error code Error message Description
401 Unauthorized You must provide your API user's token in the response headers.

Increment dataset view count

POST request to find out which are the most viewed datasets for the token user:

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

Use this endpoint if you want to increment the view count of the dataset with id provided in the URL path. If successful, this endpoint will return 200 OK containing an empty object in the response body.

You can optionally provide the authentication token for your API user in the request headers. If no token is provided, a dataset view is registered without being associated with any user. If a token is provided, the dataset view count for your API user will be incremented.

Creating resources

The creation of resources on the graph is performed automatically after the creation of each resource, so you don't need to explicitly do it yourself. Because of this, creating resources on the graph is restricted to other RW API services, and requires authentication from a RW API service. Normal API users won't be able to call these endpoints successfully - if you try to do it with a "normal" API user token, you will receive a response with HTTP status code 403 Forbidden.

For details on how these specific endpoints work, you should check out the developer docs for each of the resources supported. The following resources are currently supported as graph nodes:

Deleting resources

The deletion of resources on the graph is performed automatically after the deletion of each resource, so you don't need to explicitly do it yourself. Because of this, deleting resources on the graph is restricted to other RW API services, and requires authentication from a RW API service. Normal API users won't be able to call these endpoints successfully - if you try to do it with a "normal" API user token, you will receive a response with HTTP status code 403 Forbidden.

For details on how these specific endpoints work, you should check out the developer docs for each of the resources supported. The following resources are currently supported as graph nodes:

Relationships between graph nodes and concepts

Getting the list of concepts for a dataset:

curl -X GET https://api.resourcewatch.org/v1/graph/query/list-concepts/:id \
-H "x-api-key: <your-api-key>"

Example response, containing the "urban" concept:

{
  "data": [
    {
      "id": "37d04efc-0ab2-4499-a891-54dca1013c74",
      "type": "graph",
      "attributes": {
        "iso": "",
        "synonyms": [
          "city",
          "urban"
        ],
        "id": "urban",
        "label": "Cities",
        "default_parent": "settlements"
      }
    }
  ]
}

Getting vocabulary for the same dataset:

curl -X GET https://api.resourcewatch.org/v1/dataset/:id/vocabulary \
-H "x-api-key: <your-api-key>"

Example response, containing the "knowledge_graph" vocabulary with the "urban" tag associated:

{
  "data": [
    {
      "id": "knowledge_graph",
      "type": "vocabulary",
      "attributes": {
        "tags": [
          "urban"
        ],
        "name": "knowledge_graph",
        "application": "rw"
      }
    }
  ]
}

Creating (if it doesn't exist yet) the association between the vocabulary "knowledge_graph" and a dataset:

curl -X POST https://api.resourcewatch.org/v1/dataset/:id/vocabulary/knowledge_graph \
-H "x-api-key: <your-api-key>" \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <your-token>' \
-d '{
  "application": "rw",
  "tags": ["urban", "society"]
}'

Editing the association between the vocabulary "knowledge_graph" and a dataset:

curl -X PATCH https://api.resourcewatch.org/v1/dataset/:id/vocabulary/knowledge_graph \
-H "x-api-key: <your-api-key>" \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <your-token>' \
-d '{
  "application": "rw",
  "tags": ["urban"]
}'

Deleting the association between the vocabulary "knowledge_graph" and a dataset:

curl -X DELETE https://api.resourcewatch.org/v1/dataset/:id/vocabulary/knowledge_graph \
-H "x-api-key: <your-api-key>"

The management of connections between resources and concepts is handled by vocabulary endpoints, using the vocabulary "knowledge_graph". Using this vocabulary, you can add tags to your dataset. These tags will be added as concepts, and one (or more, accordingly) graph edges will be created, establishing a connection between your resource and the provided tags.

This section provides some examples of how you can use vocabulary endpoints to manage your resources' concepts. Keep in mind that you can always refer to the vocabulary endpoint documentation for more details on how to use these endpoints.

On the examples on the side, you'll be able to understand that you can map the tags associated with a given resource with the tags associated with the "knowledge_graph" vocabulary for the same resource. You can use vocabulary's endpoints to create (if it doesn't exist yet), edit, or delete the tags associated with that resource. Those changes will be reflected in the concepts that are associated with that same resource.

Lastly, keep in mind that, despite the examples on the side refer to datasets, you can use vocabulary's endpoints to update the tags associated with the "knowledge_graph" vocabulary for all supported resource types: datasets, layers, widgets, and metadata.

Favorite relationships between graph nodes and users

As in the case of managing relationships between graph nodes and concepts, the management of favorite relationships between resources and users is handled by vocabulary endpoints. Please refer to the favorite endpoint documentation for more details on how to use these endpoints.

Graph concept reference

Example concept entity structure:

{
  "id": "society",
  "label": "Society",
  "synonyms": [
    "People"
  ],
  "labels": [
    "CONCEPT",
    "TOPIC"
  ],
  "numberOfDatasetsTagged": 1,
  "datasets": [
    "4458eb12-8572-45d1-bf07-d5a3ee097021"
  ]
}

This section describes the attributes that are present on a graph concept entity:

Field name Type Description
id String The concept unique identifier.
label String A readable version of the concept identifier.
synonyms String | Array The list of synonyms for this concept (or an empty string, if no synonyms exist).
labels Array The list of identifiers for the type of this graph node.
numberOfDatasetsTagged Number The number of datasets that are currently tagged with this concept.
datasets Array The list of dataset ids that are currently tagged with this concept.

Graph relationship reference

Example relationship entity structure:

{
  "id": "4458eb12-8572-45d1-bf07-d5a3ee097021",
  "type": "graph",
  "attributes": {
    "iso": "",
    "synonyms": [
      "Habitat"
    ],
    "id": "habitat",
    "label": "Habitats",
    "default_parent": "ecosystem"
  }
}

This section describes the attributes that are present on a graph relationship entity:

Field name Type Description
id String The id of the relationship (usually the dataset id, if finding concepts related to a dataset).
type String Always set to "graph".
attributes.iso String Deprecated attribute - you should not rely on this attribute.
attributes.synonyms Array A list of synonyms for this concept.
attributes.id String The concept unique identifier.
attributes.label String A readable version of the concept identifier.
attributes.default_parent String The id of the parent concept, if existing.

Areas

Note: the documentation for these endpoints is not maintained and might not be up to date.

The following sections describe endpoints API users can use to interact with version 1 of Areas of Interest.

Get user areas

Getting a list of areas for the current user

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

Response:

{
  "data": [
    {
      "type": "area",
      "id": "59ca3213d08a7d001054522b",
      "attributes": {
        "name": "Test area France",
        "application": "rw",
        "geostore": "8f77fe62cf15d5098ba0ee11c5126aa6",
        "userId": "58e22f662071c01c02f76a0f",
        "env": "production",
        "createdAt": "2017-09-26T10:55:15.990Z",
        "updatedAt": "2017-09-26T10:55:15.990Z",
        "image": "",
        "datasets": [

        ],
        "use": {

        },
        "iso": {

        }
      }
    },
    {
      "type": "area",
      "id": "59ca32ea3209db0014e9a7b7",
      "attributes": {
        "name": "Test custom area",
        "application": "rw",
        "geostore": "b12640deba9d3c5012c5359dd5572e2d",
        "userId": "58e22f662071c01c02f76a0f",
        "env": "production",
        "createdAt": "2017-09-26T10:58:50.226Z",
        "updatedAt": "2017-09-26T10:58:50.226Z",
        "image": "",
        "datasets": [

        ],
        "use": {

        },
        "iso": {

        }
      }
    }
  ]
}

Returns the list of areas created by the user provided.

Filters

Getting a list of areas for the current user and a given application

curl -X GET https://api.resourcewatch.org/v1/area?application=rw
-H "Authorization: Bearer <your-token>" \
-H "x-api-key: <your-api-key>"
Parameter Description Type Values
application Application. Read more about this field here. Text Any Text, values separated by commas
env Environment. Read more about this field here. Text

Pagination

Example request to load page 2 using 25 results per page

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

The Areas 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 areas list.

In the specific case of the Areas service, the default value for the page[size] query parameter is 1000 for backwards compatibility reasons, 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 areas

curl -X GET https://api.resourcewatch.org/v1/area?sort=name \
-H "x-api-key: <your-api-key>"

Sorting areas by multiple criteria

curl -X GET https://api.resourcewatch.org/v1/area?sort=name,createdAt \
-H "x-api-key: <your-api-key>"

Sort by name descending, createdAt ascending

curl -X GET https://api.resourcewatch.org/v1/area?sort=-name,+createdAt \
-H "x-api-key: <your-api-key>"

The Areas service currently supports sorting using the sort query parameter. Sorting areas adheres to the conventions defined in the Sorting guidelines for the RW API, so we strongly recommend reading that section before proceeding.

Create area

Creates a new area

Parameters

Parameter Description Type Values Required
application Application. Read more about this field here. Text Any Text, values separated by commas Yes
name Name of the new area Text Any Text Yes
geostore Geostore ID Text Any Text Yes
env Environment. Read more about this field here. Text Any Text No
curl -X POST https://api.resourcewatch.org/v1/area \
-H "Authorization: Bearer <your-token>" \
-H "x-api-key: <your-api-key>" \
-H "Content-Type: application/json"  -d \
 '{
   "name": <name>,
   "application": <application>,
   "geostore": <geostore id>
 }'

Example

Create an area with name 'Portugal area' and Geostore ID '713899292fc118a915741728ef84a2a7' for the Resource Watch application

curl -X POST https://api.resourcewatch.org/v1/area?application=rw \
-H "Authorization: Bearer <your-token>" \
-H "x-api-key: <your-api-key>" \
-H "Content-Type: application/json"  -d \
 '{
   "name": "Portugal area",
   "application": "rw",
   "geostore": "713899292fc118a915741728ef84a2a7"
 }'
{
  "data": {
    "type": "area",
    "id": "5a0da028e6d876001080c259",
    "attributes": {
      "name": "Portugal area",
      "application": "rw",
      "geostore": "713899292fc118a915741728ef84a2a7",
      "userId": "58e22f662071c01c02f76a0f",              
      "env": "production",
      "createdAt": "2017-11-16T14:26:48.396Z",
      "updatedAt": "2017-11-16T14:26:48.396Z",
      "image": "",
      "datasets": [

      ],
      "use": {

      },
      "iso": {

      }
    }
  }
}

Delete area

Deletes an area

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

Example

curl -X DELETE https://api.resourcewatch.org/v1/area/59ca3213d08a7d001054522b \
-H "Authorization: Bearer <your-token>" \
-H "x-api-key: <your-api-key>"

Delete areas by user id

curl -X DELETE https://api.resourcewatch.org/v1/area/by-user/<user-id> \
-H "Authorization: Bearer <your-token>" \
-H "x-api-key: <your-api-key>"

Example response:

{
  "data": [
    {
      "type": "area",
      "id": "59ca3213d08a7d001054522b",
      "attributes": {
        "name": "Test area France",
        "application": "rw",
        "geostore": "8f77fe62cf15d5098ba0ee11c5126aa6",
        "userId": "58e22f662071c01c02f76a0f",
        "env": "production",
        "createdAt": "2017-09-26T10:55:15.990Z",
        "updatedAt": "2017-09-26T10:55:15.990Z",
        "image": "",
        "datasets": [

        ],
        "use": {

        },
        "iso": {

        }
      }
    },
    {
      "type": "area",
      "id": "59ca32ea3209db0014e9a7b7",
      "attributes": {
        "name": "Test custom area",
        "application": "rw",
        "geostore": "b12640deba9d3c5012c5359dd5572e2d",
        "userId": "58e22f662071c01c02f76a0f",
        "env": "production",
        "createdAt": "2017-09-26T10:58:50.226Z",
        "updatedAt": "2017-09-26T10:58:50.226Z",
        "image": "",
        "datasets": [

        ],
        "use": {

        },
        "iso": {

        }
      }
    }
  ]
}

This endpoint deletes all areas for the provided userId. Any microservice or user with ADMIN role can use this endpoint. Regular users can use this endpoint to delete the areas they own.

Errors for deleting areas by user id

Error code Error message (example) Description
401 Unauthorized No token was provided.
403 Not authorized You are trying to delete the areas of an user that is not the same logged user, not an ADMIN user or a microservice.

Get area

Gets all the information from an area

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

Example

curl -X GET https://api.resourcewatch.org/v1/area/59ca32ea3209db0014e9a7b7 \
-H "Authorization: Bearer <your-token>" \
-H "x-api-key: <your-api-key>"
{
    "data": {
        "type": "area",
        "id": "59ca32ea3209db0014e9a7b7",
        "attributes": {
            "name": "Test custom area",
            "application": "rw",
            "geostore": "b12640deba9d3c5012c5359dd5572e2d",
            "userId": "58e22f662071c01c02f76a0f",
            "env": "production",
            "createdAt": "2017-09-26T10:58:50.226Z",
            "updatedAt": "2017-09-26T10:58:50.226Z",
            "image": "",
            "datasets": [],
            "use": {},
            "iso": {}
        }
    }
}

Areas v2

Before reading any further, please ensure you have read the Areas of Interest concept documentation first. It gives you a brief and clear description of what an Area of Interest 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 Areas service. Areas of Interest are used by the Global Forest Watch website to subscribe to notifications on deforestation and fire alerts inside a particular areas you might be interest in. The sections below describe in detail how you can use the endpoints provided by RW API's Areas service to define your own geographic areas of interest.

What is the difference between v1 and v2?

v2 areas are an upgrade in the functionality of the Areas service, and provide you with an easier-to-use interface for creating Areas of Interest. Features such as the notification of alerts inside your Area of Interest are only available in v2 endpoints.

Up until v2 areas endpoints were available, you could create Areas of Interest, but you could not define deforestation or fire alerts for your areas. In order to do that, you would need to manually create a subscription that referenced your Area of Interest. Not only that, but you also needed to manage this interaction between Areas of Interest and Subscriptions by yourself.

v2 areas endpoints were built with the intention of automating this interaction between areas and subscriptions, thus merging together v1 areas of interest and subscriptions. In practice, this means that, if your users already had v1 areas or subscriptions previously created, they will show up as v2 areas when requesting data from the v2 endpoints. This also means that, if your application was already using either subscriptions or v1 areas, you can safely transition into v2 areas while keeping the legacy v1 areas and subscriptions that your users have created.

Throughout the sections below, you'll be able to find Implementation details sections that dive deeper into how this synchronization between Areas and Subscriptions is performed on each particular case.

Interaction between Areas and Subscriptions

As it was stated in the paragraphs above, you can use v2 endpoint to create Areas of Interest and subscribe to deforestation of fire alerts. These subscriptions (and the associated emails or webhook notifications) are handled by the Subscriptions service. This means in practice that each Area might have a Subscription associated. If this is the case, the Area's subscriptionId property will contain the id of the associated Subscription from the Subscriptions service.

This interaction between Areas and Subscriptions is transparent for the API users, meaning that you don't need to worry about creating, updating or deleting the subscriptions associated to your areas - this happens automatically, taken into account the Area properties.

Getting all user areas

Example request to get all areas for the logged user:

curl -X GET https://api.resourcewatch.org/v2/area \
  -H "Authorization: Bearer <your-token>" \
-H "x-api-key: <your-api-key>"

Example response:

{
    "data": [
        {
            "type": "area",
            "id": "5e4d74c3ef240412c2d56a71",
            "attributes": {
                "application": "gfw",
                "userId": "5e2f0eaf9de40a6c87dd9b7d",
                "createdAt": "2020-02-19T12:17:01.176Z",
                "datasets": [],
                "use": {},
                "env": "production",
                "iso": {},
                "admin": {},
                "tags": [],
                "status": "saved",
                "public": false,
                "fireAlerts": false,
                "deforestationAlerts": false,
                "webhookUrl": "",
                "monthlySummary": false,
                "subscriptionId": "5e4d273dce77c53768bc24f9",
                "email": "your.email@resourcewatch.org",
                "language": "en"
            }
        }
    ]
}

The /v2/areas endpoint returns all the areas of interest associated with the user who made the request. For a detailed description of each field, check out the Area reference section.

Pagination

Example request to load page 2 using 25 results per page

curl -X GET https://api.resourcewatch.org/v2/area?page[number]=2&page[size]=25 \
-H "x-api-key: <your-api-key>"

The Areas v2 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 areas list.

In the specific case of the Areas v2 service, the default value for the page[size] query parameter is 100, instead of 10. However, this default value will be reduced to 10 in future releases, so (as recommended in the pagination guidelines), you should not rely on the default page size and always provide a value tailored to your needs.

Filters

Filtering areas

curl -X GET https://api.resourcewatch.org/v2/area?application=rw&public=true \
-H "x-api-key: <your-api-key>"

The /v2/areas endpoint provides the following parameters to tailor the returned listing:

Field Description Type Example
application Filter results by the application associated with the areas. String 'gfw'
status Filter results by the status of the area. String 'saved'
public Filter results by the privacy status of the area. Boolean true
env Environment to which the area 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.
all Return all the areas instead of just the areas associated with user of the request. This filter will only be taken into account for ADMIN users. Boolean true

Sorting

Sorting areas

curl -X GET "https://api.resourcewatch.org/v2/area?sort=name" \
-H "x-api-key: <your-api-key>"

Sorting layers by multiple criteria

curl -X GET "https://api.resourcewatch.org/v2/area?sort=name,status" \
-H "x-api-key: <your-api-key>"

Explicit order of sorting

curl -X GET "https://api.resourcewatch.org/v2/area?sort=-name,+status" \
-H "x-api-key: <your-api-key>"

The Areas v2 service currently supports sorting using the sort query parameter. Sorting v2 areas 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 Area reference section for a detailed description of the fields you can use when sorting.

Errors for getting user areas

Error code Error message (example) Description
401 Unauthorized No authorization token was provided.

Implementation details

Finds all areas for the user who requested the list of areas. For each area, if it has an associated subscription (i.e. the subscriptionId field of the area is not empty), it merges the subscription data over the area data, returning it as a single object. After that, the remaining user subscriptions are converted to area objects and returned.

Getting all areas

Example request to get ALL areas (only available for ADMIN users):

curl -X GET https://api.resourcewatch.org/v2/area?all=true \
  -H "Authorization: Bearer <your-token>" \
-H "x-api-key: <your-api-key>"

Example response:

{
    "data": [
        {
            "type": "area",
            "id": "5e4d74c3ef240412c2d56a71",
            "attributes": {
                "application": "gfw",
                "userId": "5e2f0eaf9de40a6c87dd9b7d",
                "createdAt": "2020-02-19T12:17:01.176Z",
                "updatedAt": "2020-02-19T12:17:01.176Z",
                "datasets": [],
                "use": {},
                "env": "production",
                "iso": {},
                "admin": {},
                "tags": [],
                "status": "saved",
                "public": false,
                "fireAlerts": false,
                "deforestationAlerts": false,
                "webhookUrl": "",
                "monthlySummary": false,
                "subscriptionId": "5e4d273dce77c53768bc24f9",
                "email": "your.email@resourcewatch.org",
                "language": "en"
            }
        }
    ],
    "links": {
        "self": "https://api.resourcewatch.org/v2/area?all=true&page[number]=1&page[size]=10",
        "first": "https://api.resourcewatch.org/v2/area?all=true&page[number]=1&page[size]=10",
        "last": "https://api.resourcewatch.org/v2/area?all=true&page[number]=1&page[size]=10",
        "prev": "https://api.resourcewatch.org/v2/area?all=true&page[number]=1&page[size]=10",
        "next": "https://api.resourcewatch.org/v2/area?all=true&page[number]=1&page[size]=10"
    },
    "meta": {
        "total-pages": 1,
        "total-items": 1,
        "size": 10
    }
}

The same /v2/areas endpoint, used to retrieve all of the logged user's areas, can be used to retrieve ALL areas (for all users). To trigger this behavior, all you need to do is provide the all=true flag as a query parameter - keep in mind this option will only be taken into account for ADMIN users (i.e. if the logged user is not an ADMIN, the all=true flag is ignored and the logged user's areas are returned).

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

Pagination

Example request to load page 2 using 25 results per page

curl -X GET https://api.resourcewatch.org/v2/area?page[number]=2&page[size]=25&all=true \
-H "x-api-key: <your-api-key>"

The Areas v2 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 areas list.

Filters

Filtering areas

curl -X GET https://api.resourcewatch.org/v2/area?application=rw&public=true&all=true \
-H "x-api-key: <your-api-key>"

The filters for this endpoint are the same as the /v2/areas endpoint described above:

Field Description Type Example
application Filter results by the application associated with the areas. Read more about this field here. String 'gfw'
status Filter results by the status of the area. String 'saved'
public Filter results by the privacy status of the area. Boolean true
env Environment to which the area 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.
all Return all the areas instead of just the areas associated with user of the request. This filter will only be taken into account for ADMIN users. Boolean true

Errors for getting all areas

Error code Error message (example) Description
401 Unauthorized No authorization token was provided.

Implementation details

If the all=true query filter is provided, the /find-all endpoint of the Subscriptions service is used to find all existing subscriptions (for all users).

Then, for each area in the Areas service database, if it has an associated subscription (i.e. the subscriptionId field of the area is not empty), it merges the subscription data over the area data, returning it as a single object. After that, the remaining subscriptions are converted to area objects and returned.

Getting an area by its id

curl -X GET https://api.resourcewatch.org/v2/area/:id \
  -H "Authorization: Bearer <your-token>" \
-H "x-api-key: <your-api-key>"

Example response:

{
    "data": {
        "type": "area",
        "id": "5e4d787bef240412c2d56a74",
        "attributes": {
            "application": "gfw",
            "userId": "5e2f0eaf9de40a6c87dd9b7d",
            "createdAt": "2020-02-19T12:17:01.176Z",
            "updatedAt": "2020-02-19T12:17:01.176Z",
            "datasets": [],
            "use": {},
            "env": "production",
            "iso": {},
            "admin": {},
            "tags": [],
            "status": "saved",
            "public": false,
            "fireAlerts": false,
            "deforestationAlerts": false,
            "webhookUrl": "",
            "monthlySummary": false,
            "subscriptionId": "5e4d273dce77c53768bc24f9",
            "email": "tiago.garcia@vizzuality.com",
            "language": "en"
        }
    }
}

If you know the id or the slug of a area, then you can access it directly - keep in mind the id search is case-sensitive. If the area has the public attribute set to false, you will only be able to fetch its information if you are the owner of the area. If the area has the public attribute set to true and the user who requests it is not the owner, some information will be hidden for privacy reasons.

Errors for getting an area by its id

Error code Error message (example) Description
401 Unauthorized No authorization token was provided.
401 Area private You are trying to get the information of a private area without being the owner of the area.

Implementation details

Try to find an area with the id provided:

  1. If the area exists:
    1. If the area has an associated subscription, the subscription is fetched, its data is merged over the area and the result is returned.
    2. If the area has no subscription associated, the area data is returned.
  2. If the area does not exist:
    1. Try to find a subscription with the id provided. If it exists, it is returned as an area object, if not, a 404 Not Found error is returned.

Creating an area

Example request to create an area

curl -X POST https://api.resourcewatch.org/v2/area \
-H "Authorization: Bearer <your-token>" \
-H "x-api-key: <your-api-key>" \
-H "Content-Type: application/json" -d \
 '{
    "name": "Example area",
    "application": "gfw",
    "image": "",
    "tags": [],
    "public": false,
    "fireAlerts": true,
    "deforestationAlerts": true,
    "webhookUrl": "https://example.com",
    "monthlySummary": true,
    "email": "youremail@resourcewatch.org",
    "language": "en"
}'

Example request to create an area with an associated image

curl --location --request POST 'https://api.resourcewatch.org/v2/area' \ \
-H "x-api-key: <your-api-key>"
-H 'Authorization: Bearer <your-token>' \
--form 'name="Example area"' \
--form 'geostore="a15899292fc118a345741728ef84a21a"' \
--form 'deforestationAlerts="true"' \
--form 'deforestationAlertsType="glad-s2"' \
--form 'image=@"/home/user/image.jpg"'

Example response:

{
    "data": {
        "type": "area",
        "id": "5e4d7c47ef240412c2d56a78",
        "attributes": {
            "name": "Example area",
            "application": "gfw",
            "wdpaid": null,
            "userId": "5e2f0eaf9de40a6c87dd9b7d",
            "createdAt": "2020-02-19T18:19:51.485Z",
            "updatedAt": "2020-02-19T18:19:51.485Z",
            "image": "https://s3.amazonaws.com/image.jpg",
            "env": "production",  
            "datasets": [],
            "tags": [],
            "status": "pending",
            "public": false,
            "fireAlerts": true,
            "deforestationAlerts": true,
            "webhookUrl": "https://example.com",
            "monthlySummary": true,
            "subscriptionId": "5e4d7c47dd8fa31290d548ae",
            "email": "youremail@resourcewatch.org",
            "language": "en"
        }
    }
}

Use this endpoint to create new areas. For a detailed description of each field that can be provided in the body of the request, check out the Area reference section.

Keep in mind that you should provide one of the following when creating an area:

According to multiple factors (including the geostore that is associated with the area, if the area subscribes to fireAlerts, deforestationAlerts, etc.), there might be a period of time in which the data for the area is being generated. While that is the case, the area will have status set to 'pending'. Once the area data is ready, the status of the area will be updated to 'saved'.

Errors for creating an area

Error code Error message (example) Description
400 <field> can not be empty. You are missing a required field while creating the area.
400 <field> is not valid. You provided an invalid field while creating the area.
400 geostore and geostoreDataApi are mutually exclusive, cannot provide both at the same time You are trying to provide geostore and geostoreDataApi at the same time, and only one of the fields can be provided.
401 Unauthorized No token was provided.

Email notifications

After creating an area, if the email field of the area contains a valid email address, an email is sent to the user. The email content varies according to the status of the area:

If you want to understand more about how these emails are sent or how you can update its content, please check the developer docs section on Areas v2 Email Notifications.

Implementation details

POST of a new area always starts by creating the area. Then, taking into account the area attributes, it might also create a subscription which will then be associated with the area. The area's subscriptionId attribute will then be updated with the id of the created subscription if that's the case. The created area is then returned.

The subscription is created only if the area has selected set to true at least one of the following attributes:

Updating an area

Example request to update an area

curl -X PATCH https://api.resourcewatch.org/v2/area/:id \
-H "Authorization: Bearer <your-token>" \
-H "x-api-key: <your-api-key>" \
-H "Content-Type: application/json" -d \
 '{
    "name": "Example area",
    "application": "gfw",
    "tags": [],
    "public": false,
    "fireAlerts": true,
    "deforestationAlerts": true,
    "webhookUrl": "https://example.com",
    "monthlySummary": true,
    "email": "youremail@resourcewatch.org",
    "language": "en"
}'

Example request to update an area with an associated image

curl --location --request PATCH 'https://api.resourcewatch.org/v2/area/:id' \ \
-H "x-api-key: <your-api-key>"
-H 'Authorization: Bearer <your-token>' \
--form 'name="Example area"' \
--form 'geostore="a15899292fc118a345741728ef84a21a"' \
--form 'deforestationAlerts="true"' \
--form 'deforestationAlertsType="glad-s2"' \
--form 'image=@"/home/user/image.jpg"'

Example response:

{
    "data": {
        "type": "area",
        "id": "5e4d7c47ef240412c2d56a78",
        "attributes": {
            "name": "Example area",
            "application": "gfw",
            "wdpaid": null,
            "userId": "5e2f0eaf9de40a6c87dd9b7d",
            "createdAt": "2020-02-19T18:19:51.485Z",
            "updatedAt": "2020-05-29T22:17:12.176Z",
            "image": "https://s3.amazonaws.com/image.jpg",
            "env": "production",
            "datasets": [],
            "tags": [],
            "status": "pending",
            "public": false,
            "fireAlerts": true,
            "deforestationAlerts": true,
            "webhookUrl": "https://example.com",
            "monthlySummary": true,
            "subscriptionId": "5e4d7c47dd8fa31290d548ae",
            "email": "youremail@resourcewatch.org",
            "language": "en"
        }
    }
}

Use this endpoint to update an existing area. For a detailed description of each field that can be provided in the body of the request, check out the Area reference section. Keep in mind that you must provide one of the following when updating an area:

Please check the Area model reference for details on what values each field is expected to provide.

Errors for updating an area

Error code Error message (example) Description
400 <field> can not be empty. You are missing a required field while updating the area.
400 <field> is invalid. You provided an invalid field while updating the area.
400 Id required No id was provided in the URL.
400 geostore and geostoreDataApi are mutually exclusive, cannot provide both at the same time You are trying to provide geostore and geostoreDataApi at the same time, and only one of the fields can be provided.
401 Unauthorized No token was provided.
403 Not authorized You are trying to update an area that is not owned by you and you are not an ADMIN user.
404 Area not found The area with id provided does not exist.

Email notifications

After updating an area, if the email field of the area contains a valid email address and the area's status is saved, an email is sent to let the user know the area of interest is ready to be viewed.

If you want to understand more about how these emails are sent or how you can update its content, please check the developer docs section on Areas v2 Email Notifications.

Implementation details

PATCHing an area is a bit more complex, and it comes down to 3 major cases:

  1. The area already exists and has subscriptions preference (deforestationAlerts, fireAlerts or monthlySummary set to true) in the request data:
    1. If the area doesn't have a subscription associated, a new one is created and associated.
    2. If the area already had a subscription, then the subscription is PATCHed according to the data provided in the request body.
  2. The area already exists and doesn’t has subscription preferences (deforestationAlerts, fireAlerts or monthlySummary set to true) in the request data:
    1. If the area had a subscription associated, then the subscription associated is deleted.
    2. Otherwise, just save the area.
  3. The area doesn’t exist because on the fetch it returned a mapped subscription (meaning we are PATCHing an area using the id of a subscription):
    1. First, create a new area, and then:
      1. If the request data has subscriptions preference (deforestationAlerts, fireAlerts or monthlySummary set to true), also PATCH the subscription.
      2. If the request data doesn't have subscriptions preference (deforestationAlerts, fireAlerts or monthlySummary set to true), delete the associated subscription.

Deleting an area

curl -X DELETE https://api.resourcewatch.org/v2/area/:id \
  -H "Authorization: Bearer <your-token>" \
-H "x-api-key: <your-api-key>" 

Returns 204 No Content in case of success.

Use this endpoint to delete an existing area. This endpoint requires authentication and, in order to DELETE an area, you need to be either the owner of the area or an ADMIN user.

DELETing an area deletes the area with id provided and any associated subscription with the area being deleted (identified by the id stored in the subscriptionId field). This is done transparently from the perspective of an API user, so no action is needed to trigger this behavior.

Errors for deleting an area

Error code Error message (example) Description
400 Id required No id was provided in the URL.
401 Unauthorized No token was provided.
403 Not authorized You are trying to delete an area that is not owned by you and you are not an ADMIN user.
404 Area not found The area with id provided does not exist.

Deleting areas by user id

curl -X DELETE https://api.resourcewatch.org/v2/area/by-user/:user-id \
-H "Authorization: Bearer <your-token>" \
-H "x-api-key: <your-api-key>"

Example response:

{
    "data": [
        {
            "type": "area",
            "id": "5e4d74c3ef240412c2d56a71",
            "attributes": {
                "application": "gfw",
                "userId": "5e2f0eaf9de40a6c87dd9b7d",
                "createdAt": "2020-02-19T12:17:01.176Z",
                "datasets": [],
                "use": {},
                "env": "production",
                "iso": {},
                "admin": {},
                "tags": [],
                "status": "saved",
                "public": false,
                "fireAlerts": false,
                "deforestationAlerts": false,
                "webhookUrl": "",
                "monthlySummary": false,
                "subscriptionId": "5e4d273dce77c53768bc24f9",
                "email": "your.email@resourcewatch.org",
                "language": "en"
            }
        }
    ]
}

This endpoint deletes all areas for the provided userId. Any microservice or user with ADMIN role can use this endpoint. Regular users can use this endpoint to delete the areas they own.

Errors for deleting areas by user id

Error code Error message (example) Description
401 Unauthorized No token was provided.
403 Not authorized You are trying to delete the areas of an user that is not the same logged user, not an ADMIN user or a microservice.

Update areas by geostore

Example request to update all areas that reference geostores with ids "123" and "234":

curl -X POST https://api.resourcewatch.org/v2/area/update \
-H "Authorization: Bearer <your-token>" \
-H "x-api-key: <your-api-key>" \
-H "Content-Type: application/json" -d \
 '{
    "geostores": ["123", "234"],
    "update_params": {
        "status": "saved",
        "name": "Updated Area"
    }
}'

Example response:

{
    "data": [
        {
            "type": "area",
            "id": "5e4d74c3ef240412c2d56a71",
            "attributes": {
                "application": "gfw",
                "userId": "5e2f0eaf9de40a6c87dd9b7d",
                "createdAt": "2020-02-19T12:17:01.176Z",
                "updatedAt": "2020-05-29T22:17:12.176Z",
                "datasets": [],
                "use": {},
                "env": "production",
                "iso": {},
                "admin": {},
                "tags": [],
                "status": "saved",
                "public": false,
                "fireAlerts": false,
                "deforestationAlerts": false,
                "webhookUrl": "",
                "monthlySummary": false,
                "subscriptionId": "5e4d273dce77c53768bc24f9",
                "email": "tiago.garcia@vizzuality.com",
                "language": "en"
            }
        }
    ]
}

Use this endpoint to batch update multiple areas that are associated with one of the geostore ids provided in the request body. In order to use this endpoint, you need to be authenticated as an ADMIN user.

You can use the update_params field of the request body to specify multiple fields to update on the areas that belong to the geostore ids provided in the body. Keep in mind that the same validations as when updating an area are applied. If a validation fails, the request will fail with 400 Bad Request and no area will be updated.

In case of success a 200 OK response is returned, and all the areas that match the update criteria (belonging to one of the geostores provided in the request body) will be returned.

Email notifications

After updating areas by geostore, for each area that was updated which has a valid email address associated and its status updated to saved, an email will be sent to the user to let them know that the area is ready to be viewed.

If you want to understand more about how these emails are sent or how you can update its content, please check the developer docs section on Areas v2 Email Notifications.

Sync areas

curl -X POST https://api.resourcewatch.org/v2/area/sync \
  -H "Authorization: Bearer <your-token>" \
-H "x-api-key: <your-api-key>"

Example response:

{
    "data": {
        "syncedAreas": 8,
        "createdAreas": 0
    }
}

Example snippet that synchronizes the areas before fetching the information of ALL areas:

// First call the sync endpoint
await request.post('v2/area/sync');

// Then call the get endpoint while there are more pages to find
var results = [];
var hasNextPage = true;
var pageNumber = 1;
while (hasNextPage) {
   var res = await request.get('v2/area?all=true&page[number]=' + pageNumber);
   results = results.concat(res.data);
   pageNumber++;
   hasNextPage = res.links.self === res.links.last;
}

Use this endpoint to synchronize each area information with the associated subscription. The usage of this endpoint is recommended if you are performing update processes that rely on updated subscription information for the areas.

This endpoint supports the following query parameters to control the execution of the sync:

Field Description Type Example
startDate The date from which the sync will be executed. All subscriptions that have been updated since this date will be synced with the existing areas. String 2020-03-18T09:45:56.476Z
endDate The date until which the sync will be executed. All subscriptions that have been updated until this date will be synced with the existing areas. String 2020-03-25T09:45:56.476Z

Note: By default, the sync is done for the last week changes (i.e. the default value for the startDate parameter is one week ago and the default value for the endDate parameter is now).

Area reference

This section gives you a complete view at the properties that are maintained as part of an area. When interacting with an area (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 area. Auto generated on creation. Cannot be modified by users.
name String No Name of the area.
application String Yes 'gfw' The application this area belongs to.
env String Yes production Environment to which the area belongs. Read more about this field in the Environments concept section.
geostore String No If this area references a geostore obtained from RW API's Geostore service, the id of that geostore will be saved in this field.
geostoreDataApi String No If this area references a geostore obtained from the GFW Data API, the id of that geostore will be saved in this field.
wdpaId String No If this area references a WDPA, the id of the WDPA will be saved in this field.
userId String Yes (autopopulated) Id of the user who owns the area. Set automatically on creation. Cannot be modified by users.
use Object No If this area references a land use concession, this field will contain an object that identifies the concrete area referred.
use.id String No The id of the land use concession to track.
use.name String No The name of the land use concession to track. The supported values for this field include mining for mining areas, logging for Congo Basin logging roads, oilpalm for palm oil plantations and fiber for wood fiber plantations.
iso Object No If this area references an admin country or region, this field will contain an object that identifies the concrete area referred.
iso.country String No The ISO 3166-1 alpha-3 code of the country being referred by this area.
iso.region String No The GADM id of the region inside the country to reference (optional, you can reference the whole country, or just on specific region of the country).
iso.subregion String No The GADM id of the subregion inside the region to reference (optional, you can reference the whole region, or just on specific subregion of the region).
admin Object No Alternative syntax, see the iso field above.
admin.adm0 String No Alternative syntax, see the iso.country field above.
admin.adm1 String No Alternative syntax, see the iso.region field above.
admin.adm2 String No Alternative syntax, see the iso.subregion field above.
image String No URL for an image representative of the area of interest. When creating/updating areas, you can optionally attach a file to your request, which will be uploaded to a public image repository, and the URL for it will be returned in subsequent GET requests for said areas. Do not upload private/sensitive images.
templateId String No ?
tags Array Yes [] Array of string tags that can be used to categorize areas.
status String Yes 'pending' The status of the area - can be one of pending, saved or failed. Cannot be modified by users. Initially, it is set as pending. Once all the data for the area is crunched and ready to be read, the status is updated to saved and an email is sent to the user. If errors occur, the status is set to failed.
public Boolean Yes false If the area is public or private. Public area information can be accessed by other users.
fireAlerts Boolean Yes false If the area subscribes to notifications on fire alerts - set this field to true if you wish to be notified about fire alerts in your area of interest.
deforestationAlerts Boolean Yes false If the area subscribes to notifications on deforestation alerts - set this field to true if you wish to be notified about deforestation alerts in your area of interest.
monthlySummary Boolean Yes false If the area subscribes to monthly summary notifications - set this field to true if you wish to be notified monthly about deforestation and fire alerts in your area of interest.
email String No The email that will be used as receiver of the notification emails.
webhookUrl String No Instead of receiving an email as notification, you can choose to receive a hit in the webhook URL you set in this field.
language String No 'en' The language in which you wish to receive the email notifications. en, fr, zh, id, pt_BR or es_MX are the supported values for this field. If any other value is provided, en is automatically set.
subscriptionId String No If an area is returned as the reflection of an existing subscription in the Subscriptions service, this field will contain the id of the corresponding subscription.
createdAt Date No (autogenerated) now Automatically maintained date of when the area was created. Cannot be modified by users.
updatedAt Date No (autogenerated) now Automatically maintained date of when the area was last updated. Cannot be modified by users.

Webshot

The webshot set of endpoints allows you to capture a given page as a document file, that can then be used, for example, as a preview thumbnail.

This service has two endpoints:

PDF

This endpoint expects a URL as a query parameter and generates a pdf containing a rendered version of that page:

curl -X GET \
  'https://api.resourcewatch.org/v1/webshot/pdf?url=https://google.com&filename=my-google-screenshoz.pdf' \
  -H "x-api-key: <your-api-key>" \
  -H 'Authorization: Bearer <your-token>' \
  -H 'Content-Type: application/json' \

The endpoint accepts the following optional parameters:

It is important to take into account that this endpoint works by rendering the https://resourcewatch.org/embed/widget/<widget id> URL with those dimensions applied to the viewport. So the resulting screenshot will have the proportional size of the corresponding DOM element within that viewport, and not the exact height and width specified.

Widget thumbnail

This endpoint generates a thumbnail image for the provided widget and stores it on AWS S3.

curl -X POST \
  https://api.resourcewatch.org/v1/webshot/widget/7b540186-9a9f-4e13-a6e8-f38e64fab2e1/thumbnail \
  -H "x-api-key: <your-api-key>" \
  -H 'Authorization: Bearer <your-token>' \
  -H 'Content-Type: application/json' \
{
    "data": {
        "widgetThumbnail": "https://s3.amazonaws.com/resourcewatch/thumbnails/<filename>.png"
    }
}

This endpoint accepts two optional query parameters, height and width, that configure the size of the generated screenshot. Keep in mind that this endpoint works by rendering the https://resourcewatch.org/embed/widget/<widget id> URL with those dimensions applied to the viewport, and then captures the content of the .widget-content DOM element into an image file. As such, the resulting screenshot will have the proportional size of the corresponding DOM element within that viewport, and not the exact height and width specified.

Layer thumbnail

This endpoint generates a thumbnail image for the provided layer and stores it on AWS S3.

curl -X POST \
  https://api.resourcewatch.org/v1/webshot/layer/7b540186-9a9f-4e13-a6e8-f38e64fab2e1/thumbnail \
  -H "x-api-key: <your-api-key>" \
  -H 'Authorization: Bearer <your-token>' \
  -H 'Content-Type: application/json' \
{
    "data": {
        "layerThumbnail": "https://s3.amazonaws.com/resourcewatch/thumbnails/<filename>.png"
    }
}

This endpoint accepts two optional query parameters, height and width, that configure the size of the generated screenshot. Keep in mind that this endpoint works by rendering the https://resourcewatch.org/embed/layer/<layer id> URL with those dimensions applied to the viewport, and then captures the content of the .layer-content DOM element into an image file. As such, the resulting screenshot will have the proportional size of the corresponding DOM element within that viewport, and not the exact height and width specified.

Topic

What is a Topic?

A topic contains the information to display a web page belonging to a user.

Getting all topics

This endpoint will allow to get all topics belonging to a user:

curl -X GET https://api.resourcewatch.org/v1/topic -H 'Authorization: Bearer exampleToken' \
-H "x-api-key: <your-api-key>"

Response:

{
    "data": [
        {
            "id": "10",
            "type": "topics",
            "attributes": {
                "name": "Cities topic",
                "slug": "cities-topic",
                "summary": "",
                "description": "",
                "content": "<p></p>\n<iframe width=\"500\" height=\"410\" src=\"/embed/widget/5ebeddda-8f3d-4e63-8a52-08e15c3e148c\" frameBorder=\"0\"></iframe>\n<p></p>\n<iframe width=\"500\" height=\"410\" src=\"/embed/widget/73c574b9-f9ab-4f77-87be-651ff8dac5fe\" frameBorder=\"0\"></iframe>\n<p>test1</p>\n",
                "published": true,
                "env": "production",
                "photo": {
                    "cover": "https://s3.amazonaws.com/image.jpg",
                    "thumb": "https://s3.amazonaws.com/image.jpg",
                    "original": "https://s3.amazonaws.com/image.jpg"
                },
                "user-id": "eb63867922e16e34ef3ce862",
                "private": true,
                "application":  ["rw"]
            }
        },
        ...
      ]
}

Filters

Available filters parameters:

Field Description Type
published Filter topics by publishing status (true, false) Boolean
private Filter topics by private status (true, false) Boolean
user Filter topics by author user id Text
application The application to which the topic belongs. Read more about this field here. Text (single value)
env Environment to which the topic 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
curl -X GET https://api.resourcewatch.org/v1/topic?user=57bc2608f098ce98007985e4&private=false \
-H "x-api-key: <your-api-key>"
# Deprecated syntax
curl -X GET https://api.resourcewatch.org/v1/topic?filter[user]=57bc2608f098ce98007985e4&filter[private]=false \
-H "x-api-key: <your-api-key>"

Sorting

There's currently no support for custom sorting of topics. The topics are listed on a pseudo-random order.

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

User

Loads the name and email address of the author of the topic. 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.

Please keep in mind that, due to the limitations of the underlying endpoint used to find users by ids, the performance of the request while including user information might be degraded.

curl -X GET https://api.resourcewatch.org/v1/topic?includes=user \
-H "x-api-key: <your-api-key>"

Example response:

{
    "data": [
      {
        "id": "86",
        "type": "topics",
        "attributes": {
          "name": "Test topic three",
          "slug": "test-topic-three-cd4305e9-e3c8-456b-85a0-32eccb6100e6",
          "summary": "test topic three summary",
          "description": "test topic three description",
          "content": "test topic three description",
          "published": true,
          "env": "production",
          "user-id": "57ac9f9e29309063404573a2",
          "application":  ["rw"],
          "user": {
            "name": "John Doe",
            "role": "ADMIN",
            "email": "john.doe@vizzuality.com"
          }
        }
      }
   ]
}

Creating a topic

When creating a topic, the application field should be present and cannot contain any values that are not associated with the creating user's account. If an application value is not provided, ["rw"] is used by default, and the process will fail if the user account does not belong to it. Any role can create a topic.

Supported fields:

Name Description Accepted values
name Short name for the topic any valid text
slug Unique identifier for the topic any valid text
summary Summary of the content of the topic any valid text
description Description of the topic any valid text
content Content of the topic, typically encoded as a JSON string any valid text
published If the topic is in a publishable state boolean
photo Object containing a set of image urls associated with the topic object
user_id Id of the user who created the topic string with valid user id (not validated)
private boolean
application Application(s) to which the topic belongs. Defaults to ["rw"]. Read more about this field here. array of strings
env Environment to which the topic belongs. Read more about this field in the Environments concept section. string
curl -X POST https://api.resourcewatch.org/v1/topics \
-H "Authorization: Bearer <your-token>" \
-H "x-api-key: <your-api-key>" \
-H "Content-Type: application/json"  -d \
 '{
      "data": {
          "type": "topics",
          "attributes": {
              "name": "Cities",
              "summary": "Traditional models of city development can lock us into congestion, sprawl, and inefficient resource use. However, compact, ...",
              "description": "",
              "content": "[{...}]",
              "published": false,
              "env": "production",
              "photo": {
                  "cover": "...",
                  "thumb": "...",
                  "original": "..."
              },
              "user-id": "eb63867922e16e34ef3ce862",
              "private": true,
              "application":  ["rw"]
          }
      }
  }'
{
    "data": {
        "id": "243",
        "type": "topics",
        "attributes": {
            "name": "Cities",
            "slug": "cities-94bbc472-8970-4d9e-a3f2-d5422b1011e0",
            "summary": "Traditional models of city development can lock us into congestion, sprawl, and inefficient resource use. However, compact, ...",
            "description": "",
            "content": "[{...}]",
            "published": false,
            "env": "production",
            "photo": {
                "cover": "...",
                "thumb": "...",
                "original": "..."
            },
            "user-id": "eb63867922e16e34ef3ce862",
            "private": true,
            "user": null,
            "application":  ["rw"]
        }
    }
}

Editing a topic

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

When updating the application field of a topic, a user cannot add values not associated with their user account.

curl -X PATCH https://api.resourcewatch.org/v1/topics/<id of the topic> \
-H "Authorization: Bearer <your-token>" \
-H "x-api-key: <your-api-key>" \
-H "Content-Type: application/json"  -d \
 '{
      "data": {
          "attributes": {
              "description": "Topic related with cities."
          }
      }
  }'
{
    "data": {
        "id": "243",
        "type": "topics",
        "attributes": {
            "name": "Cities",
            "slug": "cities-94bbc472-8970-4d9e-a3f2-d5422b1011e0",
            "summary": "Traditional models of city development can lock us into congestion, sprawl, and inefficient resource use. However, compact, ...",
            "description": "Topic related with cities.",
            "content": "[{...}]",
            "published": false,
            "env": "production",
            "photo": {
                "cover": "...",
                "thumb": "...",
                "original": "..."
            },
            "user-id": "eb63867922e16e34ef3ce862",
            "private": true,
            "user": null,
            "application":  ["rw"]
        }
    }
}

Clone a topic

Clones an existing topic using its ID. If the original topic contains functioning widgets, they will be duplicated and the new ids will be used by the new topic.

curl -X POST https://api.resourcewatch.org/v1/topics/10/clone -H 'Authorization: Bearer exampleToken' \
-H "x-api-key: <your-api-key>"
{
    "data": {
        "id": "224",
        "type": "topics",
        "attributes": {
            "name": "Cities",
            "slug": "cities-a9cb2c87-f6b6-48cf-9b52-9e0de4fd8d6f",
            "summary": "Traditional models of city development can lock us into congestion, sprawl, and inefficient resource use. However, compact, ...",
            "description": "",
            "content": "[{\"id\":1511952250652,\"type\":\"widget\",\"content\":{\"widgetId\":\"b9186ce9-78ae-418b-a6d3-d521283ce485\",\"categories\":[]}},...}]",
            "published": false,
            "env": "production",
            "photo": {
                "cover": "/system/topics/photos/data?1523301918",
                "thumb": "/system/topics/photos/data?1523301918",
                "original": "/system/topics/photos/data?1523301918"
            },
            "user-id": "eb63867922e16e34ef3ce862",
            "private": true,
            "application":  ["rw"]
        }
    }
}

Dashboard

Note: the documentation for these endpoints is not maintained and might not be up to date.

What is a dashboard

A dashboard contains the information to display a web page belonging to a user.

Getting all dashboards

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

Example response:

{
    "data": [
        {
            "id": "10",
            "type": "dashboards",
            "attributes": {
                "name": "Cities Dashboard",
                "slug": "cities-dashboard",
                "summary": "",
                "description": "",
                "content": "<p></p>\n<iframe width=\"500\" height=\"410\" src=\"/embed/widget/5ebeddda-8f3d-4e63-8a52-08e15c3e148c\" frameBorder=\"0\"></iframe>\n<p></p>\n<iframe width=\"500\" height=\"410\" src=\"/embed/widget/73c574b9-f9ab-4f77-87be-651ff8dac5fe\" frameBorder=\"0\"></iframe>\n<p>test1</p>\n",
                "published": true,
                "photo": {
                    "cover": "https://s3.amazonaws.com/image.jpg",
                    "thumb": "https://s3.amazonaws.com/image.jpg",
                    "original": "https://s3.amazonaws.com/image.jpg"
                },
                "user-id": "eb63867922e16e34ef3ce862",
                "private": true,
                "env": "production",
                "application":  ["rw"],
                "is-highlighted": false,
                "is-featured": false,
                "author-title": "",
                "author-image": {
                    "cover": "/author_images/cover/missing.png",
                    "thumb": "/author_images/thumb/missing.png",
                    "original": "/author_images/original/missing.png"
                }
            }
        }
    ],
    "links": {
        "self": "https://api.resourcewatch.org/v1/dashboard?page%5Bnumber%5D=1&page%5Bsize%5D=10",
        "first": "https://api.resourcewatch.org/v1/dashboard?page%5Bnumber%5D=1&page%5Bsize%5D=10",
        "prev": null,
        "next": "https://api.resourcewatch.org/v1/dashboard?page%5Bnumber%5D=2&page%5Bsize%5D=10",
        "last": "https://api.resourcewatch.org/v1/dashboard?page%5Bnumber%5D=14&page%5Bsize%5D=10"
    },
    "meta": {
        "total-pages": 14,
        "total-items": 140,
        "size": 10
    }
}

This endpoint will allow to get all dashboards belonging to a user.

Filters

Example request using query string filters:

curl -X GET https://api.resourcewatch.org/v1/dashboard?name=text&private=false \
-H "x-api-key: <your-api-key>"

Deprecated filter syntax:

curl -X GET https://api.resourcewatch.org/v1/dashboard?filter[name]=text&filter[private]=false \
-H "x-api-key: <your-api-key>"

Available filters parameters:

Field Description Type
name Filter dashboards by name (partial matches and case-insensitive supported). Text
published Filter dashboards by publishing status (true, false). Boolean
private Filter dashboards by private status (true, false). Boolean
user Filter dashboards by author user id. Text
user.role The role of the user who created the dashboard. If the requesting user does not have the ADMIN role, this filter is ignored. ADMIN, MANAGER or USER
application The application to which the dashboard belongs. Read more about this field here. Text (single value)
env Environment to which the dashboard belongs. Multiple values can be combined using , as a separator. Does not support regexes. Read more about this field in the Environments concept section. Text
is-highlighted Filter dashboards by highlighted ones (true,false). Boolean
is-featured Filter dashboards by featured ones (true,false). Boolean
author-title Filter dashboards by the title of the author of the dashboard. Text

Warning: Please keep in mind that, due to the limitations of the underlying endpoint used to find user ids by role, the performance of the request while using user.role filter might be degraded.

Deprecation notice: The format filter[filterName]=value which was previously supported for some filters, is now deprecated, in favor of filterName=value.

Pagination

Example request to load page 2 using 25 results per page

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

The Dashboards 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 dashboards list.

Sorting

Sorting dashboards

curl -X GET https://api.resourcewatch.org/v1/dashboard?sort=name \
-H "x-api-key: <your-api-key>"

Sorting dashboards by multiple criteria

curl -X GET https://api.resourcewatch.org/v1/dashboard?sort=name,slug \
-H "x-api-key: <your-api-key>"

Explicit order of sorting

curl -X GET https://api.resourcewatch.org/v1/dashboard?sort=-name,+slug \
-H "x-api-key: <your-api-key>"

Sorting dashboards by the role of the user who owns the dashboard

curl -X GET https://api.resourcewatch.org/v1/dashboard?sort=user.role \
-H "x-api-key: <your-api-key>"

The Dashboards service currently supports sorting using the sort query parameter. Sorting dashboards adheres to the conventions defined in the Sorting guidelines for the RW API, so we strongly recommend reading that section before proceeding. In addition to all dashboard 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 dashboard. Keep in mind that sorting by user data is restricted to ADMIN users.

Please also keep in mind that, due to the limitations of the underlying endpoint used to find user ids by name or role, the performance of the request while using this sort might be degraded.

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

User

Example request including the information for the user who owns the dashboard:

curl -X GET https://api.resourcewatch.org/v1/dashboard?includes=user \
-H "x-api-key: <your-api-key>"

Example response:

{
    "data": [
      {
        "id": "86",
        "type": "dashboards",
        "attributes": {
          "name": "Test dashboard three",
          "slug": "test-dashboard-three-cd4305e9-e3c8-456b-85a0-32eccb6100e6",
          "summary": "test dashboard three summary",
          "description": "test dashboard three description",
          "content": "test dashboard three description",
          "published": true,
          "photo": {
            "cover": "https://s3.amazonaws.com/image.jpg",
            "thumb": "https://s3.amazonaws.com/image.jpg",
            "original": "https://s3.amazonaws.com/image.jpg"
          },
          "user-id": "57ac9f9e29309063404573a2",
          "private": true,
          "env": "production",
          "application":  ["rw"],
          "is-highlighted": false,
          "is-featured": false,
          "author-title": "",
          "author-image": {
            "cover": "/author_images/cover/missing.png",
            "thumb": "/author_images/thumb/missing.png",
            "original": "/author_images/original/missing.png"
          },
          "user": {
            "name": "John Doe",
            "role": "ADMIN",
            "email": "john.doe@vizzuality.com"
          }
        }
      }
   ]
}

Loads the name and email address of the owner of the dashboard. If you request this issue as an authenticated user with ADMIN role, you will additionally get the owner'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.

Please keep in mind that, due to the limitations of the underlying endpoint used to find users by ids, the performance of the request while including user information might be degraded.

Getting a dashboard by its ID

How to get a dashboard by its ID:

curl -X GET https://api.resourcewatch.org/dashboard/24 \
-H "x-api-key: <your-api-key>"

Response:

{
  "data": {
    "id": "24",
    "type": "dashboards",
    "attributes": {
      "name": "Cities",
      "slug": "cities",
      "summary": "Traditional models of city development can lock us into congestion, sprawl, and inefficient resource use. However, compact, connected, and efficient growth can help ensure more competitive cities, and provide a better quality of life for citizens.  The decisions that national leaders, local officials, developers, and planners make today will determine how billions of urban cities will live over the next century. Already, half the global population resides in cities. That figure is set to increase to 70 percent by 2050.",
      "description": "",
      "content": "[]",
      "published": false,
      "photo": {
        "cover": "https://s3.amazonaws.com/wri-api-backups/resourcewatch/staging/dashboards/photos/000/000/024/cover/data?1523301918",
        "thumb": "https://s3.amazonaws.com/wri-api-backups/resourcewatch/staging/dashboards/photos/000/000/024/thumb/data?1523301918",
        "original": "https://s3.amazonaws.com/wri-api-backups/resourcewatch/staging/dashboards/photos/000/000/024/original/data?1523301918"
      },
      "user-id": "58f63c81bd32c60206ed6b12",
      "private": true,
      "env": "production",
      "user": null,
      "is-highlighted": false,
      "is-featured": false,
      "author-title": "",
      "author-image": {
        "cover": "/author_images/cover/missing.png",
        "thumb": "/author_images/thumb/missing.png",
        "original": "/author_images/original/missing.png"
      }
    }
  }
}

Creating a dashboard

Example request for creating a dashboard:

curl -X POST https://api.resourcewatch.org/v1/dashboard \
-H "Authorization: Bearer <your-token>" \
-H "x-api-key: <your-api-key>" \
-H "Content-Type: application/json"  -d \
 '{
      "data": {
          "type": "dashboards",
          "attributes": {
              "name": "Cities",
              "summary": "Traditional models of city development can lock us into ...",
              "description": "",
              "content": "[{...}]",
              "published": false,
              "photo": {
                  "cover": "...",
                  "thumb": "...",
                  "original": "..."
              },
              "private": true,
              "env": "production",
              "application":  ["rw"],
              "is-highlighted": false,
              "is-featured": false,
              "author-title": "",
              "author-image": @file
          }
      }
  }'

Example response:

{
    "data": {
        "id": "243",
        "type": "dashboards",
        "attributes": {
            "name": "Cities",
            "slug": "cities-94bbc472-8970-4d9e-a3f2-d5422b1011e0",
            "summary": "Traditional models of city development can lock us into ...",
            "description": "",
            "content": "[{...}]",
            "published": false,
            "photo": {
                "cover": "...",
                "thumb": "...",
                "original": "..."
            },
            "user-id": "eb63867922e16e34ef3ce862",
            "private": true,
            "env": "production",
            "user": null,
            "application":  ["rw"],
            "is-highlighted": false,
            "is-featured": false,
            "author-title": "",
            "author-image": {
                "cover": "...",
                "thumb": "...",
                "original": "..."
            }
        }
    }
}

When creating a dashboard, the application field should be present and cannot contain any values that are not associated with the creating user's account. If an application value is not provided, ["rw"] is used by default, and the process will fail if the user account does not belong to it. Additionally, keep in mind that this endpoint implements role-based access control in accordance with the RW API role-based access control guidelines.

Supported fields:

Name Description Accepted values
name Short name for the dashboard any valid text
summary Summary of the content of the dashboard any valid text
description Description of the dashboard any valid text
content Content of the dashboard, typically encoded as a JSON string any valid text
published If the dashboard is in a publishable state boolean
photo Object containing a set of image urls associated with the dashboard object
private If the dashboard is private or publicly available. boolean
production If the dashboard is available in the production environment. boolean
preproduction If the dashboard is available in the preproduction environment. boolean
staging If the dashboard is available in the staging environment. boolean
application Application(s) to which the dashboard belongs. Defaults to ["rw"]. Read more about this field here. array of strings
env Environment to which the dashboard belongs. Read more about this field in the Environments concept section. string
is-highlighted If this dashboard is highlighted (true/false). Defaults to false. Only accessible to users with ADMIN role. boolean
is-featured If this dashboard is featured (true/false). Defaults to false. Can only be set by user with ADMIN role. boolean
author-title The title of the author of the dashboard. any valid text
author-image File for the image of the author of the dashboard. valid image file (jpg, jpeg, png)

Editing a dashboard

Example request for updating a dashboard:

curl -X PATCH https://api.resourcewatch.org/v1/dashboard/<id of the dashboard> \
-H "Authorization: Bearer <your-token>" \
-H "x-api-key: <your-api-key>" \
-H "Content-Type: application/json"  -d \
 '{
      "data": {
          "attributes": {
              "description": "Dashboard that uses cities"
          }
      }
  }'

Example response:

{
    "data": {
        "id": "243",
        "type": "dashboards",
        "attributes": {
            "name": "Cities",
            "slug": "cities-94bbc472-8970-4d9e-a3f2-d5422b1011e0",
            "summary": "Traditional models of city development can lock us ...",
            "description": "Dashboard that uses cities",
            "content": "[{...}]",
            "published": false,
            "photo": {
                "cover": "...",
                "thumb": "...",
                "original": "..."
            },
            "user-id": "eb63867922e16e34ef3ce862",
            "private": true,
            "env": "production",
            "user": null,
            "application": ["rw"],
            "is-highlighted": false,
            "is-featured": false,
            "author-title": "",
            "author-image": {
                "cover": "...",
                "thumb": "...",
                "original": "..."
            }
        }
    }
}

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

When updating the application field of a dashboard, a user cannot add values not associated with their user account.

Delete dashboard

Example request for deleting a dashboard:

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

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

Clone dashboard

Example request for cloning a dashboard:

curl -X POST https://api.resourcewatch.org/v1/dashboard/<id>/clone \
-H "Authorization: Bearer <your-token>" \
-H "x-api-key: <your-api-key>" \
-H "Content-Type: application/json"  -d \
 '{
    "data": {
        "attributes": {
            "name": "Copy of Cities dashboard",
        }
    }
  }'

Example response:

{
    "data": {
        "id": "224",
        "type": "dashboards",
        "attributes": {
            "name": "Copy of Cities dashboard",
            "slug": "cities-a9cb2c87-f6b6-48cf-9b52-9e0de4fd8d6f",
            "summary": "Traditional models of city development can lock us into congestion, sprawl, and inefficient resource use. However, compact, ...",
            "description": "",
            "content": "[{\"id\":1511952250652,\"type\":\"widget\",\"content\":{\"widgetId\":\"b9186ce9-78ae-418b-a6d3-d521283ce485\",\"categories\":[]}},...}]",
            "published": false,
            "photo": {
                "cover": "/system/dashboards/photos/data?1523301918",
                "thumb": "/system/dashboards/photos/data?1523301918",
                "original": "/system/dashboards/photos/data?1523301918"
            },
            "user-id": "1111167922e16e34ef3ce872",
            "private": true,
            "env": "production",
            "application":  ["rw"],
            "is-highlighted": false,
            "is-featured": false,
            "author-title": "",
            "author-image": {
                "cover": "/author_images/cover/missing.png",
                "thumb": "/author_images/thumb/missing.png",
                "original": "/author_images/original/missing.png"
            }
        }
    }
}

Clones an existing dashboard using its ID. If the original dashboard contains widgets, they will be duplicated and the new ids will be used by the new dashboard. Data can be provided in the body of the request in order to overwrite the data of the original dashboard. In the example on the side, the name of the dashboard will be overwritten.

The following attributes can be overwritten by providing new values in the request body:

Static pages

Note: the documentation for these endpoints is not maintained and might not be up to date.

Tasks

What is a task?

In the context of this API, a task is a process in charge of performing certain actions on datasets of the document type. These actions can be creating a dataset or overwriting its content.

A task may contains the following fields:

Field Description Type
id Id of the task Text
type Task type - see full list here Text
message Task message, which parametrizes the task Object
status Status of the task - see full list here Text
reads Number of data reads performed by the task Number
writes Number of data writes performed by the task Number
index Name of the Elasticsearch index used in this task Text
datasetId Id of the dataset to which this task relates Text
logs List of the individual operations carried out by this task Array
error Error message generated should the task fail Text
createdAt Date and time in which the task was created DateTime
updatedAt Date and time in which the task was last updated DateTime

A task is fundamentally an internal element to the API, and it's visibility and interaction is limited to maintenance and debug actions. At its core, a task represents a single package that contains:

Get all tasks

To obtain all tasks:

curl -X GET https://api.resourcewatch.org/v1/doc-importer/task \
-H "x-api-key: <your-api-key>"

Example response:

{
    "data": [
        {
            "id": "55b02cfd-dabf-4ad0-a04d-5501cf248a0c",
            "type": "task",
            "attributes": {
                "type": "TASK_CREATE",
                "message": {
                    "id": "55b02cfd-dabf-4ad0-a04d-5501cf248a0c",
                    "type": "TASK_CREATE",
                    "datasetId": "65593fee-26e0-4c3c-84b3-cc0921bf8bc1",
                    "fileUrl": "http://gfw2-data.s3.amazonaws.com/country-pages/fire_alerts_all.csv",
                    "provider": "csv",
                    "legend": {
                        "date": [],
                        "region": [],
                        "country": [],
                        "nested": []
                    },
                    "verified": false,
                    "dataPath": "rows"
                },
                "status": "SAVED",
                "reads": 973,
                "writes": 973,
                "createdAt": "2019-02-20T07:39:31.295Z",
                "updatedAt": "2019-02-20T10:10:07.147Z",
                "index": "index_65593fee26e04c3c84b3cc0921bf8bc1_1550648371365",
                "datasetId": "65593fee-26e0-4c3c-84b3-cc0921bf8bc1",
                "logs": [
                    {
                        "id": "a67f2557-9237-4435-82fd-3a0ad64b0292",
                        "type": "STATUS_INDEX_CREATED",
                        "taskId": "55b02cfd-dabf-4ad0-a04d-5501cf248a0c",
                        "index": "index_65593fee26e04c3c84b3cc0921bf8bc1_1550648371365"
                    },
                    {
                        "id": "53ac8e83-167b-4c77-9b61-6642b1764b32",
                        "type": "STATUS_READ_DATA",
                        "taskId": "55b02cfd-dabf-4ad0-a04d-5501cf248a0c"
                    }
                ]
            }
        },
        {

            "id": "415ecb4e-ed9a-4b0f-9f8b-7755775b08f5",
            "type": "task",
            "attributes": {
                "type": "TASK_CREATE",
                "message": {
                    "id": "415ecb4e-ed9a-4b0f-9f8b-7755775b08f5",
                    "type": "TASK_CREATE",
                    "datasetId": "638cce8c-3e97-4bdd-b4de-41cd28254370",
                    "fileUrl": "http://gfw2-data.s3.amazonaws.com/country-pages/fire_alerts_all.csv",
                    "provider": "csv",
                    "legend": {
                        "date": [],
                        "region": [],
                        "country": [],
                        "nested": []
                    },
                    "verified": false,
                    "dataPath": "rows"
                },
                "status": "SAVED",
                "reads": 973,
                "writes": 973,
                "createdAt": "2019-02-20T07:39:36.421Z",
                "updatedAt": "2019-02-20T10:10:09.175Z",
                "index": "index_638cce8c3e974bddb4de41cd28254370_1550652900017",
                "datasetId": "638cce8c-3e97-4bdd-b4de-41cd28254370",
                "logs": [
                    {
                        "id": "8f5b6b0c-9132-4b5c-b7c4-b58582b3cb0b",
                        "type": "STATUS_INDEX_CREATED",
                        "taskId": "415ecb4e-ed9a-4b0f-9f8b-7755775b08f5",
                        "index": "index_638cce8c3e974bddb4de41cd28254370_1550652900017"
                    },
                    {
                        "id": "63c69b2b-31cd-4bdb-9794-f6d4ec155e7b",
                        "type": "STATUS_READ_DATA",
                        "taskId": "415ecb4e-ed9a-4b0f-9f8b-7755775b08f5"
                    }
                ]
            }
        }
    ],
    "links": {
        "self": "https://api.resourcewatch.org/v1/doc-importer/task?page[number]=1&page[size]=10",
        "first": "https://api.resourcewatch.org/v1/doc-importer/task?page[number]=1&page[size]=10",
        "last": "https://api.resourcewatch.org/v1/doc-importer/task?page[number]=23&page[size]=10",
        "prev": "https://api.resourcewatch.org/v1/doc-importer/task?page[number]=1&page[size]=10",
        "next": "https://api.resourcewatch.org/v1/doc-importer/task?page[number]=2&page[size]=10"
    },
    "meta": {
        "total-pages": 23,
        "total-items": 227,
        "size": 10
    }
}

Pagination

Example request to load page 2 using 25 results per page

curl -X GET https://api.resourcewatch.org/v1/doc-importer/task?page[number]=2&page[size]=25 \
-H "x-api-key: <your-api-key>"

The Tasks 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 tasks list.

Filter params

Available filters:

Field Description Type
type Task type Text
status Task status Text
datasetID Id of the dataset to which the task refers Text
createdAt Tasks created on the given date Date
updatedAt Tasks last updated on the given date Date
createdBefore Tasks created before the given date Date
createdAfter Tasks created after the given date Date
updatedBefore Tasks last updated before the given date Date
updatedAfter Tasks last updated after the given date Date

Return tasks with type TASK_OVERWRITE

curl -X GET https://api.resourcewatch.org/v1/doc-importer/task?type=TASK_OVERWRITE \
-H "x-api-key: <your-api-key>"

Return the tasks with status SAVED

curl -X GET https://api.resourcewatch.org/v1/doc-importer/task?status=SAVED \
-H "x-api-key: <your-api-key>"

Return the tasks created on Feb 1st 2019

curl -X GET https://api.resourcewatch.org/v1/doc-importer/task?createdAt=2019-02-01 \
-H "x-api-key: <your-api-key>"

Return the tasks last updated between Jan 2nd and Feb 2nd 2019

curl -X GET https://api.resourcewatch.org/v1/doc-importer/task?updatedAfter=2019-01-02&updatedBefore=2019-02-02 \
-H "x-api-key: <your-api-key>"

Return the tasks last updated before and Feb 2nd 2019 and with status ERROR

curl -X GET https://api.resourcewatch.org/v1/doc-importer/task?updatedBefore=2019-02-02&status=ERROR \
-H "x-api-key: <your-api-key>"

Get a single task

To obtain the task:

curl -X GET https://api.resourcewatch.org/v1/doc-importer/task/55b02cfd-dabf-4ad0-a04d-5501cf248a0c \
-H "x-api-key: <your-api-key>"

Example response:

{
    "data": {
        "id": "55b02cfd-dabf-4ad0-a04d-5501cf248a0c",
        "type": "task",
        "attributes": {
            "type": "TASK_CREATE",
            "message": {
                "id": "55b02cfd-dabf-4ad0-a04d-5501cf248a0c",
                "type": "TASK_CREATE",
                "datasetId": "65593fee-26e0-4c3c-84b3-cc0921bf8bc1",
                "fileUrl": "http://gfw2-data.s3.amazonaws.com/country-pages/fire_alerts_all.csv",
                "provider": "csv",
                "legend": {
                    "date": [],
                    "region": [],
                    "country": [],
                    "nested": []
                },
                "verified": false,
                "dataPath": "rows"
            },
            "status": "SAVED",
            "reads": 973,
            "writes": 973,
            "createdAt": "2019-02-20T07:39:31.295Z",
            "updatedAt": "2019-02-20T10:10:07.147Z",
            "index": "index_65593fee26e04c3c84b3cc0921bf8bc1_1550648371365",
            "datasetId": "65593fee-26e0-4c3c-84b3-cc0921bf8bc1",
            "logs": [
                {
                    "id": "a67f2557-9237-4435-82fd-3a0ad64b0292",
                    "type": "STATUS_INDEX_CREATED",
                    "taskId": "55b02cfd-dabf-4ad0-a04d-5501cf248a0c",
                    "index": "index_65593fee26e04c3c84b3cc0921bf8bc1_1550648371365"
                },
                {
                    "id": "53ac8e83-167b-4c77-9b61-6642b1764b32",
                    "type": "STATUS_READ_DATA",
                    "taskId": "55b02cfd-dabf-4ad0-a04d-5501cf248a0c"
                }
            ]
        }
    }
}

Delete a task

You can delete a task if, for example, it is stuck on a running state, but it's not actually running. This should be considered a "only do it if you know what you are doing" operation, and requires ADMIN permission.

curl -X DELETE https://api.resourcewatch.org/v1/doc-importer/task/<task_id> \
-H "Authorization: Bearer <your-token>" \
-H "x-api-key: <your-api-key>" \
-H "Content-Type: application/json"

Salesforce integration

This service allows easy communication of RW API user data to Salesforce for convenient CRM purposes.

Searching for user details

Searches for users by email address

curl -X GET https://api.resourcewatch.org/v1/salesforce/contact/search?email=user@email.com \
-H "x-api-key: <your-api-key>"

Response:

{
  "data": [
    {
      "Id": "0123456789abcdef",
      "FirstName": "Test",
      "LastName": "User",
      "Email": "user@email.com",
      "Personal_Email__c": "user@email.com",
      "Work_Email__c": "user@email.com",
      "Alternate_Email__c": null
    }
  ]
}

Returns the details associated with users matching the provided search criteria. If more than one user matches the search criteria, only the first one (as sorted by Salesforce) is returned - this is likely to change in the future.

Filters

Parameter Description Type
email Email address of the user Text

Currently, only filtering by email is supported. It is also required.

Errors for searching for user details

Error code Error message Description
400 "email" is required The required email query parameter is missing in the request.

Logging user data update

curl -X POST https://api.resourcewatch.org/v1/salesforce/contact/log-action \
-H "Authorization: Bearer <your-token>" \
-H "x-api-key: <your-api-key>" \
-H "Content-Type: application/json"  -d \
 '{
   "email": "user@email.com",
   "firstName": "John",
   "lastName": "Doe"
 }'

Logs a change to a user's details. The user to update is identified by its email address, which is a required body parameter. If more than one user account matches the provided email address, the first one (as sorted by Salesforce) is used.

Changes logged using this endpoint are not applied synchronously, so they may not be reflected immediately on data loaded through other endpoints.

A successful user data update logging returns an empty HTTP 201 response.

Logging user data update parameters

Parameter Type Required
email Text Yes
countryOfInterest Text No
firstName Text No
lastName Text No
primaryRole Text No
primaryRoleOther Text No
sector Text No
areaOrRegionOfInterest Text No
title Text No
organizationName Text No
topicsOfInterest Text No
userCity Text No
userState Text No
userCountry Text No
howDoYouUseGFW Text No
howDoYouUseGFWOther Text No
signUpForTesting Text No
sourceOfContactCreation Text No

Errors for logging user data update

Error code Error message Description
400 "email" is required The required email body parameter is missing in the request.
400 "<field name>" is an invalid field The provided field name is not supported as a body parameter.

User management

The following endpoints expose the RW API's functionality regarding user management. These endpoints will allow you to login, recover a forgotten password, create, edit or delete a user account. We've already covered the basics of getting a user account in the quickstart guide section, and here we'll dive deeper into all the functionality exposed by these endpoints.

These endpoints have a key difference from most of the endpoint covered so far. The great majority of the RW API endpoints are meant to be used by your applications, and as such produce JSON responses, which are easily interpreted by computers. However, some of the functionality we'll cover in this section is meant to be used only or also by humans, making JSON a less than ideal response format.

Some (but not all) of the endpoints documented here will produce a response in either JSON or HTML format, depending on the value you provide on the Content-type HTTP request header. Use Content-Type: application/json if you are calling the endpoint from an application, and would like to get a JSON formatted response. If you are accessing these endpoints from a browser, it will typically generate a request with the Content-Type: text/html header, in which case the reply will be in HTML format.

Keep in mind that not all endpoints support both formats, and will output either HTML or JSON, no matter which Content-Type value you provide.

General notes on RW API users

User accounts in the RW API work pretty much like you would expect: you create a user account, login with it, and use it on your day-to-day interactions to access certain actions and associate certain RW API resources with it.

Besides authentication, user accounts are also used for authorization. Authorization is implemented on a per-service basis, but is commonly built on top of 3 elements associated with your a user account:

id is a unique identifier of your account. Certain actions may be limited to specific users, typically in the context of a given resource being associated directly with a specific user id.

role can be one of 3 values: USER, MANAGER and ADMIN and it is usually used for role-based access control - read more about this field in the User roles concept documentation.

application is a list of keys meant to identify the different client applications that are built using the RW API. It's present not only on user accounts, but also on many of the resources found on the RW API, either as a single value or as a list of values. Typically, in order to manipulate a given resource, that resource and the user account must have at least one overlapping application value. You can find out more about how the application field works here.

Keep in mind that it's up to each individual RW API service (dataset, widget, layer, etc) to define how they restrict or allow actions based on these or other factors, so the examples above may not be true for all cases. Refer to the documentation of each resource and endpoint for more details on restrictions they may have regarding user accounts and their properties.

Deprecation notice: Throughout these endpoints, you'll notice that many API responses contain both id and _id ( with and without an underscore prefix). Whenever both are present, they will always have the same value, and you should rely on id (no prefix) - _id is present for BC reasons, but should be considered deprecated, and will be removed in the near future.

User management and applications

As we've covered in previous sections, several RW API resources, like users, datasets or widgets, are associated with one or more applications. Applications are a way to identify the different tools that rely on the RW API, and are used to make resource management easier.

The user management service can also models its behavior based on the application that's making use of it - this can be controlled by the origin query parameter. This parameter can be passed on every request, or on the first request only, if you are relying on cookie-based sessions. In it, you can identify the application using the RW API. If it's a known application, certain elements will be adjusted:

If you use an origin application that's not known to the RW API, you will see a fallback configuration of these elements, and 3rd party login will be disabled. If you'd like your application to be supported, please contact us - we'd love to hear about how the RW API can help your projects.

Login (email + password)

Login endpoints support both HTML and JSON output formats, depending on the Content-type provided in the request. Keep in mind that HTML-based requests will result in redirects - for example, after successfully logging in, you will be taken to /auth/success - while JSON based requests will simply return the matching HTTP code - 200 in case of a successful login.

GET <BASE API URL>/auth/

Convenience URL that redirects to <BASE API URL>/auth/login - the HTML login page.

GET <BASE API URL>/auth/login

HTML page that displays the login, registration and password reset links. This is the most common entry point when using the HTML UI provided by the RW API for user management.

POST <BASE API URL>/auth/login

Email + password based login - JSON format

curl -X POST "https://api.resourcewatch.org/auth/login" \
-H "Content-Type: application/json"  -d \
 '{
    "email":"your-email@provider.com",
    "password":"potato"
}'

Response:

{
  "data": {
    "id": "5bfd237767b3176dd63f2eb7",
    "_id": "5bfd237767b3176dd63f2eb7",
    "email": "your-email@provider.com",
    "createdAt": "2018-11-15T04:46:35.313Z",
    "updatedAt": "2018-11-15T04:46:35.313Z",
    "role": "USER",
    "provider": "local",
    "organizations": [],
    "applications": [],
    "extraUserData": {
      "apps": [
        "rw"
      ]
    },
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjViZWNmYTJiNjdkYTBkM2VjMDdhMjdmNiIsInJvbGUiOiJVU0VSIiwicHJvdmlkZXIiOiJsb2NhbCIsImVtYWlsIjoidGVzdEBleGFtcGxlLmNvbSIsImV4dHJhVXNlckRhdGEiOnsiYXBwcyI6WyJydyJdfSwiY3JlYXRlZEF0IjoxNTQzMzE1NzMxNzcwLCJpYXQiOjE1NDMzMTU3MzF9.kIdkSOb7mCMOxE2ipqVOBrK7IefAjLDhaPG9DT1qvCw"
  }
}

Endpoint for email + password based login.

For HTML requests, it will redirect to either <BASE API URL>/auth/success or <BASE API URL>/auth/fail depending on whether the login was successful or not. If successful, the HTTP reply will have a session cookie that may be used in subsequent requests. An optional callbackUrl query parameter can be provided, in which case the user will be redirected to that URL in case of login success.

For JSON requests, in case of successful logins, the user details will be returned as a JSON object.

Errors for logging in

Error code Error message Description
401 Invalid email or password. Login credentials are missing or incorrect.

GET <BASE API URL>/auth/fail

Displays login errors for HTML requests. Not supported on JSON requests.

GET <BASE API URL>/auth/check-logged

Check if the user is logged

curl -X GET "https://api.resourcewatch.org/auth/check-logged" \
    -H 'Cookie: <your cookie values>'

Response

{
  "id": "5bfd237767b3176dd63f2eb7",
  "_id": "5bfd237767b3176dd63f2eb7",
  "email": "your-email@provider.com",
  "createdAt": "2018-11-27T10:59:03.531Z",
  "updatedAt": "2018-11-27T10:59:03.531Z",
  "role": "USER",
  "provider": "local",
  "extraUserData": {
    "apps": [
      "rw"
    ]
  }
}

Checks if you are logged in. This is typically used to determine if a session has been established between the the user's browser and the RW API.

Errors for checking if the user is logged

Error code Error message Description
401 Not authenticated. You are not logged in.

GET <BASE API URL>/auth/success

Successful login page for HTML requests. Not supported on JSON requests.

GET <BASE API URL>/auth/logout

Login invalidation endpoint. Only invalidates the session cookie set on login. If using JSON Web Token based authentication, this endpoint will NOT invalidate the token.

GET <BASE API URL>/auth/generate-token

Generate the user's JSON Web Token

curl -X GET "https://api.resourcewatch.org/auth/generate-token" \
    -H 'Cookie: <your cookie values>'

Response:

{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjViZWNmYTJiNjdkYTBkM2VjMDdhMjdmNiIsInJvbGUiOiJVU0VSIiwicHJvdmlkZXIiOiJsb2NhbCIsImVtYWlsIjoidGVzdEBleGFtcGxlLmNvbSIsImV4dHJhVXNlckRhdGEiOnsiYXBwcyI6WyJydyJdfSwiY3JlYXRlZEF0IjoxNTQzMzE1NzMxNzcwLCJpYXQiOjE1NDMzMTU3MzF9.kIdkSOb7mCMOxE2ipqVOBrK7IefAjLDhaPG9DT1qvCw"
}

Generates a JSON Web Token for the current user session. This is useful when using the HTML UI through a browser, where a session is established using a cookie returned on login. This cookie authenticates the user, and allows retrieving the token.

Errors for generating a new token

Error code Error message Description
401 Not authenticated. You are not logged in.

Login (3rd party oauth)

Besides its own email + password login mechanism, that you can interact with and build your own UI on top of, the RW API also provides authentication using 3rd party accounts, like Facebook, Apple or Google. These 4 authentication mechanisms use OAuth access delegation, meaning users can use their accounts on these platforms to access the RW API. For each mechanism, users will be informed, when logging in, which data the RW API requires to provide this access.

For each provider, there's a corresponding endpoint that starts the authentication flow. These endpoints simply redirect the user to the respective provider page, along with some data that allows the provider to contact the RW API when the login process is finished. You can forward users to these endpoints if, for example, you want to have your own login links on your UI.

Keep in mind that, depending on the origin application you specify, different Facebook, Google or Apple applications will be used. Also, not all origin applications support all 3 providers.

3rd party authentication using Google

Note: For the access token based login with Google, you should make sure to request the https://www.googleapis.com/auth/userinfo.email scope. This scope will make sure that the RW API can find the user email address in the payload returned by Google validating the access token. If the email is present in the payload returned by Google, it will be used to login the RW API account. If not, the RW API will use "fake email", composed using Google's unique user identifier, as the email address for the RW API account to log in.

3rd party authentication using Facebook

Note: For the access token based login with Facebook, you should make sure to request the email scope. This scope will make sure that the RW API can find the user email address in the payload returned by Facebook validating the access token. If the email is present in the payload returned by Facebook, it will be used to login the RW API account. If not, the RW API will use "fake email", composed using Facebook's unique user identifier, as the email address for the RW API account to log in.

3rd party authentication using Apple

Common authorization callback

All forms of 3rd party login return to the same endpoint:

Registration

Registration endpoints support both HTML and JSON output formats, depending on the Content-type provided in the request.

View the registration page

curl -X GET "https://api.resourcewatch.org/auth/sign-up"

Account creation page, for accounts using email-based login for HTML requests. Not supported on JSON requests.

Register a new user account

Account creation using email

curl -X POST "https://api.resourcewatch.org/auth/sign-up" \
-H "Content-Type: application/json"  -d \
 '{
    "name: "Your name"
    "email":"your-email@provider.com",
    "apps": ["rw"]
}'

Response

{
  "data": {
    "id": "5bfd237767b3176dd63f2eb7",
    "name": "Your name",
    "email": "your-email@provider.com",
    "createdAt": "2018-11-27T10:59:03.531Z",
    "organizations": [],
    "applications": [],
    "role": "USER",
    "extraUserData": {
      "apps": [
        "rw"
      ]
    }
  }
}

Account creation using email with a user defined origin app

curl -X POST "https://api.resourcewatch.org/auth/sign-up?origin=rw" \
-H "Content-Type: application/json"  -d \
 '{
    "name: "Your name"
    "email":"your-email@provider.com",
    "apps": ["rw"]
}'

Account creation endpoint, for accounts using email-based login for both HTML and JSON requests. The email must be unique, otherwise a 422 HTTP response will be returned.

For HTML requests, it will display a message informing about any validation error, or informing the user in case of success.

For JSON requests, successful logins will return a JSON object containing the details of the user.

Keep in mind that this endpoint creates a deactivated user account. A successful call to this endpoint send an email to the user, with a link that the user must click in order to confirm their account and define their password. Once confirmed using this process, the user account becomes activated and fully functional, and the user will be able to log in.

While optional, it's highly recommended that you specify which apps the user will be granted access to, as most API operation validate the user's apps match datasets, widgets, etc. All accounts created this way will have the USERrole.

This endpoint also supports receiving a callbackUrl parameter (this can either be provided as query parameter or as part of the request body). This field contains the URL where the user will be redirected to after confirming their account. If not provided, it will default to the value of the HTTP Referrer header of the sign-up request.

Errors for registering a new user account

Error code Error message Description
422 Email exists. An account already exists for the provided email address.
422 Email is required. You are missing one of the required fields.

Password recovery

Password recovery endpoints support both HTML and JSON output formats, depending on the Content-type provided in the request. These can be used either as part of your application (for example, if you want your UI to have these features built in) or as a standalone, end user facing interface (for applications that prefer to rely on the existing UI elements provided by the RW API).

GET <BASE API URL>/auth/reset-password

Displays the password reset form HTML page.

POST <BASE API URL>/auth/reset-password

Request a password reset

curl -X POST "https://api.resourcewatch.org/auth/reset-password" \
-H "Content-Type: application/json"  -d \
 '{
    "email":"your-email@provider.com"
}'

Response (JSON)

{
  "message": "Email sent"
}

Endpoint where the password reset request is sent. If an account associated with the provided email address exists, a message will be sent to it with a link that will allow the user to reset their account's password. That link will be valid for 24 hours.

Note that, for security reasons, if no account associated with the provided email address exists, the output will be the same.

This endpoint supports receiving a callbackUrl parameter (this can either be provided as query parameter or as part of the request body). This field contains the URL where the user will be redirected to after resetting their password. If not provided, it will default to the value of the HTTP Referrer header of the sign-up request.

Errors for requesting a password reset

Error code Error message Description
422 Mail required. You need to specify the email address in the request body.
400 Password recovery not allowed. Your email address is already associated with an account that uses a 3rd party login (Google/Facebook/Apple) You are requesting a password request for an email address already associated with an existing user account, and said account was created using one of the available 3rd party social logins. You should log in using that social login provider (for security reasons, the RW API does not disclose which social login provider is associated with this email address).

User details management

This section covers endpoints that focus on retrieving, modifying or deleting user accounts. Unlike previous endpoints, these are meant to be consumed by applications, and will always produce a JSON response.

Getting all users

Lists all currently active users belonging to the same apps as the requester

curl -X GET "https://api.resourcewatch.org/auth/user"
-H "Content-Type: application/json"  -d \
-H "Authorization: Bearer <your-token>"

Response:

{
  "data": [
    {
      "id": "5d2fadb3adf1dc74d2ad05dfb",
      "_id": "5d2fadb3adf1dc74d2ad05dfb",
      "email": "john.doe@vizzuality.com",
      "provider": "local",
      "createdAt": "2019-10-31T13:00:58.191Z",
      "updatedAt": "2019-10-31T13:00:58.191Z",
      "role": "USER",
      "organizations": [],
      "applications": [],
      "extraUserData": {
        "apps": []
      }
    },
    {
      ...
    }
  ],
  "links": {
    "self": "https://api.resourcewatch.org/auth/user?page[number]=1&page[size]=10",
    "first": "https://api.resourcewatch.org/auth/user?page[number]=1&page[size]=10",
    "prev": "https://api.resourcewatch.org/auth/user?page[number]=1&page[size]=10",
    "next": "https://api.resourcewatch.org/auth/user?page[number]=1&page[size]=10"
  }
}

This endpoint allows users with ADMIN role to list and filter existing user accounts. Through this endpoint, only 3rd party-based and confirmed email-based user accounts are listed - user accounts that have not been confirmed will not be listed. It's also important to keep in mind that, by default, only users belonging to the same apps as the requesting user will be shown - you can use filters to modify this behavior.

Errors for getting all users

Error code Error message Description
401 Not authenticated. You need to be logged in to use this endpoint.

Pagination

Example request using the "cursor" strategy:

curl -X GET "https://api.resourcewatch.org/auth/user?strategy=cursor"
-H "Content-Type: application/json"  -d \
-H "Authorization: Bearer <your-token>"

Example request using the "offset" strategy:

curl -X GET "https://api.resourcewatch.org/auth/user?strategy=offset"
-H "Content-Type: application/json"  -d \
-H "Authorization: Bearer <your-token>"

Currently, this endpoint supports 2 pagination strategies: "cursor" and "offset". Both strategies are available via the "strategy" query parameter: strategy=offset to use the "offset" strategy, and strategy=cursor to use the " cursor" strategy;

Until May 1st 2021, if nothing is provided, the default strategy used will be "offset". After May 1st, the "offset" strategy will be officially deprecated, and the "cursor" strategy will become the default. During this period, the " offset" strategy will still be accessible by passing the strategy=offset parameter in the request.

After September 30th 2021, the "offset" strategy will be officially deprecated. Passing the strategy=offset parameter will no longer be supported, and the "cursor" strategy will remain the default going forward.

If you are here for the first time, you should use the "cursor" strategy.

Pagination using cursor strategy

Example request to the first page with "cursor" strategy:

curl -X GET "https://api.resourcewatch.org/auth/user?strategy=cursor"
-H "Content-Type: application/json"  -d \
-H "Authorization: Bearer <your-token>"

Example response, including the "links" object in the response body:

{
  "data": [
    {
      "id": "57bc261af098ce980079873e",
      "_id": "57bc261af098ce980079873e",
      "email": "your@email.com",
      "name": "",
      "createdAt": "2021-03-24T09:19:25.000Z",
      "updatedAt": "2021-03-26T09:54:08.000Z",
      "role": "USER",
      "provider": "local",
      "organizations": [],
      "applications": [],
      "extraUserData": {
        "apps": [
          "gfw"
        ]
      }
    },
    {
      ...
    },
    {
      ...
    },
    {
      ...
    },
    {
      ...
    },
    {
      ...
    },
    {
      ...
    },
    {
      ...
    },
    {
      ...
    },
    {
      ...
    }
  ],
  "links": {
    "self": "https://api.resourcewatch.org/auth/user?strategy=cursor&page[before]=00ucw0wd1cUIGDMed5d6&page[size]=10",
    "first": "https://api.resourcewatch.org/auth/user?strategy=cursor&page[size]=10",
    "next": "https://api.resourcewatch.org/auth/user?strategy=cursor&page[after]=00ucw0wd1cUIGDMed5d6&page[size]=10"
  }
}

Example request to the page after the cursor provided with "cursor" strategy:

curl -X GET "https://api.resourcewatch.org/auth/user?strategy=cursor&page[after]=00ucw0wd1cUIGDMed5d6"
-H "Content-Type: application/json"  -d \
-H "Authorization: Bearer <your-token>"

Cursor-based pagination works by returning a slice of results, and a pointer to the end of the slice returned. On subsequent requests, you can then use the cursor to request the next slice of results after (or before) the cursor provided. Cursor-paginated methods accept limiting the amount of returned results through the page[size] query parameter - defaults to 10, with a maximum supported value of 200 -, and control of the slice returned through the page[after] and page[before] query parameters.

By default, if you don't pass a page[after] or page[before] parameter, you'll receive the first portion of results. Paginated responses include a top-level links object in the response body, that includes the link you should use to fetch the previous or next page of data.

If the slice of data you received is smaller than the page[size] provided (or 10, the default value), that indicates no further results.

Please keep in mind that, until May 1st 2021, you need to provide strategy=cursor to use this pagination strategy.

Pagination using offset strategy

DEPRECATED: Example request to load page 2 using 25 results per page using the "offset" strategy:

curl -X GET "https://api.resourcewatch.org/auth/user?strategy=offset&page[number]=2&page[size]=25"
-H "Content-Type: application/json"  -d \
-H "Authorization: Bearer <your-token>"

Until September 30th 2021, like with many other resources across the RW API, you can also paginate results with a strategy based on page number (page[number]) and page size (page[size]).

You can read more about this pagination strategy in the Pagination guidelines for the RW API. Please keep in mind that:

Also, due to the inner workings of the underlying system used by the RW API for user management, the higher the page number is, the longer the response will take to be returned. This is the principal reason we are deprecating this strategy, and a very valid reason why you should avoid using this strategy altogether.

Filters

List users with the ADMIN role (and associated with the current user's app)

curl -X GET "https://api.resourcewatch.org/auth/user?role=ADMIN"
-H "Content-Type: application/json"  -d \
-H "Authorization: Bearer <your-token>"

List users with the ADMIN role and associated with either gfw or rw apps

curl -X GET "https://api.resourcewatch.org/auth/user?role=ADMIN&app=gfw,rw"
-H "Content-Type: application/json"  -d \
-H "Authorization: Bearer <your-token>"

Response:

{
  "data": [
    {
      "id": "5d2fadb3adf1dc74d2ad05dfb",
      "_id": "5d2fadb3adf1dc74d2ad05dfb",
      "provider": "local",
      "email": "john.doe@vizzuality.com",
      "createdAt": "2019-10-31T13:00:58.191Z",
      "updatedAt": "2019-10-31T13:00:58.191Z",
      "role": "ADMIN",
      "organizations": [],
      "applications": [],
      "extraUserData": {
        "apps": [
          "rw"
        ]
      }
    },
    {
      ...
    }
  ],
  "links": {
    "self": "https://api.resourcewatch.org/auth/user?page[number]=1&page[size]=10",
    "first": "https://api.resourcewatch.org/auth/user?page[number]=1&page[size]=10",
    "last": "https://api.resourcewatch.org/auth/user?page[number]=1&page[size]=10",
    "prev": "https://api.resourcewatch.org/auth/user?page[number]=1&page[size]=10",
    "next": "https://api.resourcewatch.org/auth/user?page[number]=1&page[size]=10"
  },
  "meta": {
    "total-pages": 1,
    "total-items": 3,
    "size": 10
  }
}

The users list provides a set of parameters that you can use to tailor your users listing. Please note that filtering users 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 users list endpoint:

Filter Description Type Expected values
name Filter returned users by their name. String any valid text
email Filter returned users by their email address. Keep in mind that user accounts that rely on 3rd party authentication mechanisms may not have an email address. String any valid text
provider Filter returned users by their provider. String local, google, twitter, facebook or apple
role Filter returned users by their role. String USER, MANAGER or ADMIN
app Filter returned users by their app. Multiple values can be passed, separated by commas, in which case any user associated with at least one of the applications will be returned. Pass all to show users for all apps. String any valid text

Get the current user

Shows info for user currently logged in

curl -X GET "https://api.resourcewatch.org/auth/user/me"
-H "Content-Type: application/json"  -d \
-H "Authorization: Bearer <your-token>"

Response

{
  "provider": "local",
  "role": "ADMIN",
  "_id": "5dbadb0adf24534d1ad05dfb",
  "id": "5dbadb0adf24534d1ad05dfb",
  "email": "test.user@example.com",
  "organizations": [],
  "applications": [],
  "extraUserData": {
    "apps": [
      "rw",
      "gfw"
    ]
  },
  "createdAt": "2019-10-31T13:00:58.191Z",
  "updatedAt": "2019-10-31T13:00:58.191Z"
}

This endpoint allows you to get the details of the user account associated with the current token. It's available to all authenticated users.

Errors for getting the current user

Error code Error message Description
401 Not authenticated. You need to be logged in to use this endpoint.

Get a user by id

Shows info for user with the given id

curl -X GET "https://api.resourcewatch.org/auth/user/<user_id>"
-H "Content-Type: application/json"  -d \
-H "Authorization: Bearer <your-token>"

Response

{
  "provider": "local",
  "role": "ADMIN",
  "_id": "5dbadb0adf24534d1ad05dfb",
  "id": "5dbadb0adf24534d1ad05dfb",
  "email": "test.user@example.com",
  "organizations": [],
  "applications": [],
  "extraUserData": {
    "apps": [
      "rw",
      "gfw"
    ]
  },
  "createdAt": "2019-10-31T13:00:58.191Z",
  "updatedAt": "2019-10-31T13:00:58.191Z"
}

This endpoint allows you to get the details of the user account associated with the current token. It's available to users with role ADMIN.

Errors for getting a user by id

Error code Error message Description
401 Not authenticated. You need to be logged in to use this endpoint.
403 Not authorized. You need to have the ADMIN role to use this endpoint.

Create a user account

curl -X POST "https://api.resourcewatch.org/auth/user"
-H "Content-Type: application/json"  -d \
-H "Authorization: Bearer <your-token>" \
 '{
    "name":"new-name",
    "email":"test@example.com",
    "photo": "https://photo-url.com",
    "extraUserData" : {
        apps: ["rw", "gfw"]
    },
    "role": "MANAGER"
}'

Response:

{
  "data": {
    "id": "57bc2611f098ce9800798688",
    "_id": "57bc2611f098ce9800798688",
    "provider": "local",
    "email": "test@example.com",
    "name": "new-name",
    "photo": "https://photo-url.com",
    "createdAt": "2017-01-13T10:45:46.368Z",
    "updatedAt": "2017-01-13T10:45:46.368Z",
    "role": "MANAGER",
    "organizations": [],
    "applications": [],
    "extraUserData": {
      "apps": [
        "rw",
        "gfw"
      ]
    }
  }
}

This endpoints allows existing users to create a new user account. It's available to any logged in user who have either ADMIN or MANAGER roles, and supports providing the following fields:

The response will contain the user details, reflecting the applied changes.

It's worth keeping in mind that applications can either belong to a single user or a single organization, so by updating an user with applications associated with it, you may be removing associations between the provided applications and other users/organizations.

Errors for creating user account details

Error code Error message Description
400 Email exists. An user account with the provided email address already exists.
400 Apps required. You must provide at least one extraUserData.apps value.
400 "organizations[0].role" must be [ORG_MEMBER] When creating a new user and associating it with an organization, you can only use the ORG_MEMBER organization role.
401 Not authenticated. You need to be logged in to use this endpoint.
403 Forbidden. You can only assign the new user extraUserData.apps values that your own user account has.
403 You don't have permissions to associate this/these organization(s) You can only associate the new user with organizations if you have the ADMIN role or are the organization admin

Update your user account details

Updates current user details

curl -X PATCH "https://api.resourcewatch.org/auth/user/me"
-H "Content-Type: application/json"  -d \
-H "Authorization: Bearer <your-token>" \
 '{
    "name":"new-name",
    "photo": "https://photo-url.com",
    "extraUserData" : {
        apps: ["rw", "gfw"]
    },
    "role": "MANAGER"
}'

Response:

{
  "data": {
    "id": "57bc2611f098ce9800798688",
    "_id": "57bc2611f098ce9800798688",
    "provider": "local",
    "email": "test@example.com",
    "name": "new-name",
    "photo": "https://photo-url.com",
    "createdAt": "2017-01-13T10:45:46.368Z",
    "updatedAt": "2017-01-13T10:45:46.368Z",
    "role": "MANAGER",
    "organizations": [],
    "applications": [],
    "extraUserData": {
      "apps": [
        "rw",
        "gfw"
      ]
    }
  }
}

This endpoints allows updating your user account details. It's available to any logged in user, allowing them to modify the following fields:

The response will contain the user details, reflecting the applied changes.

It's worth keeping in mind that applications can either belong to a single user or a single organization, so by updating an user with applications associated with it, you may be removing associations between the provided applications and other users/organizations.

Errors for updating your user account details

Error code Error message Description
401 Not authenticated. You need to be logged in to use this endpoint.
400 "organizations[0].role" must be [ORG_MEMBER] When updating your user and associating it with an organization, you can only use the ORG_MEMBER organization role.
403 You don't have permissions to associate application with user . You are trying to create or modify an association between a user and an application for which you don't have permission.

Update another user's account details

Updates details of user given its id

curl -X PATCH "https://api.resourcewatch.org/auth/user/57bc2611f098ce9800798688"
-H "Content-Type: application/json"  -d \
-H "Authorization: Bearer <your-token>" \
 '{
    "name":"new-name",
    "photo": "https://photo-url.com",
    "extraUserData" : {
        apps: ["rw", "gfw"]
    },
    "role": "MANAGER"
}'

Response:

{
  "data": {
    "id": "57bc2611f098ce9800798688",
    "_id": "57bc2611f098ce9800798688",
    "provider": "local",
    "email": "test@example.com",
    "name": "new-name",
    "photo": "https://photo-url.com",
    "createdAt": "2017-01-13T10:45:46.368Z",
    "updatedAt": "2017-01-13T10:45:46.368Z",
    "role": "MANAGER",
    "organizations": [],
    "applications": [],
    "extraUserData": {
      "apps": [
        "rw",
        "gfw"
      ]
    }
  }
}

This endpoints allows updating the user account details of another user. It's available to users with the ADMIN role, allowing them to modify the following fields:

The response will contain the user details, reflecting the applied changes.

It's worth keeping in mind that applications can either belong to a single user or a single organization, so by updating an user with applications associated with it, you may be removing associations between the provided applications and other users/organizations.

Errors for updating another user's account details

Error code Error message Description
400 "organizations[0].role" must be [ORG_MEMBER] When updating another user and associating it with an organization, you can only use the ORG_MEMBER organization role.
401 Not authenticated. You need to be logged in to use this endpoint.
403 Not authorized. You need to have the ADMIN role to use this endpoint.

Getting all resources for a user id

Get all resource for a user by its id

curl -L "https://api.resourcewatch.org/auth/user/<user_id>/resources"
-H "Content-Type: application/json" \
-H "Authorization: Bearer <your-token>"

Response

{
  "datasets": {
    "data": [],
    "count": 0
  },
  "layers": {
    "data": [],
    "count": 0
  },
  "widgets": {
    "data": [],
    "count": 0
  },
  "userAccount": {
    "data": {
      "id": "<user_id>",
      "_id": "<user_id>",
      "email": "john.doe@sample.com",
      "provider": "local",
      "role": "USER",
      "extraUserData": {
        "apps": [
          "gfw"
        ]
      },
      "createdAt": "2023-03-10T23:05:41.000Z",
      "updatedAt": "2023-03-10T23:08:28.000Z"
    },
    "count": 1
  },
  "userData": {
    "data": [],
    "count": 0
  },
  "collections": {
    "data": [],
    "count": 0
  },
  "favourites": {
    "data": [],
    "count": 0
  },
  "areas": {
    "data": [],
    "count": 0
  },
  "stories": {
    "data": [],
    "count": 0
  },
  "subscriptions": {
    "data": [],
    "count": 0
  },
  "dashboards": {
    "data": [],
    "count": 0
  },
  "profiles": {
    "data": [],
    "count": 0
  },
  "topics": {
    "data": [],
    "count": 0
  }
}

This endpoints allows users to get a list of all the resources they own (through their userId or equivalent property) on the RW API. It's available to users with the ADMIN role, and will list resources of the following type:

Errors for getting all resources for a user id

Error code Error message Description
401 Not authenticated. You need to be logged in to use this endpoint.
403 Not authorized. You need to have the ADMIN role to use this endpoint.

Deleting a user

Deletes a user by its id

curl -X DELETE "https://api.resourcewatch.org/auth/user/<user_id>"
-H "Content-Type: application/json"  -d \
-H "Authorization: Bearer <your-token>"

Response

{
  "data": {
    "id": "57bc2611f098ce9800798688",
    "_id": "57bc2611f098ce9800798688",
    "provider": "local",
    "email": "test@example.com",
    "name": "new-name",
    "photo": "https://photo-url.com",
    "createdAt": "2017-01-13T10:45:46.368Z",
    "updatedAt": "2017-01-13T10:45:46.368Z",
    "role": "MANAGER",
    "organizations": [],
    "applications": [],
    "extraUserData": {
      "apps": [
        "rw",
        "gfw"
      ]
    }
  }
}

This endpoints deletes the user account with the given id. It's available to users with the ADMIN role and to users who want to delete their own account. The response will contain the details of the user account that was deleted.

Besides the actual user account, this action also deletes all resources of the following types that belong (through their userId or equivalent property) to the user:

The deletion of the above resources is done using a "best effort" approach: if some/all of them fail, the user deletion process will not be stopped or error, and the user account will be deleted anyways. When a user is deleted, a corresponding deletion is created, which can be used to track the success/failure of the different resource deletion process. Managing deletion resources is considered a RW API developer feature, and it's not meant to be used by regular RW API users.

Errors for deleting a user

Error code Error message Description
400 Cannot delete user that is admin of an organization Cannot delete user that is admin of an organization. Either delete the organization or promote another user to admin of that organization.
401 Not authenticated. You need to be logged in to use this endpoint.
403 Not authorized. You need to have ADMIN role or be logged as the user to delete to use this endpoint.

Application

The following endpoints expose the RW API's functionality regarding application management.

Applications vs applications

Naming things is said to be one of the most challenging tasks software developers face, and the team behind the RW API is no different, which is why the RW API effectively has 2 different notions of applications:

This documentation section will focus on the second instance, while you can learn more about the first one in the link above.

What is an application?

In the context of the RW API, an application correspond to a unique software application which functionality relies on the RW API. Some examples of this are the Resource Watch or the Global Forest Watch websites. If you want to develop your own application that uses any of the RW API endpoints or data, you need to create an application.

Each application has, among other elements, an API key. Each API key is unique, and should be provided with each HTTP request your client application makes to the RW API. This key is used to identify your application, and serves to ensure fair usage of shared RW API resources, or allow you to request a higher request throttle limit, should you so require.

Note that applications and API keys do not replace user authentication, and they are meant to be used simultaneously, as they fundamentally serve two different purposes:

Application ownership

Before diving into application management endpoints, there is another important point that you should keep in mind when managing your applications - application ownership. Simply put, each application must have an owner, which must be either a user or an organization. A user identifies a single person using the RW API, while an organization groups different users and grants them shared privileges over applications. Each application must be owned by either a single user or a single organization, and only the owner of an application can modify it.

Whenever you create/edit an application you must/can provide either a user id or an organization id to set it as the application's owner. You cannot provide both simultaneously, and if you are editing an existing application, the newly passed ownership value will overwrite the previous one.

Getting all applications

Getting a list of applications

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

Response:

{
  "data": [
    {
      "type": "applications",
      "id": "63be3da993ea69eb458fc466",
      "attributes": {
        "name": "Sample application",
        "organization": null,
        "user": {
          "id": "5bfd237767b3176dd63f2eb7",
          "name": "John Doe"
        },
        "apiKeyValue": "8a81e9de-517e-466f-a5d3-a1d4ccf0e290",
        "createdAt": "2023-01-11T04:40:09.455Z",
        "updatedAt": "2023-01-11T04:40:09.455Z"
      }
    }
  ],
  "links": {
    "self": "https://api.resourcewatch.org/v1/application?page[number]=1&page[size]=10",
    "first": "https://api.resourcewatch.org/v1/application?page[number]=1&page[size]=10",
    "last": "https://api.resourcewatch.org/v1/application?page[number]=99&page[size]=10",
    "prev": "https://api.resourcewatch.org/v1/application?page[number]=1&page[size]=10",
    "next": "https://api.resourcewatch.org/v1/application?page[number]=2&page[size]=10"
  },
  "meta": {
    "total-pages": 99,
    "total-items": 990,
    "size": 10
  }
}

This endpoint will allow you to get the list of the applications available in the API. By default, this endpoint will give you a paginated list of 10 applications.

Depending on your user role, the behavior of this endpoint will vary:

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

Pagination

Example request to load page 2 using 25 results per page

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

The application 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 applications list.

Errors for getting all applications

Error code Error message (example) Description
400 "page.size" must be less than or equal to 100 You cannot request page sizes larger than 100
401 Not authenticated No authorization token was provided.

Getting an application by id

Getting an application by id:

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

Response:

{
  "data": {
    "type": "applications",
    "id": "63be3da993ea69eb458fc4a6",
    "attributes": {
      "name": "Sample application",
      "organization": null,
      "user": {
        "id": "5bfd237767b3176dd63f2eb7",
        "name": "John Doe"
      },
      "apiKeyValue": "8a81e9de-517e-466f-a5d3-a1d4ccf0e290",
      "createdAt": "2023-01-11T04:40:09.455Z",
      "updatedAt": "2023-01-11T04:40:09.455Z"
    }
  }
}

If you know the id of an application, then you can access it directly. The id is case-sensitive.

To access the details of a given application using this endpoint, you need to meet one of the following conditions:

Errors for getting an application by id

Error code Error message (example) Description
401 Not authenticated No authorization token was provided.
403 Not authorized You don't have the necessary permissions to see the details for this application.
404 Application not found The application id provided is invalid or does not match any of the existing applications.

Creating an application

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

Response:

{
  "data": {
    "type": "applications",
    "id": "63be3da993ea69eb458fc4a6",
    "attributes": {
      "name": "Sample application",
      "organization": null,
      "user": {
        "id": "5bfd237767b3176dd63f2eb7",
        "name": "John Doe"
      },
      "apiKeyValue": "8a81e9de-517e-466f-a5d3-a1d4ccf0e290",
      "createdAt": "2023-01-11T04:40:09.455Z",
      "updatedAt": "2023-01-11T04:40:09.455Z"
    }
  }
}

Creating an application should be one of your very first steps when using the RW API, as you will need it to make subsequent requests for other resources, like datasets, widgets, etc. If you haven't already, you should review the details of what is an application and application ownership before proceeding.

Creating an application is done using a POST request and passing the relevant data as body fields. The supported body fields are as defined on the application reference section, but the minimum value you need to provide is the name.

Unless specified otherwise, an application owned by the user who created it. If you have the ADMIN user role, you can specify the id of the user who will own the application through the user body field. You can alternatively use the organization body field to specify the id of the organization that will own the application - you can only do so if you have the ADMIN user role, or own that organization.

Any logged in user can create an application.

A successful application creation request will return a 200 HTTP code, and the application details as stored on the RW API. Pay special attention to the id, as it will allow you to access your application later.

Errors for creating an application

Error code Error message Description
400 <field> is required Your are missing a required field value.
400 <field> is not allowed You have provided a body value that is not supported by the endpoint.
400 "value" must contain at least one of [user, organization] You must provided exactly one of either user or organization
401 Not authenticated You are not authenticated. Only authenticated users can create applications.
403 Not authorized You are authenticated but do not have the necessary permissions to create this application.
403 User can only create applications for themselves or organizations they own You are trying to create an application for a user or organization to which you don't have permissions.

Updating an application

Updating an application

curl -X PATCH "https://api.resourcewatch.org/v1/application/51943691-eebc-4cb4-bdfb-057ad4fc2145"
-H "Content-Type: application/json"  -d \
-H "Authorization: Bearer <your-token>" \
 '{
    "name":"new application name",
}'

Example response

{
  "data": {
    "type": "applications",
    "id": "63be3da993ea69eb458fc4a6",
    "attributes": {
      "name": "new application name",
      "organization": null,
      "user": {
        "id": "5bfd237767b3176dd63f2eb7",
        "name": "John Doe"
      },
      "apiKeyValue": "8a81e9de-517e-466f-a5d3-a1d4ccf0e290",
      "createdAt": "2023-01-11T04:40:09.455Z",
      "updatedAt": "2023-01-11T04:40:09.455Z"
    }
  }
}

Modify an application to be owned by an organization

curl -X PATCH "https://api.resourcewatch.org/v1/application/51943691-eebc-4cb4-bdfb-057ad4fc2145"
-H "Content-Type: application/json"  -d \
-H "Authorization: Bearer <your-token>" \
 '{
    "organization":"6bfd237767b3176dd63f2eb7",
}'

Example response

{
  "data": {
    "type": "applications",
    "id": "63be3da993ea69eb458fc4a6",
    "attributes": {
      "name": "new application name",
      "user": null,
      "organization": {
        "id": "6bfd237767b3176dd63f2eb7",
        "name": "Organization name"
      },
      "apiKeyValue": "8a81e9de-517e-466f-a5d3-a1d4ccf0e290",
      "createdAt": "2023-01-11T04:40:09.455Z",
      "updatedAt": "2023-01-11T04:40:09.455Z"
    }
  }
}

Generate a new API key

curl -X PATCH "https://api.resourcewatch.org/v1/application/51943691-eebc-4cb4-bdfb-057ad4fc2145"
-H "Content-Type: application/json"  -d \
-H "Authorization: Bearer <your-token>" \
 '{
    "regenApiKey":"true",
}'

Example response

{
  "data": {
    "type": "applications",
    "id": "63be3da993ea69eb458fc4a6",
    "attributes": {
      "name": "Sample application",
      "user": null,
      "organization": {
        "id": "6bfd237767b3176dd63f2eb7",
        "name": "Organization name"
      },
      "apiKeyValue": "9811e9de-517e-466f-a5d3-a1d4ccf0e017",
      "createdAt": "2023-01-11T04:40:09.455Z",
      "updatedAt": "2023-01-11T04:40:09.455Z"
    }
  }
}

This endpoint allows you to modify an existing application. You can modify the name, ownership (by passing the id of either the user or orgnaization). You can also request for a new API key to be issued for your application - in which case the previous API key will become invalid, and all requests using it may stop functioning.

To be able to modify an application, you must either have the ADMIN user role, be the owner of the application, or belong to the organization that owns the application with the ORG_ADMIN role.

Errors for updating an application

Error code Error message Description
400 <field> is not allowed You have provided a body value that is not supported by the endpoint.
400 "value" contains a conflict between optional exclusive peers [user, organization] You can only provide one of ether user or organization.
401 Not authenticated You are not authenticated. Only authenticated users can update applications.
403 Not authorized You are authenticated but do not have the necessary permissions to update this application.
404 Application with id doesn't exist An application with the provided id does not exist.

Deleting an application

Deleting an application

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

Response:

{
  "data": {
    "type": "applications",
    "id": "63be3da993ea69eb458fc4a6",
    "attributes": {
      "name": "Sample application",
      "organization": null,
      "user": {
        "id": "5bfd237767b3176dd63f2eb7",
        "name": "John Doe"
      },
      "apiKeyValue": "8a81e9de-517e-466f-a5d3-a1d4ccf0e290",
      "createdAt": "2023-01-11T04:40:09.455Z",
      "updatedAt": "2023-01-11T04:40:09.455Z"
    }
  }
}

Use this endpoint if you wish to delete an application. Deleting an application will render its API key invalid, and all requests made using it will return an error.

To be able to delete an application, you must either have the ADMIN user role, be the owner of the application, or belong to the organization that owns the application with the ORG_ADMIN role.

Errors for deleting an application

Error code Error message Description
401 Unauthorized You need to be logged in to be able to delete an application.
401 Not authenticated You are not authenticated. Only authenticated users can delete applications.
403 Not authorized You are authenticated but do not have the necessary permissions to delete this application.
404 Application with id doesn't exist An application with the provided id does not exist.

Application reference

This section gives you a complete view at the properties that are maintained as part of application. When interacting with an application (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 application. Auto generated on creation. Cannot be modified by users.
name String Yes Name of the application.
user String Yes (either user or organization) Id of the user who owns the application. Either this or organization must be set. Only the id is stored. If set, responses will include the id and the name.
organization String Yes (either user or organization) Id of the organization who owns the application. Either this or user must be set. Only the id is stored. If set, responses will include the id and the name.
createdAt Date No (autogenerated) Automatically maintained date of when the application was created. Cannot be modified by users.
updatedAt Date No (autogenerated) Automatically maintained date of when the application was last updated. Cannot be modified by users.

Organization

The following endpoints expose the RW API's functionality regarding organization management.

What is an organization?

In the context of the RW API, an organization is an resource meant to group multiple users and grant them certain permissions and/or ownership over a group of applications. An example of an RW API organization would be WRI itself, the owner of the RW API - it's an entity that has multiple people (users) and that runs multiple software applications (GFW, RW, etc) that rely on the services of the RW API.

Organization ownership and user association

Each organization can have multiple users, yet not all users in the same organization have the same permissions to operate over said organization's resources. To differentiate between these types of access, every user associated with an organization does so through one of the following roles:

A user can be associated with any number of organizations, and can have a different role for each of them.

Getting all organizations

Getting a list of organizations

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

Response:

{
  "data": [
    {
      "type": "organizations",
      "id": "63da7d2357499d85f8436cd9",
      "attributes": {
        "name": "Test org 1",
        "applications": [
          {
            "id": "63be3da993ea69eb458fc466",
            "name": "Sample application"
          }
        ],
        "users": [
          {
            "id": "5bfd237767b3176dd63f2eb7",
            "name": "John Doe",
            "role": "ORG_ADMIN"
          }
        ],
        "createdAt": "2023-02-01T14:54:27.530Z",
        "updatedAt": "2023-02-01T14:54:27.530Z"
      }
    }
  ],
  "links": {
    "self": "https://api.resourcewatch.org/v1/organization?page[number]=1&page[size]=10",
    "first": "https://api.resourcewatch.org/v1/organization?page[number]=1&page[size]=10",
    "last": "https://api.resourcewatch.org/v1/organization?page[number]=99&page[size]=10",
    "prev": "https://api.resourcewatch.org/v1/organization?page[number]=1&page[size]=10",
    "next": "https://api.resourcewatch.org/v1/organization?page[number]=2&page[size]=10"
  },
  "meta": {
    "total-pages": 99,
    "total-items": 990,
    "size": 10
  }
}

This endpoint will allow you to get the list of the organizations available in the API. By default, this endpoint will give you a paginated list of 10 organizations.

In order to use this endpoint, you need to be authenticated as an ADMIN or MANAGER user.

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

Pagination

Example request to load page 2 using 25 results per page

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

The organization 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 organizations list.

Getting an organization by id

Getting an organization by id:

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

Response:

{
  "data": {
    "type": "organizations",
    "id": "63da7d2357499d85f8436cd9",
    "attributes": {
      "name": "Test org 1",
      "applications": [
        {
          "id": "63be3da993ea69eb458fc466",
          "name": "Sample application"
        }
      ],
      "users": [
        {
          "id": "5bfd237767b3176dd63f2eb7",
          "name": "John Doe",
          "role": "ORG_ADMIN"
        }
      ],
      "createdAt": "2023-02-01T14:54:27.530Z",
      "updatedAt": "2023-02-01T14:54:27.530Z"
    }
  }
}

If you know the id of an organization, then you can access it directly. The id is case-sensitive.

In order to use this endpoint, you must be logged in and either:

Errors for getting an organization by id

Error code Error message (example) Description
401 Not authenticated No authorization token was provided.
403 Not authorized You do not have the necessary permissions to see this organization's details.

Creating an organization

curl -X POST "https://api.resourcewatch.org/v1/organization" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <your-token>" \
-d  \
'{
    "name": "Test org 1",
    "user": [{
      "id": "5bfd237767b3176dd63f2eb7",
      "role": "ORG_ADMIN"
    }]
}'

Response:

{
  "data": {
    "type": "organizations",
    "id": "63be3da993ea69eb458fc4a6",
    "attributes": {
      "name": "Test org 1",
      "applications": [],
      "users": [
        {
          "id": "5bfd237767b3176dd63f2eb7",
          "name": "John Doe",
          "role": "ORG_ADMIN"
        }
      ],
      "createdAt": "2023-01-11T04:40:09.455Z",
      "updatedAt": "2023-01-11T04:40:09.455Z"
    }
  }
}

Creating an organization is currently reserved for RW API administrators (users with the ADMIN role, so if you'd like to create your own, please contact us letting us know about you and your organization.

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

A successful organization creation request will return a 200 HTTP code, and the organization details as stored on the RW API. Pay special attention to the id, as it will allow you to access your organization later.

When creating an organization, you can also pass an optional array of applications ids, as applications in the request body. These applications must already exist.

It's worth keeping in mind that applications can either belong to a single user or a single organization, so by creating an organization with applications associated with it, you may be removing associations between the provided applications and other users/organizations.

Errors for creating an organization

Error code Error message Description
400 <field> is required Your are missing a required field value.
400 <field> is not allowed You have provided a body value that is not supported by the endpoint.
400 "users" must contain at least 1 items You must provide at least one user.
400 "users" must contain a user with role ORG_ADMIN' You must provide at least a user with ORG_ADMIN role.
401 Not authenticated You are not authenticated. Only authenticated users can create organizations.
403 Not authorized You are authenticated but do not have the necessary permissions to create this organization.

Updating an organization

Updating an organization

curl -X PATCH "https://api.resourcewatch.org/v1/organization/51943691-eebc-4cb4-bdfb-057ad4fc2145"
-H "Content-Type: organization/json"  -d \
-H "Authorization: Bearer <your-token>" \
 '{
    "name":"new organization name",
}'

Example response

{
  "data": {
    "type": "organizations",
    "id": "63be3da993ea69eb458fc4a6",
    "attributes": {
      "name": "new organization name",
      "applications": [],
      "users": [
        {
          "id": "5bfd237767b3176dd63f2eb7",
          "name": "John Doe",
          "role": "ORG_ADMIN"
        }
      ],
      "createdAt": "2023-01-11T04:40:09.455Z",
      "updatedAt": "2023-01-11T04:40:09.455Z"
    }
  }
}

Modify an organization and replacing its applications

curl -X PATCH "https://api.resourcewatch.org/v1/organization/51943691-eebc-4cb4-bdfb-057ad4fc2145"
-H "Content-Type: organization/json"  -d \
-H "Authorization: Bearer <your-token>" \
 '{
    "applications": ["6bfd237767b3176dd63f2eb7"],
}'

Example response

{
  "data": {
    "type": "organizations",
    "id": "63be3da993ea69eb458fc4a6",
    "attributes": {
      "name": "new organization name",
      "applications": [
        {
          "id": "6bfd237767b3176dd63f2eb7",
          "name": "application name"
        }
      ],
      "users": [
        {
          "id": "5bfd237767b3176dd63f2eb7",
          "name": "John Doe",
          "role": "ORG_ADMIN"
        }
      ],
      "createdAt": "2023-01-11T04:40:09.455Z",
      "updatedAt": "2023-01-11T04:40:09.455Z"
    }
  }
}

This endpoint allows you to modify an existing organization. When updating an organization, you can pass new values for any of these optional parameters:

When modifying either users or applications, keep in mind that the list of associations you provide will overwrite the previous one.

It's worth keeping in mind that applications can either belong to a single user or a single organization, so by updating an organization with applications associated with it, you may be removing associations between the provided applications and other users/organizations.

In order to use this endpoint, you must be logged in and either:

Additionally, if you are using this endpoint to add existing applications to an organization, you must either

Errors for updating an organization

Error code Error message Description
400 <field> is not allowed You have provided a body value that is not supported by the endpoint.
400 "users" must contain at least 1 items You must provide at least one user.
400 "users" must contain a user with role ORG_ADMIN You must provide at least a user with ORG_ADMIN role.
400 "users" must contain single a user with role ORG_ADMIN You must provide only one user with ORG_ADMIN role.
401 Not authenticated You are not authenticated. Only authenticated users can update organizations.
403 Not authorized You are authenticated but do not have the necessary permissions to update this organization, or to add one of the provided application to the organization.
404 Organization with id doesn't exist An organization with the provided id does not exist.

Deleting an organization

Deleting an organization

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

Response:

{
  "data": {
    "type": "organizations",
    "id": "63da7d2357499d85f8436cd9",
    "attributes": {
      "name": "Test org 1",
      "applications": [
        {
          "id": "63be3da993ea69eb458fc466",
          "name": "Sample application"
        }
      ],
      "users": [
        {
          "id": "5bfd237767b3176dd63f2eb7",
          "name": "John Doe",
          "role": "ORG_ADMIN"
        }
      ],
      "createdAt": "2023-02-01T14:54:27.530Z",
      "updatedAt": "2023-02-01T14:54:27.530Z"
    }
  }
}

Use this endpoint if you wish to delete an organization. In order to use this endpoint, you must be logged in and have the ADMIN user role.

Only organizations that do not have any applications associated with them can be deleted.

Errors for deleting an organization

Error code Error message Description
400 Organizations with associated applications cannot be deleted You are trying to delete an organization that still has applications associated with it. Either transfer ownership or delete the applications.
401 Not authenticated You are not authenticated. Only authenticated users can delete organizations.
403 Not authorized You are authenticated but do not have the necessary permissions to delete this organization.
404 Organization with id doesn't exist An organization with the provided id does not exist.

Organization reference

This section gives you a complete view at the properties that are maintained as part of organization. When interacting with an organization (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 organization. Auto generated on creation. Cannot be modified by users.
name String Yes Name of the organization.
users Object array Yes List of objects, each containing the id of an user, and the role they have in the organization - which can be either ORG_ADMIN or ORG_MEMBER. Every organization must have at least one ORG_ADMIN user.
applications String array No List of applications owned by this organization
createdAt Date No (autogenerated) Automatically maintained date of when the organization was created. Cannot be modified by users.
updatedAt Date No (autogenerated) Automatically maintained date of when the organization was last updated. Cannot be modified by users.

User data

The following endpoints expose the RW API's functionality regarding user data management. These endpoints will allow you to store and recover user-specific data related to the RW API, like application-specific preferences, that are not already covered by other endpoints.

These endpoints assume you already have a user account and are logged in using it - for more details on that, see this section.

What is user data?

The RW API endpoints allow users to upload their own customized data and share it with the world - it's its core mission. However, at times, you may want to store data that is specific to your usage of the RW API, and while not secret, it only makes sense to your specific user needs. Some examples of this may be a widget or layer personalization, an application' settings, or additional details about your user profile.

The User data service allows you to store data specific to your usage of the RW API, in an easy and convenient way. Besides a few core, common fields, your data is indexed by application, allowing different RW API ecosystem apps and tools to share this common data storage, while ensuring simplicity for RW API developers. To ensure this, make sure to properly store you application's data in the correct form - inside applicationData, indexed by your application's name.

Important: User data, as defined managed by these endpoints, is not the same as user account, as managed by the User management endpoints. A user account is what you use to login and authenticate. User data is an optional data storage feature, made available to anyone with an user account. Creating/updating/deleting a user account does not automatically create/update/delete user data.

Warning: The data stored through these endpoints is individual to your user account, but it's not treated and confidential or sensitive. You should not store any sort of data that you would not like to see potentially disclosed, like passwords, sensitive and/or personal information, etc.

Deprecation notice: These docs cover the /v2 user data endpoints, which are currently maintained. A /v1 set of endpoints also exists, but its deprecated, and should not be used. If your application is using the /v1 endpoints, you should upgrade at your earliest convenience. Functionality and data wise, /v2 is a superset of /v1.

Getting user data

Get user data for the current user

curl -X GET "https://api.resourcewatch.org/v2/user" \
-H "Authorization: Bearer <your-token>" \
-H "x-api-key: <your-api-key>"

Get user data for a given user id

curl -X GET "https://api.resourcewatch.org/v2/user/5bfd237767b3176dd63f2eb7" \
-H "Authorization: Bearer <your-token>" \
-H "x-api-key: <your-api-key>"

Response:

{
  "data": {
    "type": "user",
    "id": "5bfd237767b3176dd63f2eb7",
    "attributes": {
      "fullName": "John Doe",
      "email": "john.doe@wri.org",
      "createdAt": "2017-04-25T14:15:58.469Z",
      "applicationData": {
        "gfw": {
          "sector": "Private sector",
          "state": "",
          "city": "",
          "howDoYouUse": [
            ""
          ],
          "primaryResponsibilities": [
            ""
          ],
          "signUpForTesting": false,
          "language": "en",
          "profileComplete": true,
          "interests": [],
          "signUpToNewsletter": false,
          "topics": []
        }
      }
    }
  }
}

There are two endpoints that allow you to retrieve user data:

Errors

Error code Error message Description
401 Not authenticated. You are not logged in.
403 Forbidden. You do not have permission to access the requested data.
404 User not found The requested user id does not have stored user data.

Creating user data

Create user data for the current user

curl -X POST https://api.resourcewatch.org/v2/user \
-H "Authorization: Bearer <your-token>" \
-H "x-api-key: <your-api-key>" \
-H "Content-Type: application/json"  -d \
'{
  "fullName": "John Doe",
  "firstName": "John",
  "lastName": "Doe",
  "email": "john.doe@wri.org",
  "applicationData": {
    "gfw": {
      "someKey": "someValue"
    }
  }
}'
{
  "data": {
    "type": "user",
    "id": "5bfd237767b3176dd63f2eb7",
    "attributes": {
      "fullName": "John Doe",
      "firstName": "John",
      "lastName": "Doe",
      "email": "john.doe@wri.org",
      "createdAt": "2017-04-25T14:15:58.469Z",
      "applicationData": {
        "gfw": {
          "sector": "Private sector",
          "state": "",
          "city": "",
          "howDoYouUse": [
            ""
          ],
          "primaryResponsibilities": [
            ""
          ],
          "signUpForTesting": false,
          "language": "en",
          "profileComplete": true,
          "interests": [],
          "signUpToNewsletter": false,
          "topics": [],
          "someKey": "someValue"
        }
      }
    }
  }
}

This endpoint allows you to store user data for a user that did not previously have user data. Each user (by id) can only have a single user data record, and it will be shared and visible in other RW API applications that rely on these endpoints, so it's important to follow a few guidelines to help maintain coherence: - User data root fields (around name and email address) are meant to be shared between multiple apps, so only modify those if the change is intentional by the user. - All application-specific data must be stored in the applicationData object, and in it, indexed by your application name. The included example shows how the gfw application could store its data. This is not enforced, but disregarding this principle may lead to your data being deleted without prior notice. - The gfw application has special logic and fields, as seen in the included example. However, other application keys will not have this, and no manipulation will occur on your data stored. What you send is what gets stored, no more, no less.

Errors

Error code Error message Description
400 Duplicated user. This user already has data associated with it.
400 Unsupported sector. The provided applicationData.gfw.sector value is not formatted correctly.
401 Not authenticated. You are not logged in.
403 Forbidden. You do not have permission to access the requested data.

Updating user data

Update user data for the given user id

curl -X PATCH https://api.resourcewatch.org/v2/user/5bfd237767b3176dd63f2eb7 \
-H "Authorization: Bearer <your-token>" \
-H "x-api-key: <your-api-key>" \
-H "Content-Type: application/json"  -d \
'{
  "fullName": "John Doe",
  "firstName": "John",
  "lastName": "Doe",
  "email": "john.doe@wri.org",
  "applicationData": {
    "gfw": {
      "someKey": "someOtherValue"
    }
  }
}'
{
  "data": {
    "type": "user",
    "id": "5bfd237767b3176dd63f2eb7",
    "attributes": {
      "fullName": "John Doe",
      "firstName": "John",
      "lastName": "Doe",
      "email": "john.doe@wri.org",
      "createdAt": "2017-04-25T14:15:58.469Z",
      "applicationData": {
        "gfw": {
          "sector": "Private sector",
          "state": "",
          "city": "",
          "howDoYouUse": [
            ""
          ],
          "primaryResponsibilities": [
            ""
          ],
          "signUpForTesting": false,
          "language": "en",
          "profileComplete": true,
          "interests": [],
          "signUpToNewsletter": false,
          "topics": [],
          "someKey": "someOtherValue"
        }
      }
    }
  }
}

This endpoint allows you to update existing user data for a user. Similar to the user data creation process, there are a few things to keep in mind when updating user data, to help maintain coherence: - User data root fields (around name and email address) are meant to be shared between multiple apps, so only modify those if the change is intentional by the user. - All application-specific data must be stored in the applicationData object, and in it, indexed by your application name. The included example shows how the gfw application could store its data. This is not enforced, but disregarding this principle may lead to your data being deleted without prior notice. - The gfw application has special logic and fields, as seen in the included example. However, other application keys will not have this, and no manipulation will occur on your data stored. What you send is what gets stored, no more, no less. - If updating a key within the applicationData object, all its content will be replace with the values you provide. Keys not provided are kept as-is.

You can only update user data for the user provided in the authentication token.

Errors

Error code Error message Description
400 Unsupported sector. The provided applicationData.gfw.sector value is not formatted correctly.
401 Not authenticated. You are not logged in.
403 Forbidden. You do not have permission to access the requested data.
404 User not found The requested user id does not have stored user data.

Deleting user data

Delete user data for the given user id

curl -X DELETE https://api.resourcewatch.org/v2/user/5bfd237767b3176dd63f2eb7 \
-H "Authorization: Bearer <your-token>" \
-H "x-api-key: <your-api-key>"
{
  "data": {
    "type": "user",
    "id": "5bfd237767b3176dd63f2eb7",
    "attributes": {
      "fullName": "John Doe",
      "firstName": "John",
      "lastName": "Doe",
      "email": "john.doe@wri.org",
      "createdAt": "2017-04-25T14:15:58.469Z",
      "applicationData": {
        "gfw": {
          "sector": "Private sector",
          "state": "",
          "city": "",
          "howDoYouUse": [
            ""
          ],
          "primaryResponsibilities": [
            ""
          ],
          "signUpForTesting": false,
          "language": "en",
          "profileComplete": true,
          "interests": [],
          "signUpToNewsletter": false,
          "topics": [],
          "someKey": "someOtherValue"
        }
      }
    }
  }
}

This endpoint allows you to delete user data. Keep in mind that this will delete all user data for all applications, and not just yours. If you want to delete user data for your application, use the update user data endpoint instead. Fully deleting user data will typically only be used when deleting the actual user account.

You can only delete user data for the user provided in the authentication token.

Errors

Error code Error message Description
401 Not authenticated. You are not logged in.
403 Forbidden. You do not have permission to access the requested data.
404 User not found The requested user id does not have stored user data.

Troubleshooting

This section is meant to help you deal with common pitfalls of everyday usage of the API.

Authentication and authorization

401 Unauthorized

401 Unauthorized errors mean that the API did not receive the necessary data to identify who you are. You may not be logged in, there may be an issue with your usage of the user token, or the token you are using may be in the wrong header.

Make sure you have followed the quickstart guide, which shows you how to create a JSON Web Token for authorization and how to pass it correctly in the Authorization header.

403 Forbidden

A 403 Forbidden error means that you are identified as a valid user, but you do not have the required permissions for the action you are trying to perform. Common scenarios where this happens are:

Check the specific documentation for the endpoint you are trying to use for more details on its behavior. Conditions that trigger a 403 Forbidden error will often vary beyond the ones listed above.

Contact

The following contact endpoints are available

Contact us

Example request with the minimum required data

curl -X POST https://api.resourcewatch.org/v1/form/contact-us \
-H "x-api-key: <your-api-key>" \
-H "Content-Type: application/json" -d \
    '{
        "email": "example.example@vizzuality.com",
        "message": "This is a test"
    }'

Example request with complete data

curl -X POST https://api.resourcewatch.org/v1/form/contact-us \
-H "x-api-key: <your-api-key>" \
-H "Content-Type: application/json" -d \
    '{
        "email": "example.example@vizzuality.com",
        "message": "This is a test",
        "language": "es_MX",
        "tool": "fw",
        "topic": "data-related-inquiry"
    }'

Sends a contact form including an origin email address and a message. It can also optionally include:

The language value is used as a reference for future communication with the user. topic and tool are used to internally better determine the communication path the request must follow in order to reach the desired person that will handle it.

On success, a 200 HTTP code with no response body is returned.

Requesting a webinar

Example request for a webinar

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

This endpoint allows users to request a webinar. Internally, it sends the user submitted information to a WRI staff member, via email. The user must provide their name, email address, and a request text, all of which will be included in the above mentioned email. A successful request returns an HTTP 204 response.