Reference

iNaturalist actually provides two APIs:

  • the REST API that they also use internally: it is very complete and provides read/write access, but is rather slow and sometimes inconsistent.

  • the Node-based API allows searching and returning core data, is faster and provides more consistent returned results than the REST API, but has less features.

Pyinaturalist provides functions to use both of those APIs.

Note

While not mandatory, it is considered good practice in the iNaturalist community to set a custom user-agent header to your API calls. That allows iNaturalist to identify “who’s doing what” with their APIs, and maybe contact you back in case they want to start a discussion about how you use them.

It is recommended to set this user-agent field to either something that identifies the project (MyCoolAndroidApp/2.0) or its contact person (Jane Doe, iNat user XXXXXX, jane@doe.net).

Pyinaturalist therefore provides a couple of features to make that easy:

import pyinaturalist
from pyinaturalist.node_api import get_observation

pyinaturalist.user_agent = "MyCoolAndroidApp/2.0 (using Pyinaturalist)"

# From now on, all API calls will use this user-agent.

t = get_access_token('username', 'password', 'app_id', 'app_secret')
do_something_else()
get_observation(observation_id=1234)
...

In the rare cases where you want to use multiple user agents in your script, you can configure it per call:

get_observation(observation_id=16227955, user_agent='AnotherUserAgent')

(All functions that communicate with the API accept the user_agent optional parameter).

If you don’t configure the user agent, Pyinaturalist/<VERSION> will be used.

REST API

pyinaturalist.rest_api.add_photo_to_observation(observation_id, file_object, access_token, user_agent=None)[source]

Upload a picture and assign it to an existing observation.

Parameters
  • observation_id (int) – the ID of the observation

  • file_object (BinaryIO) – a file-like object for the picture. Example: open(‘/Users/nicolasnoe/vespa.jpg’, ‘rb’)

  • access_token (str) – the access token, as returned by get_access_token()

  • user_agent (Optional[str]) – a user-agent string that will be passed to iNaturalist.

pyinaturalist.rest_api.create_observations(params, access_token, user_agent=None)[source]

Create a single or several (if passed an array) observations).

Parameters
  • params (Dict[str, Dict[str, Any]]) –

  • access_token (str) – the access token, as returned by get_access_token()

  • user_agent (Optional[str]) – a user-agent string that will be passed to iNaturalist.

Return type

List[Dict[str, Any]]

Returns

iNaturalist’s JSON response, as a Python object

Raise

requests.HTTPError, if the call is not successful. iNaturalist returns an error 422 (unprocessable entity) if it rejects the observation data (for example an observation date in the future or a latitude > 90. In that case the exception’s response attribute give details about the errors.

allowed params: see https://www.inaturalist.org/pages/api+reference#post-observations

Example:

params = {‘observation’:

{‘species_guess’: ‘Pieris rapae’},

}

TODO investigate: according to the doc, we should be able to pass multiple observations (in an array, and in renaming observation to observations, but as far as I saw they are not created (while a status of 200 is returned)

pyinaturalist.rest_api.delete_observation(observation_id, access_token, user_agent=None)[source]

Delete an observation.

Parameters
  • observation_id (int) –

  • access_token (str) –

  • user_agent (Optional[str]) – a user-agent string that will be passed to iNaturalist.

Return type

List[Dict[str, Any]]

Returns

iNaturalist’s JSON response, as a Python object (currently raise a JSONDecodeError because of an iNaturalist bug

Raise

ObservationNotFound if the requested observation doesn’t exists, requests.HTTPError (403) if the observation belongs to another user

pyinaturalist.rest_api.get_access_token(username, password, app_id, app_secret, user_agent=None)[source]

Get an access token using the user’s iNaturalist username and password.

(you still need an iNaturalist app to do this)

Parameters
  • username (str) –

  • password (str) –

  • app_id (str) –

  • app_secret (str) –

  • user_agent (Optional[str]) – a user-agent string that will be passed to iNaturalist.

Return type

str

Returns

the access token, example use: headers = {“Authorization”: “Bearer %s” % access_token}

pyinaturalist.rest_api.get_all_observation_fields(search_query='', user_agent=None)[source]

Like get_observation_fields(), but handles pagination for you.

Parameters
  • search_query (str) – a string to search

  • user_agent (Optional[str]) – a user-agent string that will be passed to iNaturalist.

Return type

List[Dict[str, Any]]

pyinaturalist.rest_api.get_observation_fields(search_query='', page=1, user_agent=None)[source]

Search the (globally available) observation

Parameters
  • search_query (str) –

  • page (int) –

  • user_agent (Optional[str]) – a user-agent string that will be passed to iNaturalist.

Return type

List[Dict[str, Any]]

Returns

pyinaturalist.rest_api.put_observation_field_values(observation_id, observation_field_id, value, access_token, user_agent=None)[source]

Sets an observation field (value) on an observation.

Parameters
  • observation_id (int) –

  • observation_field_id (int) –

  • value (Any) –

  • access_token (str) – access_token: the access token, as returned by get_access_token()

  • user_agent (Optional[str]) – a user-agent string that will be passed to iNaturalist.

Return type

Dict[str, Any]

Returns

iNaturalist’s response as a dict, for example: {‘id’: 31,

’observation_id’: 18166477, ‘observation_field_id’: 31, ‘value’: ‘fouraging’, ‘created_at’: ‘2012-09-29T11:05:44.935+02:00’, ‘updated_at’: ‘2018-11-13T10:49:47.985+01:00’, ‘user_id’: 1, ‘updater_id’: 1263313, ‘uuid’: ‘b404b654-1bf0-4299-9288-52eeda7ac0db’, ‘created_at_utc’: ‘2012-09-29T09:05:44.935Z’, ‘updated_at_utc’: ‘2018-11-13T09:49:47.985Z’}

Will fail if this observation_field is already set for this observation.

pyinaturalist.rest_api.update_observation(observation_id, params, access_token, user_agent=None)[source]

Update a single observation. See https://www.inaturalist.org/pages/api+reference#put-observations-id

Parameters
  • observation_id (int) – the ID of the observation to update

  • params (Dict[str, Any]) – to be passed to iNaturalist API

  • access_token (str) – the access token, as returned by get_access_token()

  • user_agent (Optional[str]) – a user-agent string that will be passed to iNaturalist.

Return type

List[Dict[str, Any]]

Returns

iNaturalist’s JSON response, as a Python object

Raise

requests.HTTPError, if the call is not successful. iNaturalist returns an error 410 if the observation doesn’t exists or belongs to another user (as of November 2018).

Node-based API

pyinaturalist.node_api.get_all_observations(params, user_agent=None)[source]

Like get_observations() but handles pagination so you get all the results in one shot.

Some params will be overwritten: order_by, order, per_page, id_above (do NOT specify page when using this).

Returns a list of dicts (one entry per observation)

Return type

List[Dict[str, Any]]

pyinaturalist.node_api.get_observation(observation_id, user_agent=None)[source]

Get details about an observation.

Parameters
  • observation_id (int) –

  • user_agent (Optional[str]) – a user-agent string that will be passed to iNaturalist.

Return type

Dict[str, Any]

Returns

a dict with details on the observation

Raises

ObservationNotFound

pyinaturalist.node_api.get_observations(params, user_agent=None)[source]

Search observations, see: http://api.inaturalist.org/v1/docs/#!/Observations/get_observations.

Returns the parsed JSON returned by iNaturalist (observations in r[‘results’], a list of dicts)

Return type

Dict[str, Any]

pyinaturalist.node_api.get_rank_range(min_rank=None, max_rank=None)[source]

Translate min and/or max rank into a list of ranks

Return type

List[str]

pyinaturalist.node_api.get_taxa(user_agent=None, min_rank=None, max_rank=None, **params)[source]

Given zero to many of following parameters, returns taxa matching the search criteria. See https://api.inaturalist.org/v1/docs/#!/Taxa/get_taxa

Parameters
  • q – Name must begin with this value

  • is_active – Taxon is active

  • taxon_id – Only show taxa with this ID, or its descendants

  • parent_id – Taxon’s parent must have this ID

  • rank – Taxon must have this exact rank

  • min_rank (Optional[str]) – Taxon must have this rank or higher; overrides rank

  • max_rank (Optional[str]) – Taxon must have this rank or lower; overrides rank

  • rank_level – Taxon must have this rank level. Some example values are 70 (kingdom), 60 (phylum), 50 (class), 40 (order), 30 (family), 20 (genus), 10 (species), 5 (subspecies)

  • id_above – Must have an ID above this value

  • id_below – Must have an ID below this value

  • per_page – Number of results to return in a page. The maximum value is generally 200 unless otherwise noted

  • locale – Locale preference for taxon common names

  • preferred_place_id – Place preference for regional taxon common names

  • only_id – Return only the record IDs

  • all_names – Include all taxon names in the response

Return type

Dict[str, Any]

Returns

A list of dicts containing taxa results

pyinaturalist.node_api.get_taxa_autocomplete(user_agent=None, **params)[source]

Given a query string, returns taxa with names starting with the search term See: https://api.inaturalist.org/v1/docs/#!/Taxa/get_taxa_autocomplete

Parameters
  • q – Name must begin with this value

  • is_active – Taxon is active

  • taxon_id – Only show taxa with this ID, or its descendants

  • rank – Taxon must have this rank

  • rank_level – Taxon must have this rank level. Some example values are 70 (kingdom), 60 (phylum), 50 (class), 40 (order), 30 (family), 20 (genus), 10 (species), 5 (subspecies)

  • per_page – Number of results to return in a page. The maximum value is generally 200 unless otherwise noted

  • locale – Locale preference for taxon common names

  • preferred_place_id – Place preference for regional taxon common names

  • all_names – Include all taxon names in the response

Return type

Dict[str, Any]

Returns

A list of dicts containing taxa results

pyinaturalist.node_api.get_taxa_by_id(taxon_id, user_agent=None)[source]

Get one or more taxa by ID. See: https://api.inaturalist.org/v1/docs/#!/Taxa/get_taxa_id

Param

taxon_id: Get taxa with this ID. Multiple values are allowed.

Return type

Dict[str, Any]

Returns

A list of dicts containing taxa results

pyinaturalist.node_api.make_inaturalist_api_get_call(endpoint, params, user_agent=None, **kwargs)[source]

Make an API call to iNaturalist.

endpoint is a string such as ‘observations’ method: ‘GET’, ‘HEAD’, ‘POST’, ‘PUT’, ‘PATCH’, ‘DELETE’ kwargs are passed to requests.request Returns a requests.Response object

Return type

Response

Exceptions

exception pyinaturalist.exceptions.AuthenticationError[source]

Bases: Exception

exception pyinaturalist.exceptions.ObservationNotFound[source]

Bases: Exception