{
  "num_results": 46,
  "objects": [
    {
      "association_proxies": [
        {
          "model": "tag",
          "name": "tags",
          "target_collection": "annotation_tags"
        }
      ],
      "collection": "annotation",
      "columns": [
        {
          "default": null,
          "doc": "Primary key `id`",
          "foreign_key": null,
          "name": "id",
          "nullable": false,
          "primary_key": true,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": "{}",
          "doc": "Text field containing JSON properties for this resource",
          "foreign_key": null,
          "name": "data",
          "nullable": true,
          "primary_key": false,
          "type": "JSON()",
          "unique": null
        },
        {
          "default": null,
          "doc": "Foreign key `id` for related [label](#label) (or class label)",
          "foreign_key": "label.id",
          "name": "label_id",
          "nullable": true,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": "1.0",
          "doc": "(Optional) likelihood/probability of the label assignment",
          "foreign_key": null,
          "name": "likelihood",
          "nullable": true,
          "primary_key": false,
          "type": "Float()",
          "unique": null
        },
        {
          "default": "False",
          "doc": "Whether or not this annotation requires review",
          "foreign_key": null,
          "name": "needs_review",
          "nullable": true,
          "primary_key": false,
          "type": "Boolean()",
          "unique": null
        },
        {
          "default": "function",
          "doc": "Creation time (UTC)",
          "foreign_key": null,
          "name": "created_at",
          "nullable": true,
          "primary_key": false,
          "type": "DateTime()",
          "unique": null
        },
        {
          "default": "function",
          "doc": "Updated time (UTC)",
          "foreign_key": null,
          "name": "updated_at",
          "nullable": true,
          "primary_key": false,
          "type": "TIMESTAMP()",
          "unique": null
        },
        {
          "default": null,
          "doc": "Foriegn key `id` for owner [user](#user) object",
          "foreign_key": "users.id",
          "name": "user_id",
          "nullable": false,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": "Foriegn key `id` for [point](#point) object",
          "foreign_key": "point.id",
          "name": "point_id",
          "nullable": false,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": "Foriegn key `id` for [annotation_set](#annotation_set) object",
          "foreign_key": "annotation_set.id",
          "name": "annotation_set_id",
          "nullable": false,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": "User comment",
          "foreign_key": null,
          "name": "comment",
          "nullable": true,
          "primary_key": false,
          "type": "Text()",
          "unique": null
        },
        {
          "default": null,
          "doc": "`id` of parent [annotation](#annotation) for group of linked observations",
          "foreign_key": "annotation.id",
          "name": "parent_id",
          "nullable": true,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        }
      ],
      "description": "\n    Annotation resource. Links [label](#label) objects to [point](#point) objects.\n    Also stores comments, [tag](#tag) associations, review flags, probability estimates, linked observations, etc...\n    ",
      "endpoints": [
        {
          "description": "Create new [annotation](#annotation) object. Expects JSON. Fields shown in `MODEL COLUMNS` below. ",
          "endpoint": "/api/annotation",
          "method": "POST",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Enforce implied permissions from parent [annotation_set](#annotation_set)",
              "name": "post_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get list of [annotation](#annotation) objects matching API query. See [Making API search queries](#api_query) for instructions on making search queries",
          "endpoint": "/api/annotation",
          "fields": [
            "id",
            "created_at",
            "updated_at",
            "annotation_set_id",
            "data",
            "label",
            "label.id",
            "label.name",
            "label.uuid",
            "label.parent_id",
            "label.label_scheme_id",
            "point",
            "point.media_id",
            "point.x",
            "point.y",
            "user",
            "user.id",
            "user.username",
            "point.t",
            "point.data",
            "point.annotation_set_id",
            "likelihood",
            "needs_review",
            "point.id",
            "tags",
            "tags.id",
            "tags.name",
            "comment",
            "timestamp",
            "parent_id",
            "color",
            "suggested_tags",
            "object_id",
            "label.lineage_names"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "\n        Filter results based on permissions from parent [annotation_set](#annotation_set)\n        ",
              "name": "get_many_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get single [annotation](#annotation) object with pk field matching param `id`",
          "endpoint": "/api/annotation/<id>",
          "fields": [
            "id",
            "created_at",
            "updated_at",
            "annotation_set_id",
            "data",
            "label",
            "label.id",
            "label.name",
            "label.uuid",
            "label.parent_id",
            "label.label_scheme_id",
            "point",
            "point.media_id",
            "point.x",
            "point.y",
            "user",
            "user.id",
            "user.username",
            "point.t",
            "point.data",
            "point.annotation_set_id",
            "likelihood",
            "needs_review",
            "point.id",
            "tags",
            "tags.id",
            "tags.name",
            "comment",
            "timestamp",
            "parent_id",
            "color",
            "suggested_tags",
            "object_id",
            "label.lineage_names",
            "label_id",
            "point.updated_at",
            "observation_count",
            "linked_observations",
            "media",
            "version_count"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Enforce implied permissions from parent [annotation_set](#annotation_set)",
              "name": "get_single_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Delete single [annotation](#annotation) object with pk field matching param `id`",
          "endpoint": "/api/annotation/<id>",
          "method": "DELETE",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Enforce implied permissions from parent [annotation_set](#annotation_set)",
              "name": "delete_auth_preprocessor"
            }
          ]
        },
        {
          "description": "\n        Batch update [annotation](#annotation) objects. Set `q` in querystring to filter selected [annotations](#annotation) as\n        per [Making API search queries](#api_query). Returned results are pre-filtered for only the annotations that come from\n        [annotation_sets](#annotation_set) where `current_user_can_edit` is set to `true`. As a safety measure, there\n        is a limit of `200` annotations that can be updated in a single request.\n\n        **CAUTION**: this endpoint can batch update many annotations in a single request! If used incorrectly, you can\n        loose your annotations and any annotations that have been shared with you for which you have been granted edit\n        access. Please use with caution.\n        **TIP**: Test your search query (`q`) on a `GET` request first to see what is returned before updating.\n\n        PATCH request data must be JSON with the following fields:\n        ```{ \"label_id\": ..., \"tags\": [...], \"comment\": \"...\" }```\n        Where `label_id` is the `id` of the [label](#label) object that you would like to assign to the list of matched\n        [annotations](#annotation). Setting `label_id` to `false` will reset the label and any assigned tags.\n        `tags` is a list of `[tag.id](#tag)'s` and `comment` is a string that can be assigned to each annotation.\n\n        ```\n        # Example: batch change ALL annotations matching filter. Set label_id=7326 (\"Ecklonia radiata\") for all annotations in an annotation_set annotation_set_id=2171 annotated by user user_id=1 with a label matching label_id=7331 (\"Sargasm spp\")\n\n        # PATCH: (TIP first run as GET request to check filter before PATCHING)\n        /api/annotation?q={\"filters\": [{\"name\": \"annotation_set_id\", \"op\": \"eq\", \"val\": 2171}, {\"name\": \"label_id\", \"op\": \"eq\", \"val\": 7331}, {\"name\": \"user_id\", \"op\": \"eq\", \"val\": 1}]}\n\n        # JSON PATCH DATA:\n        { \"label_id\": 7326 }\n        ```\n        ",
          "endpoint": "/api/annotation",
          "method": "PATCH"
        },
        {
          "description": null,
          "endpoint": "/api/annotation/<int:id>",
          "method": "PATCH"
        },
        {
          "description": null,
          "endpoint": "/api/annotation/<int:annotation_id>/tag/<int:tag_id>",
          "method": "DELETE"
        },
        {
          "description": "Updates `parent_id` of annotation to group observations of the same object. If `link_id` points to a child annotation, the observation\n        will be linked to its `parent`.\n        An observation group is used to link observations of the same object that has been annotated multiple times.",
          "endpoint": "/api/annotation/<int:id>/link/<int:link_id>",
          "method": "PATCH"
        },
        {
          "description": "View all previous versions of this annotation, i.e.: a change log.",
          "endpoint": "/api/annotation/<int:id>/versions",
          "method": "GET"
        },
        {
          "description": "Unlink this annotation from the observation group. If it is a group parent, the first child will be set as the\n        new parent.\n        An observation group is used to link observations of the same object that has been annotated multiple times.",
          "endpoint": "/api/annotation/<int:id>/link",
          "method": "DELETE"
        },
        {
          "description": "Set this annotation as the parent of the observation group.\n        An observation group is used to link observations of the same object that has been annotated multiple times.",
          "endpoint": "/api/annotation/<int:id>/link",
          "method": "PATCH"
        },
        {
          "description": "\n        General [annotation](#annotation) export endpoint. This can export annotations across multiple\n        [annotation_sets](#annotation_set). However, this endpoint is limited to a maximum of 200,000 annotations\n        in any single query. You can export more in separate queries using a combination of `limit` and `offset`\n        parameters. To export a single `annotation_set` without limits, see the `export` endpoint in the\n        [annotation_set](annotation_set) resource.\n\n        \n        Export [annotations](#annotation) matching query define in `q`.\n        Search queries are executed on the [annotation](#annotation) model. This endpoint also supports translating\n        to a target `label_scheme` (when possible)\n\n        \n        Querystring parameters are:\n\n        ```?q={...}&f={...}&disposition=...&template=...&include_columns=[...]```\n\n        Where `q` is a JSON search query (see [Making API search queries](#api_query)) on the collection model,\n        where `f` is a JSON dictionary containing a sequence of operations for transforming the data\n        (see [Data transformation API](#api_data_transform) for more info),\n        `disposition` defines the download type which can be `attachment` (default, triggers a download) or `inline` (displays in\n        the browser),\n        `template` is optional depending on the output of the steps in `f` and can be used to define the export format,\n        `include_columns` is a JSON list of column fields for the exported model.\n        Nested fields for related models delimited with a `.`\n        If `include_columns` is omitted, all allowed columns will be returned (or the exporter's `default_columns`, if\n        it defines them).\n\n        Metadata for the dataset is also returned in the response. Depending on the output\n        format, this could be as part of the response body in a `metadata` field (e.g., Json) or in the response headers with the key\n        `X-Content-Metadata` (e.g., CSV or HTML).\n    \n\n        Allowed fields include:\n\n        `id`, `tag_names`, `comment`, `label.id`, `label.name`, `label.lineage_names`, `label.uuid`, `label.color`,\n        `supplementary_label`, `updated_at`, `object_id`, `parent_id`, `needs_review`, `likelihood`,`timestamp`,\n        `point.is_targeted`,`point.id`, `point.x`, `point.y`, `point.t`, `point.data`, `point.media.id`, `point.media.key`,\n        `point.polygon`, `annotation_set.id`, `annotation_set.name`, `media_collection.id`, `media_collection.name`,\n        `point.media.path_best`, `point.media.timestamp_start`, `point.media.timestamp_start_local`,\n        `point.media.path_best_thm`, `point.media.data`, `point.pose.timestamp`, `point.pose.timestamp_local`,\n        `point.pose.lat`, `point.pose.lon`, `point.pose.alt`, `point.pose.dep`, `point.pose.data`, `point.pose.id`,\n        `point.media.deployment.campaign.id`, `point.media.deployment.campaign.key`, `point.media.deployment.campaign.name`,\n        `point.media.deployment.platform.id`, `point.media.deployment.platform.key`, `point.media.deployment.platform.name`,\n        `user.username`,`user.full_name`, `user.affiliations_names`,\n        `point.media.deployment.key`, `point.media.deployment.id`, `point.media.deployment.name`,\n        `point.bbox`, `point.has_xy`, `point.has_polygon`, `point.pixels`,\n        `point.media.dims`, `point.media.camera_installation_id`, `point.media.camera_installation.name`,\n        `point.media.camera.key`, `point.media.camera.name`, `point.media.media_type.name`\n\n        `point.pixels` (pixel coordinates) and `point.media.dims` (resolved pixel dimensions: the media item's own\n        `width` / `height`, or the default of its [camera_installation](#camera_installation)) are `null` when the\n        media dimensions are unknown. The templates `models/annotation/export_coco.json` (one image per media item)\n        and `models/annotation/export_coco_vid.json` (one image per video frame) export\n        [COCO](https://cocodataset.org/#format-data) JSON, with COCO-VID tracking fields for linked observations; see\n        the templates for the `include_columns` they use.\n\n        See [annotation](#annotation) model columns, relations and attributes for more information on each of the included fields.\n\n        **TRANSLATING TO OTHER LABEL_SCHEMES**\n\n        \n        The `translate` querystring parameter translates [labels](#label) to a target [label_scheme](#label_scheme).\n        It is a JSON object:\n\n        ```\n        &translate={\"target_label_scheme_id\": ..., \"vocab_registry_keys\": [...], \"match\": ..., \"mapping_override\": {...}}\n        ```\n        - `target_label_scheme_id` [required]: the `id` of the target [label_scheme](#label_scheme).\n        - `vocab_registry_keys` [optional]: the vocab registries used for semantic matching, in priority order\n          (default: `[\"worms\", \"caab\", \"catami\"]`).\n        - `match` [optional]: how to choose between several target labels that share vocab elements with a label.\n          `\"consensus\"` (default) picks the target label sharing vocab elements from the most registries, then the\n          most vocab elements, then the best ranked registry. `\"priority\"` picks a match from the first registry in\n          `vocab_registry_keys` order that has one.\n        - `mapping_override` [optional]: `{source label.id: target label.id}` overrides the translation of a label,\n          and of its descendants that have no closer match of their own.\n\n        Each label is matched by its `mapping_override`, then by `tree_traversal` (the label is in the target scheme or\n        a scheme it extends), then by `semantic` translation (shared vocab elements). If a label has no match, its\n        parent is tried, and so on up the tree. A match on the label itself always takes precedence over a match on an\n        ancestor. When several target labels match equally well, the most general one (fewest ancestors) is chosen.\n\n        The `translation_info` output describes the match as `<method>.<level>[.<vocab elements>]`:\n        - `method` is `mapping_override`, `tree_traversal` or `semantic`;\n        - `level` is `direct` (matched on the label itself) or `relative-<id>` (matched on the ancestor label with\n          that `id`);\n        - for `semantic` matches, the matched vocab elements are listed as `<registry>-<key>`, delimited by `+`.\n\n        For example: `semantic.direct.worms-217362+caab-37320000`, `semantic.relative-123.worms-217362`,\n        `tree_traversal.direct` or `mapping_override.relative-123`.\n        \n        To include the translation in the output, add the translation columns below to `include_columns`.\n\n        Additional allowed columns include:\n\n        `label.translated.id`, `label.translated.name`, `label.translated.lineage_names`,\n        `label.translated.uuid`, `label.translated.translation_info`,\n\n        These columns are ignored if no `translate` query parameter is supplied.\n        \n\n        **EXAMPLES**\n\n        ```\n        # TODO\n        ```\n        ",
          "endpoint": "/api/annotation/export",
          "method": "GET"
        },
        {
          "description": "\n        Get a tally of [annotations](#annotation).\n\n        \n        The tally of [annotations](#annotation) can be grouped by different properties. `group_by` can be one of\n        [`month`,'year_collected', 'month_collected', `user`, `platform`, `campaign`, `deployment`, `camera`, `label`,\n        `annotation_set`, `affiliation`^, `usergroup`^]. Set `q` in querystring to filter\n        selected [annotations](#annotation) as per [Making API search queries](#api_query). Note, the same query in `q`\n        can be applied to all `group_by` types to filter the list of [annotations](#annotation) that are included in the\n        tally. Results are also paginated with a default of `500` and a maximum on `5000` returned per page. This can be\n        controlled by setting the `results_per_page` parameter in the query string.\n        Returned results are pre-filtered to return only the annotations that have been labeled (`label_id != null`).\n        Also accepts a query string parameter `template` which formats the data using a predefined template. Some example\n        templates include: `data.html` which returns an HTML table, `json.html` which returns HTML-formatted JSON, `data.csv`\n        which returns a CSV file for download. If left blank, raw JSON will be returned.\n\n        For `group_by=annotation_set`, results also include the related `media_collection_id`, `media_collection_name`,\n        owner (`user_id`, `user_first_name`, `user_last_name`), `label_scheme_id`, `label_scheme_name`, status flags\n        (`is_final`, `is_qaqc`, `is_real_science`, `is_full_bio_score`, `is_exemplar`), `is_public` and\n        `current_user_can_view`. All matching annotation sets are listed, including ones that the current user can not\n        view (to help discover datasets and contact their custodians).\n\n        ^ **NOTE**: the counts in the `affiliation` and `usergroup` tally should be interpreted with care.\n        If someone belongs to more than one group, then their annotations will contribute to both so they may be double\n        counted. The corollary of that is if someone has not linked themselves to an affiliation or group, then their\n        annotations will not be counted in the tally.\n\n        **TRANSLATING TO OTHER LABEL_SCHEMES**\n\n        When using `group_by=label`, labels can also be translated to another label scheme with the `translate`\n        parameter.\n        \n        The `translate` querystring parameter translates [labels](#label) to a target [label_scheme](#label_scheme).\n        It is a JSON object:\n\n        ```\n        &translate={\"target_label_scheme_id\": ..., \"vocab_registry_keys\": [...], \"match\": ..., \"mapping_override\": {...}}\n        ```\n        - `target_label_scheme_id` [required]: the `id` of the target [label_scheme](#label_scheme).\n        - `vocab_registry_keys` [optional]: the vocab registries used for semantic matching, in priority order\n          (default: `[\"worms\", \"caab\", \"catami\"]`).\n        - `match` [optional]: how to choose between several target labels that share vocab elements with a label.\n          `\"consensus\"` (default) picks the target label sharing vocab elements from the most registries, then the\n          most vocab elements, then the best ranked registry. `\"priority\"` picks a match from the first registry in\n          `vocab_registry_keys` order that has one.\n        - `mapping_override` [optional]: `{source label.id: target label.id}` overrides the translation of a label,\n          and of its descendants that have no closer match of their own.\n\n        Each label is matched by its `mapping_override`, then by `tree_traversal` (the label is in the target scheme or\n        a scheme it extends), then by `semantic` translation (shared vocab elements). If a label has no match, its\n        parent is tried, and so on up the tree. A match on the label itself always takes precedence over a match on an\n        ancestor. When several target labels match equally well, the most general one (fewest ancestors) is chosen.\n\n        The `translation_info` output describes the match as `<method>.<level>[.<vocab elements>]`:\n        - `method` is `mapping_override`, `tree_traversal` or `semantic`;\n        - `level` is `direct` (matched on the label itself) or `relative-<id>` (matched on the ancestor label with\n          that `id`);\n        - for `semantic` matches, the matched vocab elements are listed as `<registry>-<key>`, delimited by `+`.\n\n        For example: `semantic.direct.worms-217362+caab-37320000`, `semantic.relative-123.worms-217362`,\n        `tree_traversal.direct` or `mapping_override.relative-123`.\n        \n        When translating, the output contains the additional columns: `label_lineage_names`, `translated_id`,\n        `translated_lineage_names`, `translated_name`, `translated_label_scheme_name` and `translated_info`.\n        \n\n        **EXAMPLES**\n\n        ```\n        # Example: tally of annotations for top 500 most commonly used labels returned as an HTML table\n        /api/annotation/tally/label?template=data.html&results_per_page=500\n\n        # Example: tally of annotations for the top 1000 users returned as a CSV file\n        /api/annotation/tally/user?&results_per_page=1000&template=data.csv\n\n        # Example: tally of annotations for the top 20 affiliations returned as an HTML table\n        /api/annotation/tally/affiliation?&results_per_page=20&template=data.html\n\n        # Example: tally of annotations by the top 200 usergroups returned as an HTML table\n        /api/annotation/tally/usergroup?&template=data.html&results_per_page=200\n\n        # Example: tally of annotations by month between 2020-01-01 and 2021-01-01 returned as an HTML table\n        /api/annotation/tally/month?q={\"filters\": [{\"name\":\"updated_at\",\"op\":\"gt\",\"val\":\"2020-01-01\"}, {\"name\":\"updated_at\",\"op\":\"lt\",\"val\":\"2021-01-01\"}] }&template=data.html\n\n        # Example: tally of annotations by platform returned as raw JSON\n        /api/annotation/tally/platform\n\n        # Example: tally of annotations by campaign returned as a HTML-formatted JSON\n        /api/annotation/tally/campaign?&template=json.html\n\n        # Example: tally of annotations for top 2000 deployments returned as an HTML table\n        /api/annotation/tally/deployment?&template=data.html&results_per_page=2000\n\n        # Example: tally annotations by deployment filtered by annotation_set.usergroup with ID=63 returned as an HTML table\n        /api/annotation/tally/deployment?&results_per_page=2000&template=data.html&q={\"filters\": [{\"name\":\"annotation_set\",\"op\":\"has\",\"val\": {\"name\":\"usergroups\",\"op\":\"any\",\"val\": {\"name\":\"id\",\"op\":\"eq\",\"val\":63}}}]}\n\n        # Example: tally of annotations for the top 20 users for platform(s) containing \"IMOS\" in their name that were labeled during the year 2020. Return the result as an HTML table using the template \"data.html\", GET:\n        /api/annotation/tally/user?q={\"filters\": [{\"name\":\"point\",\"op\":\"has\",\"val\": {\"name\":\"media\",\"op\":\"has\",\"val\": {\"name\":\"deployment\",\"op\":\"has\",\"val\": {\"name\":\"platform\",\"op\":\"has\",\"val\": {\"name\":\"name\",\"op\":\"ilike\",\"val\":\"%IMOS%\"}}}}}, {\"name\":\"created_at\",\"op\":\"gt\",\"val\":\"2020-01-01\"}, {\"name\":\"created_at\",\"op\":\"lt\",\"val\":\"2021-01-01\"}] }&results_per_page=20&template=data.html\n\n        # Example: tally of annotations by top 100 labels for a give deployment (id=10306) returned as an HTML table\n        # Translated into the catami annotation scheme (id=2) using the \"caab\" and \"worms\" vocab_registries (only works with compatible schemas)\n        /api/annotation/tally/label?q={\"filters\":[{\"name\":\"point\",\"op\":\"has\",\"val\":{\"name\":\"media\",\"op\":\"has\",\"val\":{\"name\":\"deployment_id\",\"op\":\"eq\",\"val\":10306}}}]}&results_per_page=100&unannotated_point_count=294&translate={\"vocab_registry_keys\":[\"caab\",\"worms\"],\"target_label_scheme_id\":\"2\"}&template=data.html\n\n        # Example: tally annotations by label in a deployment matching the key \"r20200131_021337_NG02_middleton_22\", filtered for occurrences between 20-30m, showing only primary observation (no linked children, i.e. only count an observation group/object once)\n        /api/annotation/tally/label?q={\"filters\":[{\"name\":\"point\",\"op\":\"has\",\"val\":{\"name\":\"media\",\"op\":\"has\",\"val\":{\"name\":\"deployment\",\"op\":\"has\",\"val\":{\"name\":\"key\",\"op\":\"eq\",\"val\":\"r20200131_021337_NG02_middleton_22\"}}}},{\"name\":\"point\",\"op\":\"has\",\"val\": {\"name\":\"media\",\"op\":\"has\",\"val\": {\"name\":\"poses\",\"op\":\"any\",\"val\": {\"name\":\"dep\",\"op\":\"gt\",\"val\":20}}}},{\"name\":\"point\",\"op\":\"has\",\"val\": {\"name\":\"media\",\"op\":\"has\",\"val\": {\"name\":\"poses\",\"op\":\"any\",\"val\": {\"name\":\"dep\",\"op\":\"lt\",\"val\":30}}}},{\"name\":\"is_child\",\"op\":\"eq\",\"val\":false}]}\n        ```\n        ",
          "endpoint": "/api/annotation/tally/<group_by>",
          "method": "GET"
        }
      ],
      "hybrid_properties": [
        {
          "args": [],
          "doc": "\n        BOOLEAN, whether or not this annotation has a linked parent annotation\n        (queryable)\n        ",
          "name": "is_child",
          "type": "property"
        },
        {
          "args": [],
          "doc": "The in-situ timestamp for when the annotated object was captured/sampled in the media frame.\n        Returns `media.timestamp_start + point.t` if `point.t` is set, otherwise it just\n        returns `media.timestamp_start` ",
          "name": "timestamp",
          "type": "property"
        },
        {
          "args": [
            "ts"
          ],
          "doc": "Absolute difference in seconds of the in-situ timestamp and input `ts`, which is datetime string\n        eg: `\"2020-09-25T00:57:11.945009\"` (or in a format that is parsable by `dateutil.parser.parse`)",
          "name": "timestamp_proximity",
          "type": "method"
        },
        {
          "args": [
            "lat",
            "lon"
          ],
          "doc": "FLOAT, distance (in meters) of closest linked [pose](#pose) relative to `lat` and `lon` (which are both in decimal degrees)",
          "name": "distance",
          "type": "method"
        },
        {
          "args": [
            "x",
            "y"
          ],
          "doc": "FLOAT, euclidean distance to `x` and `y` (which are proportions of the image width and height)",
          "name": "xy_distance",
          "type": "method"
        },
        {
          "args": [
            "label_id",
            "include_synonyms",
            "include_descendants"
          ],
          "doc": "\n        BOOLEAN. True if this annotation's label matches the provided `label_id`,\n        or any synonymous labels linked via `vocab_elements`. If `include_descendants`\n        is True, all descendant labels (children at any depth) of the matching set\n        are also considered matches.\n\n        Usage via API (examples):\n\n        - Match direct label only:\n          `{\"name\":{\"method\":\"matches_label\",\"kwargs\":{\"label_id\":123,\"include_synonyms\":false}},\"op\":\"eq\",\"val\":true}`\n        - Match label and synonyms:\n          `{\"name\":{\"method\":\"matches_label\",\"kwargs\":{\"label_id\":123,\"include_synonyms\":true}},\"op\":\"==\",\"val\":true}`\n        - Match label, synonyms and all descendants:\n          `{\"name\":{\"method\":\"matches_label\",\"kwargs\":{\"label_id\":123,\"include_synonyms\":true,\"include_descendants\":true}},\"op\":\"eq\",\"val\":true}`\n        ",
          "name": "matches_label",
          "type": "method"
        }
      ],
      "methods": [
        {
          "doc": "Implied color code for this annotation based on [label](#label) assignment",
          "name": "color",
          "type": "method"
        },
        {
          "doc": "BOOLEAN, whether or not the current user has edit rights for this annotation as implied by the permissions of the parent [annotation_set](#annotation_set)",
          "name": "current_user_can_edit",
          "type": "method"
        },
        {
          "doc": "\n        INT, denoting the number of linked observations of this object\n        ",
          "name": "observation_count",
          "type": "method"
        },
        {
          "doc": "Properties for related [pose](#pose) item excluding [posedata](#posedata) fields",
          "name": "pose",
          "type": "method"
        },
        {
          "doc": "Properties for related [pose](#pose) item including any linked [posedata](#posedata) fields",
          "name": "pose_data",
          "type": "method"
        },
        {
          "doc": "List of suggested [tag](#tag) implied from [label](#label) definition",
          "name": "suggested_tags",
          "type": "method"
        },
        {
          "doc": "INT, denoting the number of changes in the version history of this object",
          "name": "version_count",
          "type": "method"
        },
        {
          "doc": "List of [annotation](#annotation) objects (as dicts) linked with the same `object_id`",
          "name": "linked_observations",
          "type": "property"
        },
        {
          "doc": "[media](#media) object information for this [annotation](#annotation) via `point.media` link",
          "name": "media",
          "type": "property"
        },
        {
          "doc": "\n        ID of observation group: ID of primary observation (parent annotation) if linked, otherwise own ID.\n        ",
          "name": "object_id",
          "type": "property"
        },
        {
          "doc": "Selected fiedls of supplementary labels for relates [point](#point). Returns `id`, `likelihood`, `name`,\n        `lineage_names`, `username`. Can optionally filter through URL param: `supplementary_annotation_set_id`, which\n        will filter for specific supplementary annotation_set. If not supplied will return all.",
          "name": "supplementary_label",
          "type": "property"
        },
        {
          "doc": "Comma-delimited names of applied tags. Can also be used to set tags using comma-delimited tags when creating annotaions",
          "name": "tag_names",
          "type": "property"
        },
        {
          "doc": "\n        Returns `id` of `label.translated` for [label](#label) if defined and if a match is found, otherwise  `None`.\n        ",
          "name": "translated_label_id",
          "type": "property"
        }
      ],
      "relations": [
        {
          "direction": "MANYTOONE",
          "doc": "Related [label](#label) object",
          "key": "label",
          "model": "label"
        },
        {
          "direction": "MANYTOONE",
          "doc": "Related owner [user](#user) object",
          "key": "user",
          "model": "users"
        },
        {
          "direction": "MANYTOONE",
          "doc": "Related [point](#point) object",
          "key": "point",
          "model": "point"
        },
        {
          "direction": "MANYTOONE",
          "doc": "Related [annotation_set](#annotation_set) object",
          "key": "annotation_set",
          "model": "annotation_set"
        },
        {
          "direction": "MANYTOONE",
          "doc": "Parent annotation in a linked set of observations",
          "key": "parent",
          "model": "annotation"
        },
        {
          "direction": "ONETOMANY",
          "doc": "Collection of linked child observations",
          "key": "children",
          "model": "annotation"
        },
        {
          "direction": "ONETOMANY",
          "doc": "Collection of [annotation_tags](#annotation_tags) associations",
          "key": "annotation_tags",
          "model": "annotation_tags"
        },
        {
          "direction": "ONETOMANY",
          "doc": null,
          "key": "versions",
          "model": "annotation_version"
        }
      ]
    },
    {
      "association_proxies": [],
      "collection": "annotation_set",
      "columns": [
        {
          "default": null,
          "doc": "Primary key `id`",
          "foreign_key": null,
          "name": "id",
          "nullable": false,
          "primary_key": true,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": "{}",
          "doc": "Text field containing JSON properties for this resource",
          "foreign_key": null,
          "name": "data",
          "nullable": true,
          "primary_key": false,
          "type": "JSON()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "name",
          "nullable": false,
          "primary_key": false,
          "type": "String(length=80)",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "description",
          "nullable": true,
          "primary_key": false,
          "type": "Text()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": "media_collection.id",
          "name": "media_collection_id",
          "nullable": false,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": "label_scheme.id",
          "name": "label_scheme_id",
          "nullable": false,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": "Foreign key reference for ID of related owner [users](#users) model",
          "foreign_key": "users.id",
          "name": "user_id",
          "nullable": false,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": "function",
          "doc": null,
          "foreign_key": null,
          "name": "created_at",
          "nullable": false,
          "primary_key": false,
          "type": "DateTime()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": "annotation_set.id",
          "name": "parent_id",
          "nullable": true,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": "False",
          "doc": null,
          "foreign_key": null,
          "name": "is_exemplar",
          "nullable": true,
          "primary_key": false,
          "type": "Boolean()",
          "unique": null
        },
        {
          "default": null,
          "doc": "whether or not the intent was full biodiversity scoring, or just targeted scoring",
          "foreign_key": null,
          "name": "is_full_bio_score",
          "nullable": true,
          "primary_key": false,
          "type": "Boolean()",
          "unique": null
        },
        {
          "default": null,
          "doc": "whether or not this is for science, or was for education / training / testing",
          "foreign_key": null,
          "name": "is_real_science",
          "nullable": true,
          "primary_key": false,
          "type": "Boolean()",
          "unique": null
        },
        {
          "default": "False",
          "doc": "whether or not the annotation set has been QA/QC'd",
          "foreign_key": null,
          "name": "is_qaqc",
          "nullable": true,
          "primary_key": false,
          "type": "Boolean()",
          "unique": null
        },
        {
          "default": "False",
          "doc": "whether or not the annotator has completed annotating",
          "foreign_key": null,
          "name": "is_final",
          "nullable": true,
          "primary_key": false,
          "type": "Boolean()",
          "unique": null
        },
        {
          "default": "base",
          "doc": null,
          "foreign_key": null,
          "name": "type",
          "nullable": true,
          "primary_key": false,
          "type": "String(length=80)",
          "unique": null
        }
      ],
      "description": "\n    Annotation Set resource: defines how the [media](#media) objects contained in a [media_collection](#media_collection) should be annotated /\n    analysed. Each [media_collection](#media_collection) can have multiple [annotation_sets](#annotation_set) attached to it.\n    ",
      "endpoints": [
        {
          "description": "Create new [annotation_set](#annotation_set) object. Expects JSON. Fields shown in `MODEL COLUMNS` below. ",
          "endpoint": "/api/annotation_set",
          "method": "POST",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to LOGGED IN users only",
              "name": "post_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Update single [annotation_set](#annotation_set) object with pk field matching param `id`. Expects JSON. Fields shown in `MODEL COLUMNS` below.",
          "endpoint": "/api/annotation_set/<id>",
          "method": "PATCH",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": null,
              "name": "patch_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get list of [annotation_set](#annotation_set) objects matching API query. See [Making API search queries](#api_query) for instructions on making search queries",
          "endpoint": "/api/annotation_set",
          "fields": [
            "id",
            "name",
            "parent_id",
            "description",
            "user",
            "user.id",
            "user.username",
            "user.first_name",
            "user.last_name",
            "created_at",
            "children",
            "media_collection",
            "media_collection.id",
            "media_collection.name",
            "media_collection.current_user_can_view",
            "label_scheme",
            "label_scheme.id",
            "label_scheme.name",
            "data",
            "current_user_can_view",
            "current_user_is_owner",
            "current_user_is_member",
            "current_user_can_edit",
            "is_public",
            "is_exemplar",
            "is_full_bio_score",
            "is_real_science",
            "is_qaqc",
            "is_final",
            "annotation_count",
            "usergroup_count"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_many_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get single [annotation_set](#annotation_set) object with pk field matching param `id`",
          "endpoint": "/api/annotation_set/<id>",
          "fields": [
            "id",
            "name",
            "parent_id",
            "description",
            "user",
            "user.id",
            "user.username",
            "user.first_name",
            "user.last_name",
            "created_at",
            "children",
            "media_collection",
            "media_collection.id",
            "media_collection.name",
            "media_collection.current_user_can_view",
            "label_scheme",
            "label_scheme.id",
            "label_scheme.name",
            "data",
            "current_user_can_view",
            "current_user_is_owner",
            "current_user_is_member",
            "current_user_can_edit",
            "is_public",
            "is_exemplar",
            "is_full_bio_score",
            "is_real_science",
            "is_qaqc",
            "is_final",
            "annotation_count",
            "usergroup_count",
            "files",
            "files.id",
            "files.name",
            "files.file_url",
            "files.created_at",
            "files.description",
            "media_count",
            "point_count",
            "unannotated_point_count"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Assert object view permission from shared `usergroups`. Checks current_user has view permission. Also allows\n        owner of `parent` to view `children` or supplementary annotation_sets",
              "name": "get_single_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Delete single [annotation_set](#annotation_set) object with pk field matching param `id`",
          "endpoint": "/api/annotation_set/<id>",
          "method": "DELETE",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Assert object delete permission from shared `usergroups`. Checks current user is owner and object is not\n        shared in a `usergroup`. Also allows owner of `parent` to delete the `child`",
              "name": "delete_auth_preprocessor"
            }
          ]
        },
        {
          "description": "\n        Add object with id `instance_id` to group with id `group_id`\n        ",
          "endpoint": "/api/annotation_set/<int:instance_id>/group/<int:group_id>",
          "method": "POST"
        },
        {
          "description": "Remove resource with id `instance_id` from group with id `group_id`",
          "endpoint": "/api/annotation_set/<int:instance_id>/group/<int:group_id>",
          "method": "DELETE"
        },
        {
          "description": "\n        Export [annotations](#annotation) from [annotation_set](#annotation_set) matching `id`.\n        \n        Export [annotations](#annotation) matching query define in `q`.\n        Search queries are executed on the [annotation](#annotation) model. This endpoint also supports translating\n        to a target `label_scheme` (when possible)\n\n        \n        Querystring parameters are:\n\n        ```?q={...}&f={...}&disposition=...&template=...&include_columns=[...]```\n\n        Where `q` is a JSON search query (see [Making API search queries](#api_query)) on the collection model,\n        where `f` is a JSON dictionary containing a sequence of operations for transforming the data\n        (see [Data transformation API](#api_data_transform) for more info),\n        `disposition` defines the download type which can be `attachment` (default, triggers a download) or `inline` (displays in\n        the browser),\n        `template` is optional depending on the output of the steps in `f` and can be used to define the export format,\n        `include_columns` is a JSON list of column fields for the exported model.\n        Nested fields for related models delimited with a `.`\n        If `include_columns` is omitted, all allowed columns will be returned (or the exporter's `default_columns`, if\n        it defines them).\n\n        Metadata for the dataset is also returned in the response. Depending on the output\n        format, this could be as part of the response body in a `metadata` field (e.g., Json) or in the response headers with the key\n        `X-Content-Metadata` (e.g., CSV or HTML).\n    \n\n        Allowed fields include:\n\n        `id`, `tag_names`, `comment`, `label.id`, `label.name`, `label.lineage_names`, `label.uuid`, `label.color`,\n        `supplementary_label`, `updated_at`, `object_id`, `parent_id`, `needs_review`, `likelihood`,`timestamp`,\n        `point.is_targeted`,`point.id`, `point.x`, `point.y`, `point.t`, `point.data`, `point.media.id`, `point.media.key`,\n        `point.polygon`, `annotation_set.id`, `annotation_set.name`, `media_collection.id`, `media_collection.name`,\n        `point.media.path_best`, `point.media.timestamp_start`, `point.media.timestamp_start_local`,\n        `point.media.path_best_thm`, `point.media.data`, `point.pose.timestamp`, `point.pose.timestamp_local`,\n        `point.pose.lat`, `point.pose.lon`, `point.pose.alt`, `point.pose.dep`, `point.pose.data`, `point.pose.id`,\n        `point.media.deployment.campaign.id`, `point.media.deployment.campaign.key`, `point.media.deployment.campaign.name`,\n        `point.media.deployment.platform.id`, `point.media.deployment.platform.key`, `point.media.deployment.platform.name`,\n        `user.username`,`user.full_name`, `user.affiliations_names`,\n        `point.media.deployment.key`, `point.media.deployment.id`, `point.media.deployment.name`,\n        `point.bbox`, `point.has_xy`, `point.has_polygon`, `point.pixels`,\n        `point.media.dims`, `point.media.camera_installation_id`, `point.media.camera_installation.name`,\n        `point.media.camera.key`, `point.media.camera.name`, `point.media.media_type.name`\n\n        `point.pixels` (pixel coordinates) and `point.media.dims` (resolved pixel dimensions: the media item's own\n        `width` / `height`, or the default of its [camera_installation](#camera_installation)) are `null` when the\n        media dimensions are unknown. The templates `models/annotation/export_coco.json` (one image per media item)\n        and `models/annotation/export_coco_vid.json` (one image per video frame) export\n        [COCO](https://cocodataset.org/#format-data) JSON, with COCO-VID tracking fields for linked observations; see\n        the templates for the `include_columns` they use.\n\n        See [annotation](#annotation) model columns, relations and attributes for more information on each of the included fields.\n\n        **TRANSLATING TO OTHER LABEL_SCHEMES**\n\n        \n        The `translate` querystring parameter translates [labels](#label) to a target [label_scheme](#label_scheme).\n        It is a JSON object:\n\n        ```\n        &translate={\"target_label_scheme_id\": ..., \"vocab_registry_keys\": [...], \"match\": ..., \"mapping_override\": {...}}\n        ```\n        - `target_label_scheme_id` [required]: the `id` of the target [label_scheme](#label_scheme).\n        - `vocab_registry_keys` [optional]: the vocab registries used for semantic matching, in priority order\n          (default: `[\"worms\", \"caab\", \"catami\"]`).\n        - `match` [optional]: how to choose between several target labels that share vocab elements with a label.\n          `\"consensus\"` (default) picks the target label sharing vocab elements from the most registries, then the\n          most vocab elements, then the best ranked registry. `\"priority\"` picks a match from the first registry in\n          `vocab_registry_keys` order that has one.\n        - `mapping_override` [optional]: `{source label.id: target label.id}` overrides the translation of a label,\n          and of its descendants that have no closer match of their own.\n\n        Each label is matched by its `mapping_override`, then by `tree_traversal` (the label is in the target scheme or\n        a scheme it extends), then by `semantic` translation (shared vocab elements). If a label has no match, its\n        parent is tried, and so on up the tree. A match on the label itself always takes precedence over a match on an\n        ancestor. When several target labels match equally well, the most general one (fewest ancestors) is chosen.\n\n        The `translation_info` output describes the match as `<method>.<level>[.<vocab elements>]`:\n        - `method` is `mapping_override`, `tree_traversal` or `semantic`;\n        - `level` is `direct` (matched on the label itself) or `relative-<id>` (matched on the ancestor label with\n          that `id`);\n        - for `semantic` matches, the matched vocab elements are listed as `<registry>-<key>`, delimited by `+`.\n\n        For example: `semantic.direct.worms-217362+caab-37320000`, `semantic.relative-123.worms-217362`,\n        `tree_traversal.direct` or `mapping_override.relative-123`.\n        \n        To include the translation in the output, add the translation columns below to `include_columns`.\n\n        Additional allowed columns include:\n\n        `label.translated.id`, `label.translated.name`, `label.translated.lineage_names`,\n        `label.translated.uuid`, `label.translated.translation_info`,\n\n        These columns are ignored if no `translate` query parameter is supplied.\n        \n\n        **EXAMPLES**\n\n        ```\n        # Example1: get all columns as a downloaded CSV file, only point annotations - filter out whole frame labels\n        /api/annotation_set/2194/export?template=dataframe.csv&f={\"operations\":[{\"module\":\"pandas\", \"method\":\"json_normalize\"}]}&q={\"filters\":[{\"name\":\"point\", \"op\":\"has\", \"val\":{\"name\":\"has_xy\", \"op\":\"eq\",\"val\":true}}]}\n\n        # Example2: aggregate label counts per frame (percent cover, no point information) as a downloaded csv\n        /api/annotation_set/2171/export?template=dataframe.csv&include_columns=[\"label.name\", \"label.lineage_names\", \"point.media.key\", \"point.pose.timestamp\", \"point.pose.lat\", \"point.pose.lon\", \"point.pose.alt\", \"point.pose.dep\"]&f={\"operations\":[{\"module\":\"pandas\", \"method\":\"json_normalize\"},{\"method\":\"fillna\", \"kwargs\":{\"value\":\"-\"}},{\"module\":\"pandas\", \"method\":\"count_unstack\", \"kwargs\":{\"columns\":[\"label.id\", \"label.uuid\", \"label.name\", \"label.lineage_names\", \"comment\", \"tag_names\"]}}]}\n\n        # Example3: show selected columns as an HTML table in the browser, filter out unlabeled annotations\n        /api/annotation_set/2171/export?template=dataframe.html&disposition=inline&include_columns=[\"label.name\",\"label.lineage_names\", \"updated_at\", \"point.x\", \"point.y\", \"point.media.key\", \"point.pose.timestamp\", \"point.pose.lat\", \"point.pose.lon\", \"point.pose.alt\", \"point.pose.dep\", \"point.media.deployment.key\", \"point.media.deployment.campaign.key\"]&f={\"operations\":[{\"module\":\"pandas\", \"method\":\"json_normalize\"}]}&q={\"filters\":[{\"name\":\"label_id\", \"op\":\"is_not_null\"}]}\n\n        # Example4: show HTML table in browser with tally of label counts (can be refreshed for readable live summary)\n        /api/annotation_set/2171/export?template=dataframe.html&disposition=inline&include_columns=[\"label.uuid\",\"label.name\",\"label.lineage_names\",\"label.id\"]&f={\"operations\":[{\"module\":\"pandas\",\"method\":\"json_normalize\"},{\"module\":\"pandas\",\"method\":\"groupby_count\"}]}&q={\"filters\":[{\"name\":\"label_id\",\"op\":\"is_not_null\"}]}\n        ```\n\n        NB: the UI contains an \"ADVANCED\" option which can help build more complex export queries.\n        ",
          "endpoint": "/api/annotation_set/<int:id>/export",
          "method": "GET"
        },
        {
          "description": "\n        Validate supplementary `annotation_set` `label` suggestions. It accepts an optional query string parameter\n        `supplementary_annotation_set_id` which specifies the `id` of the supplementary annotation_set to filter.\n        If omitted, it will validate against all supplementary `annotation_sets`. It evaluates the maximal `likelihood`\n        supplementary `annotation` for which to conduct the validation. It outputs `classification_report` which includes\n        a variety of classification performance parameters and a `confusion_matrix` oriented with rows showing actual\n        labels and columns showing the maximal likelihood supplementary labels.\n\n        This endpoint accepts the `translate` parameter, which allows validation by cross mapping to different\n        vocabularies. This can be useful if there are differences in the taxonomic resolution.\n        \n        The `translate` querystring parameter translates [labels](#label) to a target [label_scheme](#label_scheme).\n        It is a JSON object:\n\n        ```\n        &translate={\"target_label_scheme_id\": ..., \"vocab_registry_keys\": [...], \"match\": ..., \"mapping_override\": {...}}\n        ```\n        - `target_label_scheme_id` [required]: the `id` of the target [label_scheme](#label_scheme).\n        - `vocab_registry_keys` [optional]: the vocab registries used for semantic matching, in priority order\n          (default: `[\"worms\", \"caab\", \"catami\"]`).\n        - `match` [optional]: how to choose between several target labels that share vocab elements with a label.\n          `\"consensus\"` (default) picks the target label sharing vocab elements from the most registries, then the\n          most vocab elements, then the best ranked registry. `\"priority\"` picks a match from the first registry in\n          `vocab_registry_keys` order that has one.\n        - `mapping_override` [optional]: `{source label.id: target label.id}` overrides the translation of a label,\n          and of its descendants that have no closer match of their own.\n\n        Each label is matched by its `mapping_override`, then by `tree_traversal` (the label is in the target scheme or\n        a scheme it extends), then by `semantic` translation (shared vocab elements). If a label has no match, its\n        parent is tried, and so on up the tree. A match on the label itself always takes precedence over a match on an\n        ancestor. When several target labels match equally well, the most general one (fewest ancestors) is chosen.\n\n        The `translation_info` output describes the match as `<method>.<level>[.<vocab elements>]`:\n        - `method` is `mapping_override`, `tree_traversal` or `semantic`;\n        - `level` is `direct` (matched on the label itself) or `relative-<id>` (matched on the ancestor label with\n          that `id`);\n        - for `semantic` matches, the matched vocab elements are listed as `<registry>-<key>`, delimited by `+`.\n\n        For example: `semantic.direct.worms-217362+caab-37320000`, `semantic.relative-123.worms-217362`,\n        `tree_traversal.direct` or `mapping_override.relative-123`.\n                ",
          "endpoint": "/api/annotation_set/<int:id>/annotations/validate",
          "method": "GET"
        },
        {
          "description": null,
          "endpoint": "/api/annotation_set/<int:id>/media",
          "method": "GET"
        },
        {
          "description": "\n        Returns list of [annotation](#annotation) objects contained in the `annotation_set` with an ID matching `id`.\n        The results can be filtered and searched. See [Making API search queries](#api_query) for instructions on making search queries.\n        In addition it accepts `include_columns` and `include_methods` query parameters which override returned\n        fields of [annotation](#annotation) model.\n        ",
          "endpoint": "/api/annotation_set/<int:id>/annotations",
          "method": "GET"
        },
        {
          "description": "\n        List the [group_dashboards](#group_dashboard) available for this [annotation_set](#annotation_set): those offered\n        for `annotation_set` datasets by the [groups](#groups) it is shared in. Each result includes `authorized`, with the launch `url`\n        for the current user (a signed token in place of `{token}` in the dashboard's `url_base`, or `null` if they\n        can't launch it) and the result of each of the dashboard's `permission_tests`. See\n        [group_dashboard](#group_dashboard) for the token and how a dashboard decodes it.\n\n        **EXAMPLES**\n\n        ```\n        # Dashboards for annotation_set 1234, as JSON\n        /api/annotation_set/1234/dashboards\n        ```\n        ",
          "endpoint": "/api/annotation_set/<int:id>/dashboards",
          "method": "GET"
        },
        {
          "description": "\n        Public summary of an [annotation_set](#annotation_set) to help with dataset discovery. Returns non-sensitive\n        metadata (name, description, custodian, media_collection and label_scheme names, status flags and counts)\n        whether or not the current user has permission to view the annotation set, as well as `current_user_can_view`\n        and `is_public`. It does not return any annotations, media or files. The groups that the annotation set is\n        shared in can be listed with the [groups](#groups) resource, eg:\n        `/api/groups?q={\"filters\":[{\"name\":\"shared_annotation_sets\",\"op\":\"any\",\"val\":{\"name\":\"id\",\"op\":\"eq\",\"val\":ID}}]}`\n\n        **EXAMPLES**\n\n        ```\n        # Summary of annotation set with id=5806 as JSON\n        /api/annotation_set/5806/summary\n        ```\n        ",
          "endpoint": "/api/annotation_set/<int:id>/summary",
          "method": "GET"
        },
        {
          "description": "\n        Get a tally of [annotations](#annotation) for an `annotation_set` matching `id`.\n\n        \n        The tally of [annotations](#annotation) can be grouped by different properties. `group_by` can be one of\n        [`month`,'year_collected', 'month_collected', `user`, `platform`, `campaign`, `deployment`, `camera`, `label`,\n        `annotation_set`, `affiliation`^, `usergroup`^]. Set `q` in querystring to filter\n        selected [annotations](#annotation) as per [Making API search queries](#api_query). Note, the same query in `q`\n        can be applied to all `group_by` types to filter the list of [annotations](#annotation) that are included in the\n        tally. Results are also paginated with a default of `500` and a maximum on `5000` returned per page. This can be\n        controlled by setting the `results_per_page` parameter in the query string.\n        Returned results are pre-filtered to return only the annotations that have been labeled (`label_id != null`).\n        Also accepts a query string parameter `template` which formats the data using a predefined template. Some example\n        templates include: `data.html` which returns an HTML table, `json.html` which returns HTML-formatted JSON, `data.csv`\n        which returns a CSV file for download. If left blank, raw JSON will be returned.\n\n        For `group_by=annotation_set`, results also include the related `media_collection_id`, `media_collection_name`,\n        owner (`user_id`, `user_first_name`, `user_last_name`), `label_scheme_id`, `label_scheme_name`, status flags\n        (`is_final`, `is_qaqc`, `is_real_science`, `is_full_bio_score`, `is_exemplar`), `is_public` and\n        `current_user_can_view`. All matching annotation sets are listed, including ones that the current user can not\n        view (to help discover datasets and contact their custodians).\n\n        ^ **NOTE**: the counts in the `affiliation` and `usergroup` tally should be interpreted with care.\n        If someone belongs to more than one group, then their annotations will contribute to both so they may be double\n        counted. The corollary of that is if someone has not linked themselves to an affiliation or group, then their\n        annotations will not be counted in the tally.\n\n        **TRANSLATING TO OTHER LABEL_SCHEMES**\n\n        When using `group_by=label`, labels can also be translated to another label scheme with the `translate`\n        parameter.\n        \n        The `translate` querystring parameter translates [labels](#label) to a target [label_scheme](#label_scheme).\n        It is a JSON object:\n\n        ```\n        &translate={\"target_label_scheme_id\": ..., \"vocab_registry_keys\": [...], \"match\": ..., \"mapping_override\": {...}}\n        ```\n        - `target_label_scheme_id` [required]: the `id` of the target [label_scheme](#label_scheme).\n        - `vocab_registry_keys` [optional]: the vocab registries used for semantic matching, in priority order\n          (default: `[\"worms\", \"caab\", \"catami\"]`).\n        - `match` [optional]: how to choose between several target labels that share vocab elements with a label.\n          `\"consensus\"` (default) picks the target label sharing vocab elements from the most registries, then the\n          most vocab elements, then the best ranked registry. `\"priority\"` picks a match from the first registry in\n          `vocab_registry_keys` order that has one.\n        - `mapping_override` [optional]: `{source label.id: target label.id}` overrides the translation of a label,\n          and of its descendants that have no closer match of their own.\n\n        Each label is matched by its `mapping_override`, then by `tree_traversal` (the label is in the target scheme or\n        a scheme it extends), then by `semantic` translation (shared vocab elements). If a label has no match, its\n        parent is tried, and so on up the tree. A match on the label itself always takes precedence over a match on an\n        ancestor. When several target labels match equally well, the most general one (fewest ancestors) is chosen.\n\n        The `translation_info` output describes the match as `<method>.<level>[.<vocab elements>]`:\n        - `method` is `mapping_override`, `tree_traversal` or `semantic`;\n        - `level` is `direct` (matched on the label itself) or `relative-<id>` (matched on the ancestor label with\n          that `id`);\n        - for `semantic` matches, the matched vocab elements are listed as `<registry>-<key>`, delimited by `+`.\n\n        For example: `semantic.direct.worms-217362+caab-37320000`, `semantic.relative-123.worms-217362`,\n        `tree_traversal.direct` or `mapping_override.relative-123`.\n        \n        When translating, the output contains the additional columns: `label_lineage_names`, `translated_id`,\n        `translated_lineage_names`, `translated_name`, `translated_label_scheme_name` and `translated_info`.\n        \n\n        **EXAMPLES**\n\n        ```\n        ```\n        ",
          "endpoint": "/api/annotation_set/<int:id>/annotations/tally/<group_by>",
          "method": "GET"
        },
        {
          "description": "\n        Returns lists of the labels used in the `annotation_set` with an ID matching `id`. The `list_type` parameter\n        must one of [`updated_at`, `count`] which returns the most recently used labels or\n        counts by label (most frequently used), respectively. Depending on the `list_type`, an additional field containing\n        either the `count` or most recent `updated_at` datetime will be returned.\n        The number of results and page can be controlled with the optional `results_per_page` query parameter,\n        with a maximum of 200 results and a default of 20.\n        ",
          "endpoint": "/api/annotation_set/<int:id>/labels/list/<list_type>",
          "method": "GET"
        },
        {
          "description": "\n        Add the [media](#media) object with the ID `media_id` to the [media_collection](#media_collection) of the [annotation_set](#annotation_set) matching `annotation_set_id`\n        ",
          "endpoint": "/api/annotation_set/<int:annotation_set_id>/media/<int:media_id>",
          "method": "POST"
        },
        {
          "description": "\n        Remove the [media](#media) object with the ID `media_id` from the [media_collection](#media_collection) of the [annotation_set](#annotation_set) matching `annotation_set_id`\n        ",
          "endpoint": "/api/annotation_set/<int:annotation_set_id>/media/<int:media_id>",
          "method": "DELETE"
        },
        {
          "description": "\n        Clone the [annotation_set](#annotation_set) matching `id` to create a new one under the same collection.\n        This will clone all annotation_set properties along with all [points](#point), [annotations](#annotation),\n        [tags](#tag), [labels](#labels) including all annotation properties (`needs_review`, `likelihood`, `comment`).\n\n        Labels can also be translated to another label scheme with the `translate` parameter (the new annotation_set\n        then uses the target label scheme).\n        \n        The `translate` querystring parameter translates [labels](#label) to a target [label_scheme](#label_scheme).\n        It is a JSON object:\n\n        ```\n        &translate={\"target_label_scheme_id\": ..., \"vocab_registry_keys\": [...], \"match\": ..., \"mapping_override\": {...}}\n        ```\n        - `target_label_scheme_id` [required]: the `id` of the target [label_scheme](#label_scheme).\n        - `vocab_registry_keys` [optional]: the vocab registries used for semantic matching, in priority order\n          (default: `[\"worms\", \"caab\", \"catami\"]`).\n        - `match` [optional]: how to choose between several target labels that share vocab elements with a label.\n          `\"consensus\"` (default) picks the target label sharing vocab elements from the most registries, then the\n          most vocab elements, then the best ranked registry. `\"priority\"` picks a match from the first registry in\n          `vocab_registry_keys` order that has one.\n        - `mapping_override` [optional]: `{source label.id: target label.id}` overrides the translation of a label,\n          and of its descendants that have no closer match of their own.\n\n        Each label is matched by its `mapping_override`, then by `tree_traversal` (the label is in the target scheme or\n        a scheme it extends), then by `semantic` translation (shared vocab elements). If a label has no match, its\n        parent is tried, and so on up the tree. A match on the label itself always takes precedence over a match on an\n        ancestor. When several target labels match equally well, the most general one (fewest ancestors) is chosen.\n\n        The `translation_info` output describes the match as `<method>.<level>[.<vocab elements>]`:\n        - `method` is `mapping_override`, `tree_traversal` or `semantic`;\n        - `level` is `direct` (matched on the label itself) or `relative-<id>` (matched on the ancestor label with\n          that `id`);\n        - for `semantic` matches, the matched vocab elements are listed as `<registry>-<key>`, delimited by `+`.\n\n        For example: `semantic.direct.worms-217362+caab-37320000`, `semantic.relative-123.worms-217362`,\n        `tree_traversal.direct` or `mapping_override.relative-123`.\n                ",
          "endpoint": "/api/annotation_set/<int:id>/clone",
          "method": "POST"
        }
      ],
      "hybrid_properties": [
        {
          "args": [],
          "doc": "Number of media items in the media_collection",
          "name": "media_count",
          "type": "property"
        },
        {
          "args": [],
          "doc": "Total number of labeled [annotations](#annotation) this `annotation_set`",
          "name": "annotation_count",
          "type": "property"
        },
        {
          "args": [],
          "doc": "BOOLEAN, whether or not this annotation has a linked parent annotation",
          "name": "is_child",
          "type": "property"
        },
        {
          "args": [],
          "doc": "Whether or not this object is public (i.e. shared in a public group)",
          "name": "is_public",
          "type": "property"
        },
        {
          "args": [],
          "doc": "Whether the current logged in user is the owner of this object",
          "name": "current_user_is_owner",
          "type": "property"
        },
        {
          "args": [],
          "doc": "Whether the current logged in user is a member of a group that includes this object",
          "name": "current_user_is_member",
          "type": "property"
        },
        {
          "args": [],
          "doc": "Whether the current logged in user is a member with edit permission of a group that includes this object",
          "name": "current_user_is_edit_member",
          "type": "property"
        },
        {
          "args": [],
          "doc": "Whether the current logged in user is the owner of a group that includes this object",
          "name": "current_user_is_group_owner",
          "type": "property"
        },
        {
          "args": [],
          "doc": "Whether or not the current user has permission to view this object",
          "name": "current_user_can_view",
          "type": "property"
        },
        {
          "args": [],
          "doc": "Whether the current logged in user has edit permission (owner or edit_member)",
          "name": "current_user_can_edit",
          "type": "property"
        },
        {
          "args": [
            "user_id"
          ],
          "doc": "Whether the specified user is the owner of this object",
          "name": "user_is_owner",
          "type": "method"
        },
        {
          "args": [
            "user_id"
          ],
          "doc": "Whether the specified user is a member of a group that includes this object",
          "name": "user_is_member",
          "type": "method"
        },
        {
          "args": [
            "user_id"
          ],
          "doc": "Whether the specified user is a member with edit permission of a group that includes this object",
          "name": "user_is_edit_member",
          "type": "method"
        },
        {
          "args": [
            "user_id"
          ],
          "doc": "Whether the specified user is the owner of a group that includes this object",
          "name": "user_is_group_owner",
          "type": "method"
        },
        {
          "args": [
            "user_id"
          ],
          "doc": "Returns true is user is owner, dataset belongs to a public group, user owns a group or dataset belongs to an\n        unrestricted group that user is a member of",
          "name": "user_can_view",
          "type": "method"
        },
        {
          "args": [
            "user_id"
          ],
          "doc": "Whether the specified user has edit permission (owner or edit_member)",
          "name": "user_can_edit",
          "type": "method"
        }
      ],
      "methods": [
        {
          "doc": null,
          "name": "point_count",
          "type": "method"
        },
        {
          "doc": "\n        Preserve linking of annotations (observation groups) for cloning and import of annotations\n        @return:\n        ",
          "name": "preserve_object_links",
          "type": "method"
        },
        {
          "doc": null,
          "name": "unannotated_point_count",
          "type": "method"
        },
        {
          "doc": null,
          "name": "usergroup_count",
          "type": "method"
        }
      ],
      "relations": [
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "media_collection",
          "model": "media_collection"
        },
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "label_scheme",
          "model": "label_scheme"
        },
        {
          "direction": "MANYTOONE",
          "doc": "Related owner [users](#users) model",
          "key": "user",
          "model": "users"
        },
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "parent",
          "model": "annotation_set"
        },
        {
          "direction": "MANYTOMANY",
          "doc": "List of [groups](#groups) objects that contain this resource",
          "key": "usergroups",
          "model": "groups"
        },
        {
          "direction": "ONETOMANY",
          "doc": "List of [point](#point) objects",
          "key": "points",
          "model": "point"
        },
        {
          "direction": "ONETOMANY",
          "doc": "List of related [annotation](#annotation) objects",
          "key": "annotations",
          "model": "annotation"
        },
        {
          "direction": "ONETOMANY",
          "doc": null,
          "key": "children",
          "model": "annotation_set"
        },
        {
          "direction": "ONETOMANY",
          "doc": null,
          "key": "files",
          "model": "annotation_set_file"
        }
      ]
    },
    {
      "association_proxies": [],
      "collection": "annotation_set_file",
      "columns": [
        {
          "default": null,
          "doc": "Primary key `id`",
          "foreign_key": null,
          "name": "id",
          "nullable": false,
          "primary_key": true,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": "Sequence of file operations performed at last save",
          "foreign_key": null,
          "name": "last_save",
          "nullable": true,
          "primary_key": false,
          "type": "JSON()",
          "unique": null
        },
        {
          "default": null,
          "doc": "The name of the file (optional). Defaults to `basename` of either `file_url` or the path of the uploaded file",
          "foreign_key": null,
          "name": "name",
          "nullable": false,
          "primary_key": false,
          "type": "Text()",
          "unique": false
        },
        {
          "default": null,
          "doc": "The URL of the file to be loaded dynamically (if `data` field is not set)",
          "foreign_key": null,
          "name": "file_url",
          "nullable": true,
          "primary_key": false,
          "type": "Text()",
          "unique": false
        },
        {
          "default": null,
          "doc": "The description of the file (optional)",
          "foreign_key": null,
          "name": "description",
          "nullable": true,
          "primary_key": false,
          "type": "Text()",
          "unique": null
        },
        {
          "default": null,
          "doc": "The raw file storage for the file. This is not directly accessible through the API",
          "foreign_key": null,
          "name": "_rawfiledata",
          "nullable": true,
          "primary_key": false,
          "type": "LargeBinary()",
          "unique": null
        },
        {
          "default": "False",
          "doc": "Whether or not the file is compressed or not. If so, it will be automatically decompressed upon access.",
          "foreign_key": null,
          "name": "iscompressed",
          "nullable": true,
          "primary_key": false,
          "type": "Boolean()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": "users.id",
          "name": "user_id",
          "nullable": false,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": "annotation_set.id",
          "name": "annotation_set_id",
          "nullable": false,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": "function",
          "doc": null,
          "foreign_key": null,
          "name": "created_at",
          "nullable": false,
          "primary_key": false,
          "type": "DateTime()",
          "unique": null
        },
        {
          "default": "function",
          "doc": "Updated time (UTC)",
          "foreign_key": null,
          "name": "updated_at",
          "nullable": true,
          "primary_key": false,
          "type": "DateTime()",
          "unique": null
        }
      ],
      "description": "\n    Annotation Set File resource: a file associated with a [annotation_set](#annotation_set) object. Can be used for\n    batch importing / updating of [annotation](#annotation) and [point](#point) objects, as well as batch adding\n    [media](#media) objects to a [media_collection](#media_collection).\n    ",
      "endpoints": [
        {
          "description": "Create new [annotation_set_file](#annotation_set_file) object. Expects JSON. Fields shown in `MODEL COLUMNS` below. Add user_id to post payload if not supplied",
          "endpoint": "/api/annotation_set_file",
          "method": "POST",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict to users with edit rights to the annotation set",
              "name": "post_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Update single [annotation_set_file](#annotation_set_file) object with pk field matching param `id`. Expects JSON. Fields shown in `MODEL COLUMNS` below.",
          "endpoint": "/api/annotation_set_file/<id>",
          "method": "PATCH",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict to the file uploader or users with edit rights to the annotation set (also for a new\n        `annotation_set_id`)",
              "name": "patch_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get list of [annotation_set_file](#annotation_set_file) objects matching API query. See [Making API search queries](#api_query) for instructions on making search queries",
          "endpoint": "/api/annotation_set_file",
          "fields": [
            "user_id",
            "description",
            "iscompressed",
            "annotation_set_id",
            "file_url",
            "id",
            "name",
            "last_save"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_many_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get single [annotation_set_file](#annotation_set_file) object with pk field matching param `id`",
          "endpoint": "/api/annotation_set_file/<id>",
          "fields": [
            "user_id",
            "description",
            "iscompressed",
            "annotation_set_id",
            "file_url",
            "id",
            "name",
            "last_save",
            "created_at",
            "user",
            "user.id",
            "user.first_name",
            "user.last_name",
            "annotation_set",
            "annotation_set.id",
            "annotation_set.name",
            "current_user_can_edit",
            "stored_size"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_single_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Delete single [annotation_set_file](#annotation_set_file) object with pk field matching param `id`",
          "endpoint": "/api/annotation_set_file/<id>",
          "method": "DELETE",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to the file uploader, or users with edit rights to the parent annotation_set",
              "name": "delete_auth_preprocessor"
            }
          ]
        },
        {
          "description": "\n        Annotation Set File resource. \n        Get the data for the file resource matching `fid`. This endpoint also provides options to manipulate, transform\n        and save data to the database. The querystring takes the following form:\n        ```\n        ?f={...}&save={...}&disposition=...&template=...\n        ```\n        where `f` is a JSON dictionary containing a sequence of operations for transforming the data\n        (see [Data transformation API](#api_data_transform) for more info),\n        `disposition` is optional and defines the download type which can be `inline` (default, displays in\n        the browser) or `attachment` (triggers a download) ,\n        `template` is optional depending on the output of the steps in `f` and can be used to define the export format,\n        `save` is a JSON dictionary that defines batch save operations. This can be used to save the file content or the\n        output of the operations in `f` to a related database model collection.\n\n        \n\n        **IMPORTING ANNOTATIONS:** use `save={\"collection\": \"annotation_set.points\"}` with the `annotation_set_id`\n        querystring parameter. Each record creates a [point](#point): link it to its [media](#media) with `set_media`\n        (a media `key`, ideally with a `deployment_id` or `deployment_key`) and set its label(s) with\n        `annotation_label` (a label `id`, `uuid` or `origin_code`, plus optional `comment`, `likelihood`,\n        `needs_review` and `tag_names`); `x`, `y` and `t` are optional (proportions of the image width / height and\n        seconds into a video). Add `\"skip_errors\": true` to `save` to skip rows that fail. Omit `save` to preview the\n        transformed records without saving.\n\n        **Example1:** import a CSV with the columns `set_media.key`, `set_media.deployment_id`, `annotation_label.id`,\n        `x` and `y`\n        ```\n        /api/annotation_set_file/2/data?annotation_set_id=456&save={\"collection\": \"annotation_set.points\"}&f={\"operations\": [{\"module\": \"pandas\", \"method\": \"read_csv\", \"kwargs\": {\"keep_default_na\": false}}, {\"method\": \"to_dict\", \"kwargs\": {\"orient\": \"records\"}}, {\"module\": \"data\", \"method\": \"unflatten_dicts\", \"kwargs\": {}}]}\n        ```\n\n        **Example2:** import a CSV exported from another annotation set (columns `point.media.key`,\n        `point.media.deployment.id`, `label.id`, `point.x` and `point.y`), renaming the columns on the way in\n        ```\n        /api/annotation_set_file/2/data?annotation_set_id=456&save={\"collection\": \"annotation_set.points\", \"skip_errors\": true}&f={\"operations\": [{\"module\": \"pandas\", \"method\": \"read_csv\", \"kwargs\": {\"keep_default_na\": false}}, {\"method\": \"rename\", \"kwargs\": {\"columns\": {\"point.media.key\": \"set_media.key\", \"point.media.deployment.id\": \"set_media.deployment_id\", \"label.id\": \"annotation_label.id\", \"point.x\": \"x\", \"point.y\": \"y\"}}}, {\"method\": \"to_dict\", \"kwargs\": {\"orient\": \"records\"}}, {\"module\": \"data\", \"method\": \"unflatten_dicts\", \"kwargs\": {}}]}\n        ```\n        ",
          "endpoint": "/api/annotation_set_file/<int:fid>/data",
          "method": "GET"
        },
        {
          "description": "\n        Upload a file for an annotation set (multipart form post with `file` and the fields of the object, incl.\n        `annotation_set_id`). Restricted to users with edit rights to the annotation set.\n        ",
          "endpoint": "/api/annotation_set_file/data",
          "method": "POST"
        }
      ],
      "hybrid_properties": [],
      "methods": [
        {
          "doc": "Override to run special method after for preserving annotation linking",
          "name": "batch_save",
          "type": "method"
        },
        {
          "doc": "BOOLEAN, whether the current user uploaded this file or has edit rights to the parent [annotation_set](#annotation_set)",
          "name": "current_user_can_edit",
          "type": "method"
        },
        {
          "doc": "Size (bytes) of the file data stored in the database, or null if the file is linked by `file_url`",
          "name": "stored_size",
          "type": "method"
        },
        {
          "doc": null,
          "name": "data",
          "type": "property"
        }
      ],
      "relations": [
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "user",
          "model": "users"
        },
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "annotation_set",
          "model": "annotation_set"
        }
      ]
    },
    {
      "association_proxies": [],
      "collection": "annotation_tags",
      "columns": [
        {
          "default": null,
          "doc": "`id` of linked [annotation](#annotation)",
          "foreign_key": "annotation.id",
          "name": "annotation_id",
          "nullable": false,
          "primary_key": true,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": "`id` of linked [tag](#tag)",
          "foreign_key": "tag.id",
          "name": "tag_id",
          "nullable": false,
          "primary_key": true,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": "function",
          "doc": null,
          "foreign_key": null,
          "name": "assoc_created_at",
          "nullable": true,
          "primary_key": false,
          "type": "DateTime()",
          "unique": null
        }
      ],
      "description": "\n    Tag Annotation Associate resource: links [tag](#tag) objects to [annotation](#annotation) objects.\n    ",
      "endpoints": [
        {
          "description": "Create new [annotation_tags](#annotation_tags) object. Expects JSON. Fields shown in `MODEL COLUMNS` below. ",
          "endpoint": "/api/annotation_tags",
          "method": "POST",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to LOGGED IN users only",
              "name": "post_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get list of [annotation_tags](#annotation_tags) objects matching API query. See [Making API search queries](#api_query) for instructions on making search queries",
          "endpoint": "/api/annotation_tags",
          "fields": [],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_many_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get single [annotation_tags](#annotation_tags) object with pk field matching param `annotation_id`",
          "endpoint": "/api/annotation_tags/<annotation_id>",
          "fields": [],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_single_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Delete single [annotation_tags](#annotation_tags) object with pk field matching param `annotation_id`",
          "endpoint": "/api/annotation_tags/<annotation_id>",
          "method": "DELETE",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to OWNER only",
              "name": "delete_auth_preprocessor"
            }
          ]
        }
      ],
      "hybrid_properties": [],
      "methods": [],
      "relations": [
        {
          "direction": "MANYTOONE",
          "doc": "Linked [annotation](#annotation) object",
          "key": "annotation",
          "model": "annotation"
        },
        {
          "direction": "MANYTOONE",
          "doc": "Linked [tag](#tag) object",
          "key": "tag",
          "model": "tag"
        }
      ]
    },
    {
      "association_proxies": [],
      "collection": "camera",
      "columns": [
        {
          "default": null,
          "doc": "Primary key `id`",
          "foreign_key": null,
          "name": "id",
          "nullable": false,
          "primary_key": true,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": "{}",
          "doc": "Text field containing JSON properties for this resource",
          "foreign_key": null,
          "name": "data",
          "nullable": true,
          "primary_key": false,
          "type": "JSON()",
          "unique": null
        },
        {
          "default": null,
          "doc": "Unique, stable identifier, eg: `sirius_LC16`",
          "foreign_key": null,
          "name": "key",
          "nullable": false,
          "primary_key": false,
          "type": "String(length=80)",
          "unique": true
        },
        {
          "default": null,
          "doc": "Display name",
          "foreign_key": null,
          "name": "name",
          "nullable": false,
          "primary_key": false,
          "type": "String(length=128)",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "description",
          "nullable": true,
          "primary_key": false,
          "type": "Text()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": "users.id",
          "name": "user_id",
          "nullable": true,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": "function",
          "doc": null,
          "foreign_key": null,
          "name": "created_at",
          "nullable": false,
          "primary_key": false,
          "type": "DateTime()",
          "unique": null
        },
        {
          "default": "function",
          "doc": null,
          "foreign_key": null,
          "name": "updated_at",
          "nullable": true,
          "primary_key": false,
          "type": "DateTime()",
          "unique": null
        }
      ],
      "description": "\n    Camera resource: a camera (a physical unit, or a model / configuration used across several platforms). Where,\n    when and in which configuration it was used is defined by its [camera_installation](#camera_installation)s.\n    Admins and custodians can create cameras; admins and the owner can edit them.\n    ",
      "endpoints": [
        {
          "description": "Create new [camera](#camera) object. Expects JSON. Fields shown in `MODEL COLUMNS` below. A simple constructor that allows initialization from kwargs.\n\n    Sets attributes on the constructed instance using the names and\n    values in ``kwargs``.\n\n    Only keys that are present as\n    attributes of the instance's class are allowed. These could be,\n    for example, any mapped columns or relationships.\n    ",
          "endpoint": "/api/camera",
          "method": "POST",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Admins and custodians",
              "name": "post_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Update single [camera](#camera) object with pk field matching param `id`. Expects JSON. Fields shown in `MODEL COLUMNS` below.",
          "endpoint": "/api/camera/<id>",
          "method": "PATCH",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Admins and the owner. Only `key`, `name`, `description` and `data` can be changed",
              "name": "patch_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get list of [camera](#camera) objects matching API query. See [Making API search queries](#api_query) for instructions on making search queries",
          "endpoint": "/api/camera",
          "fields": [
            "id",
            "key",
            "name",
            "description",
            "data",
            "user_id",
            "created_at",
            "updated_at",
            "platform_ids",
            "platforms",
            "installation_count"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_many_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get single [camera](#camera) object with pk field matching param `id`",
          "endpoint": "/api/camera/<id>",
          "fields": [
            "id",
            "key",
            "name",
            "description",
            "data",
            "user_id",
            "created_at",
            "updated_at",
            "platform_ids",
            "platforms",
            "installation_count"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_single_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Delete single [camera](#camera) object with pk field matching param `id`",
          "endpoint": "/api/camera/<id>",
          "method": "DELETE",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Admins, or the owner if they can manage the cameras of every platform it is installed on. Its\n        installations are deleted, and their media kept (unassigned)",
              "name": "delete_auth_preprocessor"
            }
          ]
        }
      ],
      "hybrid_properties": [],
      "methods": [
        {
          "doc": "Number of installations of this camera (on all platforms)",
          "name": "installation_count",
          "type": "method"
        },
        {
          "doc": "Ids of the platforms this camera is (or was) installed on",
          "name": "platform_ids",
          "type": "method"
        },
        {
          "doc": "The platforms this camera is (or was) installed on: `[{\"id\", \"name\"}]`",
          "name": "platforms",
          "type": "method"
        }
      ],
      "relations": [
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "user",
          "model": "users"
        },
        {
          "direction": "ONETOMANY",
          "doc": null,
          "key": "installations",
          "model": "camera_installation"
        }
      ]
    },
    {
      "association_proxies": [],
      "collection": "camera_installation",
      "columns": [
        {
          "default": null,
          "doc": "Primary key `id`",
          "foreign_key": null,
          "name": "id",
          "nullable": false,
          "primary_key": true,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": "camera.id",
          "name": "camera_id",
          "nullable": false,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": "platform.id",
          "name": "platform_id",
          "nullable": false,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": "Optional name of the installation, eg: its position (`North`, `Port`) when a platform carries several units of the same camera",
          "foreign_key": null,
          "name": "name",
          "nullable": true,
          "primary_key": false,
          "type": "String(length=128)",
          "unique": null
        },
        {
          "default": null,
          "doc": "Start of the installation (inclusive, UTC). NULL: since the start",
          "foreign_key": null,
          "name": "valid_from",
          "nullable": true,
          "primary_key": false,
          "type": "DateTime()",
          "unique": null
        },
        {
          "default": null,
          "doc": "End of the installation (exclusive, UTC). NULL: still installed",
          "foreign_key": null,
          "name": "valid_to",
          "nullable": true,
          "primary_key": false,
          "type": "DateTime()",
          "unique": null
        },
        {
          "default": "key",
          "doc": "What `patterns` are matched against: `key` (the media key) or `data.<path>` (a `media.data` attribute, eg: `data.camera`)",
          "foreign_key": null,
          "name": "match_field",
          "nullable": false,
          "primary_key": false,
          "type": "String(length=64)",
          "unique": null
        },
        {
          "default": null,
          "doc": "List of PostgreSQL regular expressions. Empty: media are only assigned to this installation manually",
          "foreign_key": null,
          "name": "patterns",
          "nullable": true,
          "primary_key": false,
          "type": "JSON()",
          "unique": null
        },
        {
          "default": "0",
          "doc": "Settles media matched by several installations (highest first, then the latest `valid_from`)",
          "foreign_key": null,
          "name": "priority",
          "nullable": false,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": "Default pixel width of its media (displayed orientation)",
          "foreign_key": null,
          "name": "width",
          "nullable": true,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": "Default pixel height of its media (displayed orientation)",
          "foreign_key": null,
          "name": "height",
          "nullable": true,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "description",
          "nullable": true,
          "primary_key": false,
          "type": "Text()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": "users.id",
          "name": "user_id",
          "nullable": true,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": "function",
          "doc": null,
          "foreign_key": null,
          "name": "created_at",
          "nullable": false,
          "primary_key": false,
          "type": "DateTime()",
          "unique": null
        },
        {
          "default": "function",
          "doc": null,
          "foreign_key": null,
          "name": "updated_at",
          "nullable": true,
          "primary_key": false,
          "type": "DateTime()",
          "unique": null
        }
      ],
      "description": "\n    Camera installation resource: a [camera](#camera) installed on a [platform](#platform) for a period of time\n    (`[valid_from, valid_to)`), in a configuration (default `width` / `height` of its media). Media of the platform\n    are assigned to it by camera assignment when their `match_field` (`key`, or a `media.data` attribute such as\n    `data.camera`) matches one of its `patterns` (PostgreSQL regular expressions). Changes are not applied to\n    existing media until camera assignment is applied (`POST /api/platform/<id>/cameras/apply`); preview them with\n    `/api/platform/<id>/cameras/preview`. Admins and custodians of a datasource of the platform can manage its\n    installations.\n    ",
      "endpoints": [
        {
          "description": "Create new [camera_installation](#camera_installation) object. Expects JSON. Fields shown in `MODEL COLUMNS` below. A simple constructor that allows initialization from kwargs.\n\n    Sets attributes on the constructed instance using the names and\n    values in ``kwargs``.\n\n    Only keys that are present as\n    attributes of the instance's class are allowed. These could be,\n    for example, any mapped columns or relationships.\n    ",
          "endpoint": "/api/camera_installation",
          "method": "POST",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": null,
              "name": "post_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Update single [camera_installation](#camera_installation) object with pk field matching param `id`. Expects JSON. Fields shown in `MODEL COLUMNS` below.",
          "endpoint": "/api/camera_installation/<id>",
          "method": "PATCH",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": null,
              "name": "patch_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get list of [camera_installation](#camera_installation) objects matching API query. See [Making API search queries](#api_query) for instructions on making search queries",
          "endpoint": "/api/camera_installation",
          "fields": [
            "id",
            "name",
            "camera_id",
            "camera",
            "camera.id",
            "camera.key",
            "camera.name",
            "platform_id",
            "platform",
            "platform.id",
            "platform.name",
            "valid_from",
            "valid_to",
            "match_field",
            "patterns",
            "priority",
            "width",
            "height",
            "description",
            "user_id",
            "created_at",
            "updated_at",
            "period",
            "label"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_many_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get single [camera_installation](#camera_installation) object with pk field matching param `id`",
          "endpoint": "/api/camera_installation/<id>",
          "fields": [
            "id",
            "name",
            "camera_id",
            "camera",
            "camera.id",
            "camera.key",
            "camera.name",
            "platform_id",
            "platform",
            "platform.id",
            "platform.name",
            "valid_from",
            "valid_to",
            "match_field",
            "patterns",
            "priority",
            "width",
            "height",
            "description",
            "user_id",
            "created_at",
            "updated_at",
            "period",
            "label"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_single_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Delete single [camera_installation](#camera_installation) object with pk field matching param `id`",
          "endpoint": "/api/camera_installation/<id>",
          "method": "DELETE",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Its media are kept (unassigned)",
              "name": "delete_auth_preprocessor"
            }
          ]
        },
        {
          "description": "\n        Manually assign media to this installation (`camera_source = 'manual'`: never changed by automatic camera\n        assignment). JSON body: `media_ids` and/or `deployment_ids` (all their media). The media must belong to the\n        installation's platform, and the user must be a custodian of their datasources.\n        Returns `{\"assigned\": <count>}`.\n        ",
          "endpoint": "/api/camera_installation/<int:id>/assign",
          "method": "POST"
        }
      ],
      "hybrid_properties": [],
      "methods": [
        {
          "doc": "When the camera was installed, for display: eg: `2019-03-01 to 2020-06-30`, `from 2019-03-01`, `all dates`",
          "name": "period",
          "type": "method"
        },
        {
          "doc": "STRING, display name: the camera name and the installation `name`, eg: `GoPro Hero 9 \u2013 North`",
          "name": "label",
          "type": "property"
        }
      ],
      "relations": [
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "camera",
          "model": "camera"
        },
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "platform",
          "model": "platform"
        },
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "user",
          "model": "users"
        },
        {
          "direction": "ONETOMANY",
          "doc": null,
          "key": "media",
          "model": "media"
        }
      ]
    },
    {
      "association_proxies": [],
      "collection": "campaign-deployment",
      "columns": [],
      "description": "\n    A special resource for listing / querying campaigns in a different format.\n    ",
      "endpoints": [
        {
          "description": "\n\n        ** Examples: **\n        ```\n        # search campaign-deployments for \"gbr\"\n        /api/campaign-deployment/deployment?q={\"filters\":[{\"or\":[{\"name\":\"key\",\"op\":\"ilike\",\"val\":\"%gbr%\"},{\"name\":\"campaign\",\"op\":\"has\",\"val\":{\"name\":\"key\",\"op\":\"ilike\",\"val\":\"%gbr%\"}}]}]}\n        # match list of deployment keys (campaign-deployment)\n        /api/campaign-deployment?q={\"filters\":[{\"name\":\"key\",\"op\":\"in\",\"val\":[\"r20071004_013437_gbr_05_noggin_grids\",\"r20071010_230932_gbr_09_hydrographers_leg\"]}]}\n        # as above but for deployments\n        /api/campaign-deployment/deployment?q={\"filters\":[{\"name\":\"key\",\"op\":\"in\",\"val\":[\"r20071004_013437_gbr_05_noggin_grids\",\"r20071010_230932_gbr_09_hydrographers_leg\"]}]}\n        # as above but for IDs and not keys\n        /api/campaign-deployment/deployment?q={\"filters\":[{\"name\":\"id\",\"op\":\"in\",\"val\":[9495,9491]}]}\n        ```\n        ",
          "endpoint": "/api/campaign-deployment/<resource>",
          "method": "GET"
        },
        {
          "description": "\n\n        ** Examples: **\n        ```\n        # search campaign-deployments for \"gbr\"\n        /api/campaign-deployment/deployment?q={\"filters\":[{\"or\":[{\"name\":\"key\",\"op\":\"ilike\",\"val\":\"%gbr%\"},{\"name\":\"campaign\",\"op\":\"has\",\"val\":{\"name\":\"key\",\"op\":\"ilike\",\"val\":\"%gbr%\"}}]}]}\n        # match list of deployment keys (campaign-deployment)\n        /api/campaign-deployment?q={\"filters\":[{\"name\":\"key\",\"op\":\"in\",\"val\":[\"r20071004_013437_gbr_05_noggin_grids\",\"r20071010_230932_gbr_09_hydrographers_leg\"]}]}\n        # as above but for deployments\n        /api/campaign-deployment/deployment?q={\"filters\":[{\"name\":\"key\",\"op\":\"in\",\"val\":[\"r20071004_013437_gbr_05_noggin_grids\",\"r20071010_230932_gbr_09_hydrographers_leg\"]}]}\n        # as above but for IDs and not keys\n        /api/campaign-deployment/deployment?q={\"filters\":[{\"name\":\"id\",\"op\":\"in\",\"val\":[9495,9491]}]}\n        ```\n        ",
          "endpoint": "/api/campaign-deployment",
          "method": "GET"
        }
      ],
      "hybrid_properties": [],
      "methods": [],
      "relations": []
    },
    {
      "association_proxies": [],
      "collection": "campaign",
      "columns": [
        {
          "default": null,
          "doc": "Primary key `id`",
          "foreign_key": null,
          "name": "id",
          "nullable": false,
          "primary_key": true,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": "Name of this `campaign`",
          "foreign_key": null,
          "name": "name",
          "nullable": false,
          "primary_key": false,
          "type": "String(length=80)",
          "unique": null
        },
        {
          "default": null,
          "doc": "Key of this `campaign` (used for generating paths and links in repo)",
          "foreign_key": null,
          "name": "key",
          "nullable": false,
          "primary_key": false,
          "type": "String(length=80)",
          "unique": true
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "path",
          "nullable": true,
          "primary_key": false,
          "type": "Text()",
          "unique": null
        },
        {
          "default": "function",
          "doc": "Hex colour code for this `campaign`",
          "foreign_key": null,
          "name": "color",
          "nullable": true,
          "primary_key": false,
          "type": "String(length=10)",
          "unique": false
        },
        {
          "default": null,
          "doc": "Description for this `campaign`",
          "foreign_key": null,
          "name": "description",
          "nullable": true,
          "primary_key": false,
          "type": "Text()",
          "unique": null
        },
        {
          "default": null,
          "doc": "ID of the [user][#users] who created this `campaign`",
          "foreign_key": "users.id",
          "name": "user_id",
          "nullable": false,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": "function",
          "doc": "Datetime of creation",
          "foreign_key": null,
          "name": "created_at",
          "nullable": false,
          "primary_key": false,
          "type": "DateTime()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "media_path_pattern",
          "nullable": true,
          "primary_key": false,
          "type": "Text()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "thm_path_pattern",
          "nullable": true,
          "primary_key": false,
          "type": "Text()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "geom_start",
          "nullable": true,
          "primary_key": false,
          "type": "Geometry(geometry_type='POINT', srid=4326, from_text='ST_GeomFromEWKT', name='geometry')",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "geom_end",
          "nullable": true,
          "primary_key": false,
          "type": "Geometry(geometry_type='POINT', srid=4326, from_text='ST_GeomFromEWKT', name='geometry')",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "geom_centroid",
          "nullable": true,
          "primary_key": false,
          "type": "Geometry(geometry_type='POINT', srid=4326, from_text='ST_GeomFromEWKT', name='geometry')",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "dep_min",
          "nullable": true,
          "primary_key": false,
          "type": "Float()",
          "unique": false
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "dep_max",
          "nullable": true,
          "primary_key": false,
          "type": "Float()",
          "unique": false
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "alt_min",
          "nullable": true,
          "primary_key": false,
          "type": "Float()",
          "unique": false
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "alt_max",
          "nullable": true,
          "primary_key": false,
          "type": "Float()",
          "unique": false
        },
        {
          "default": "function",
          "doc": null,
          "foreign_key": null,
          "name": "timestamp_start",
          "nullable": true,
          "primary_key": false,
          "type": "DateTime()",
          "unique": null
        },
        {
          "default": "function",
          "doc": null,
          "foreign_key": null,
          "name": "timestamp_end",
          "nullable": true,
          "primary_key": false,
          "type": "DateTime()",
          "unique": null
        },
        {
          "default": "0",
          "doc": null,
          "foreign_key": null,
          "name": "pose_count",
          "nullable": true,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": "0",
          "doc": null,
          "foreign_key": null,
          "name": "media_count",
          "nullable": true,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": "0",
          "doc": null,
          "foreign_key": null,
          "name": "deployment_count",
          "nullable": true,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        }
      ],
      "description": "\n    Campaign resource: a group of [deployments](#deployment). Eg: a specific expedition, cruise or data collection initiative\n    ",
      "endpoints": [
        {
          "description": "Create new [campaign](#campaign) object. Expects JSON. Fields shown in `MODEL COLUMNS` below. Add user_id to post payload if not supplied",
          "endpoint": "/api/campaign",
          "method": "POST",
          "postprocessors": [
            {
              "doc": "Clears the request cache object for this resource (to cause cache refresh on next request)",
              "name": "_clear_cache"
            }
          ],
          "preprocessors": [
            {
              "doc": "Restrict to datasource custodians",
              "name": "post_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Update single [campaign](#campaign) object with pk field matching param `id`. Expects JSON. Fields shown in `MODEL COLUMNS` below.",
          "endpoint": "/api/campaign/<id>",
          "method": "PATCH",
          "postprocessors": [
            {
              "doc": "Clears the request cache object for this resource (to cause cache refresh on next request)",
              "name": "_clear_cache"
            }
          ],
          "preprocessors": [
            {
              "doc": "Restrict to custodians of every datasource with deployments in the campaign",
              "name": "patch_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get list of [campaign](#campaign) objects matching API query. See [Making API search queries](#api_query) for instructions on making search queries",
          "endpoint": "/api/campaign",
          "fields": [
            "color",
            "id",
            "key",
            "name",
            "description",
            "timestamp_start",
            "timestamp_end",
            "created_at",
            "deployment_count",
            "media_count",
            "total_annotation_count",
            "public_annotation_count",
            "latlon"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_many_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get single [campaign](#campaign) object with pk field matching param `id`",
          "endpoint": "/api/campaign/<id>",
          "fields": [
            "color",
            "id",
            "key",
            "name",
            "description",
            "timestamp_start",
            "timestamp_end",
            "created_at",
            "deployment_count",
            "media_count",
            "total_annotation_count",
            "public_annotation_count",
            "latlon",
            "user_id",
            "stats",
            "platforms",
            "total_annotation_count",
            "public_annotation_count"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_single_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Delete single [campaign](#campaign) object with pk field matching param `id`",
          "endpoint": "/api/campaign/<id>",
          "method": "DELETE",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict to custodians of every datasource with deployments in the campaign. Campaigns with labelled\n        annotations can only be deleted by custodians that are admins, with `?confirm=<campaign key>`",
              "name": "delete_auth_preprocessor"
            }
          ]
        },
        {
          "description": "\n        Deployment resource\n\n        Minimal Deployment Resource for map data - result is cached for fast loading. Cache is cleared when new deployments are saved.\n\n        :param GET: json: q: restless search query.\n        :returns GET: json: a json string containing the structure of stuff\n        ",
          "endpoint": "/api/campaign/map",
          "method": "GET"
        },
        {
          "description": "Finalise the campaign computing cached `pose` metrics and 'geo' properties",
          "endpoint": "/api/campaign/<int:id>/finalise",
          "method": "PATCH"
        },
        {
          "description": "Whether the current user can delete this campaign (and all its deployments), and what would be deleted.\n        Pass `?confirm=<campaign key>` to check a confirmed deletion.",
          "endpoint": "/api/campaign/<int:id>/delete_check",
          "method": "GET"
        }
      ],
      "hybrid_properties": [
        {
          "args": [],
          "doc": "The centroid `geom` point of all the [poses](#pose) contained in this `campaign`",
          "name": "geom",
          "type": "property"
        },
        {
          "args": [],
          "doc": "A `timestamp` from the [poses](#pose) contained in this `campaign`",
          "name": "timestamp",
          "type": "property"
        },
        {
          "args": [],
          "doc": "Fetch total annotation count from the materialized view.",
          "name": "total_annotation_count",
          "type": "property"
        },
        {
          "args": [],
          "doc": "Fetch public annotation count from the materialized view.",
          "name": "public_annotation_count",
          "type": "property"
        }
      ],
      "methods": [
        {
          "doc": "\n        Compute spatial extent of Campaign\n        :return: list with format [[SW_LAT, SW_LON],[NE_LAT,NE_LON]]\n        ",
          "name": "extent",
          "type": "method"
        },
        {
          "doc": null,
          "name": "file_count",
          "type": "method"
        },
        {
          "doc": null,
          "name": "platforms",
          "type": "method"
        },
        {
          "doc": null,
          "name": "stats",
          "type": "method"
        },
        {
          "doc": null,
          "name": "timestamp_range",
          "type": "method"
        },
        {
          "doc": null,
          "name": "latlon",
          "type": "property"
        }
      ],
      "relations": [
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "user",
          "model": "users"
        },
        {
          "direction": "ONETOMANY",
          "doc": null,
          "key": "deployments",
          "model": "deployment"
        },
        {
          "direction": "ONETOMANY",
          "doc": null,
          "key": "info",
          "model": "campaigninfo"
        },
        {
          "direction": "ONETOMANY",
          "doc": null,
          "key": "files",
          "model": "campaign_file"
        }
      ]
    },
    {
      "association_proxies": [],
      "collection": "campaign_file",
      "columns": [
        {
          "default": null,
          "doc": "Primary key `id`",
          "foreign_key": null,
          "name": "id",
          "nullable": false,
          "primary_key": true,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": "Sequence of file operations performed at last save",
          "foreign_key": null,
          "name": "last_save",
          "nullable": true,
          "primary_key": false,
          "type": "JSON()",
          "unique": null
        },
        {
          "default": null,
          "doc": "The name of the file (optional). Defaults to `basename` of either `file_url` or the path of the uploaded file",
          "foreign_key": null,
          "name": "name",
          "nullable": false,
          "primary_key": false,
          "type": "Text()",
          "unique": false
        },
        {
          "default": null,
          "doc": "The URL of the file to be loaded dynamically (if `data` field is not set)",
          "foreign_key": null,
          "name": "file_url",
          "nullable": true,
          "primary_key": false,
          "type": "Text()",
          "unique": false
        },
        {
          "default": null,
          "doc": "The description of the file (optional)",
          "foreign_key": null,
          "name": "description",
          "nullable": true,
          "primary_key": false,
          "type": "Text()",
          "unique": null
        },
        {
          "default": null,
          "doc": "The raw file storage for the file. This is not directly accessible through the API",
          "foreign_key": null,
          "name": "_rawfiledata",
          "nullable": true,
          "primary_key": false,
          "type": "LargeBinary()",
          "unique": null
        },
        {
          "default": "False",
          "doc": "Whether or not the file is compressed or not. If so, it will be automatically decompressed upon access.",
          "foreign_key": null,
          "name": "iscompressed",
          "nullable": true,
          "primary_key": false,
          "type": "Boolean()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": "users.id",
          "name": "user_id",
          "nullable": false,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": "campaign.id",
          "name": "campaign_id",
          "nullable": false,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": "function",
          "doc": null,
          "foreign_key": null,
          "name": "created_at",
          "nullable": true,
          "primary_key": false,
          "type": "DateTime()",
          "unique": null
        },
        {
          "default": "function",
          "doc": "Updated time (UTC)",
          "foreign_key": null,
          "name": "updated_at",
          "nullable": true,
          "primary_key": false,
          "type": "DateTime()",
          "unique": null
        }
      ],
      "description": "\n    Campaign File resource: a file associated with a [campaign](#campaign) object.\n    ",
      "endpoints": [
        {
          "description": "Create new [campaign_file](#campaign_file) object. Expects JSON. Fields shown in `MODEL COLUMNS` below. Add user_id to post payload if not supplied",
          "endpoint": "/api/campaign_file",
          "method": "POST",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to LOGGED IN users only",
              "name": "post_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Update single [campaign_file](#campaign_file) object with pk field matching param `id`. Expects JSON. Fields shown in `MODEL COLUMNS` below.",
          "endpoint": "/api/campaign_file/<id>",
          "method": "PATCH",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to OWNER only",
              "name": "patch_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get list of [campaign_file](#campaign_file) objects matching API query. See [Making API search queries](#api_query) for instructions on making search queries",
          "endpoint": "/api/campaign_file",
          "fields": [
            "user_id",
            "description",
            "iscompressed",
            "campaign_id",
            "file_url",
            "id",
            "name"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_many_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get single [campaign_file](#campaign_file) object with pk field matching param `id`",
          "endpoint": "/api/campaign_file/<id>",
          "fields": [
            "user_id",
            "description",
            "iscompressed",
            "campaign_id",
            "file_url",
            "id",
            "name"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_single_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Delete single [campaign_file](#campaign_file) object with pk field matching param `id`",
          "endpoint": "/api/campaign_file/<id>",
          "method": "DELETE",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to OWNER only",
              "name": "delete_auth_preprocessor"
            }
          ]
        },
        {
          "description": "\n        Get the data for the file resource matching `fid`. This endpoint also provides options to manipulate, transform\n        and save data to the database. The querystring takes the following form:\n        ```\n        ?f={...}&save={...}&disposition=...&template=...\n        ```\n        where `f` is a JSON dictionary containing a sequence of operations for transforming the data\n        (see [Data transformation API](#api_data_transform) for more info),\n        `disposition` is optional and defines the download type which can be `inline` (default, displays in\n        the browser) or `attachment` (triggers a download) ,\n        `template` is optional depending on the output of the steps in `f` and can be used to define the export format,\n        `save` is a JSON dictionary that defines batch save operations. This can be used to save the file content or the\n        output of the operations in `f` to a related database model collection.\n\n        ",
          "endpoint": "/api/campaign_file/<int:fid>/data",
          "method": "GET"
        },
        {
          "description": "\n        Save file data to database. Use this if it is not possible to dynamically link the file using the `file_url` or\n        if the `file_url` is potentially unstable / ephemeral. This should be a multipart form post with `file`\n        parameter set to the uploaded file and all other fields as in the object definition below.\n        ",
          "endpoint": "/api/campaign_file/data",
          "method": "POST"
        }
      ],
      "hybrid_properties": [],
      "methods": [
        {
          "doc": null,
          "name": "data",
          "type": "property"
        }
      ],
      "relations": [
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "user",
          "model": "users"
        },
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "campaign",
          "model": "campaign"
        }
      ]
    },
    {
      "association_proxies": [],
      "collection": "campaigninfo",
      "columns": [
        {
          "default": null,
          "doc": "Primary key `id`",
          "foreign_key": null,
          "name": "id",
          "nullable": false,
          "primary_key": true,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "name",
          "nullable": false,
          "primary_key": false,
          "type": "String(length=80)",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "description",
          "nullable": false,
          "primary_key": false,
          "type": "Text()",
          "unique": null
        },
        {
          "default": "function",
          "doc": null,
          "foreign_key": null,
          "name": "created_at",
          "nullable": false,
          "primary_key": false,
          "type": "DateTime()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": "campaign.id",
          "name": "campaign_id",
          "nullable": false,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        }
      ],
      "description": "\n    Deprecated.\n    ",
      "endpoints": [
        {
          "description": "Create new [campaigninfo](#campaigninfo) object. Expects JSON. Fields shown in `MODEL COLUMNS` below. ",
          "endpoint": "/api/campaigninfo",
          "method": "POST",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to LOGGED IN users only",
              "name": "post_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get list of [campaigninfo](#campaigninfo) objects matching API query. See [Making API search queries](#api_query) for instructions on making search queries",
          "endpoint": "/api/campaigninfo",
          "fields": [
            "name",
            "description",
            "created_at",
            "campaign_id",
            "id"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_many_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get single [campaigninfo](#campaigninfo) object with pk field matching param `id`",
          "endpoint": "/api/campaigninfo/<id>",
          "fields": [
            "name",
            "description",
            "created_at",
            "campaign_id",
            "id"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_single_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Delete single [campaigninfo](#campaigninfo) object with pk field matching param `id`",
          "endpoint": "/api/campaigninfo/<id>",
          "method": "DELETE",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to OWNER only",
              "name": "delete_auth_preprocessor"
            }
          ]
        }
      ],
      "hybrid_properties": [],
      "methods": [],
      "relations": [
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "campaign",
          "model": "campaign"
        }
      ]
    },
    {
      "association_proxies": [],
      "collection": "datasource",
      "columns": [
        {
          "default": null,
          "doc": "Primary key `id`",
          "foreign_key": null,
          "name": "id",
          "nullable": false,
          "primary_key": true,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "name",
          "nullable": false,
          "primary_key": false,
          "type": "String(length=80)",
          "unique": true
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "campaign_search",
          "nullable": true,
          "primary_key": false,
          "type": "Text()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "datafile_pattern",
          "nullable": true,
          "primary_key": false,
          "type": "Text()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "datafile_search",
          "nullable": true,
          "primary_key": false,
          "type": "Text()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "deployment_search",
          "nullable": true,
          "primary_key": false,
          "type": "Text()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "media_pattern",
          "nullable": true,
          "primary_key": false,
          "type": "Text()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "mediadir_search",
          "nullable": true,
          "primary_key": false,
          "type": "Text()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "thumb_pattern",
          "nullable": true,
          "primary_key": false,
          "type": "Text()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "thumbdir_search",
          "nullable": true,
          "primary_key": false,
          "type": "Text()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "urlbase_browse",
          "nullable": true,
          "primary_key": false,
          "type": "Text()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "credential_key",
          "nullable": true,
          "primary_key": false,
          "type": "Text()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "datafile_operations",
          "nullable": true,
          "primary_key": false,
          "type": "JSON()",
          "unique": null
        },
        {
          "default": null,
          "doc": "Datasource plugin specific settings",
          "foreign_key": null,
          "name": "params",
          "nullable": true,
          "primary_key": false,
          "type": "JSON()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "description",
          "nullable": true,
          "primary_key": false,
          "type": "Text()",
          "unique": null
        },
        {
          "default": "True",
          "doc": "Inactive datasources can not be synced (existing data is kept)",
          "foreign_key": null,
          "name": "is_active",
          "nullable": false,
          "primary_key": false,
          "type": "Boolean()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": "datasource_type.id",
          "name": "datasource_type_id",
          "nullable": false,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": "platform.id",
          "name": "platform_id",
          "nullable": false,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": "users.id",
          "name": "user_id",
          "nullable": false,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": "function",
          "doc": null,
          "foreign_key": null,
          "name": "created_at",
          "nullable": false,
          "primary_key": false,
          "type": "DateTime()",
          "unique": null
        }
      ],
      "description": "\n    Datasource resource: the parameters that define the structure and format of the data on the\n    `Datasource Repository` and which `Datasource Plugin` to use. Each [platform](#platform) must have at least one [datasource](#datasource).\n    ",
      "endpoints": [
        {
          "description": "Create new [datasource](#datasource) object. Expects JSON. Fields shown in `MODEL COLUMNS` below. ",
          "endpoint": "/api/datasource",
          "method": "POST",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to ADMIN user only",
              "name": "assert_current_user_is_admin"
            },
            {
              "doc": "Restrict request to LOGGED IN users only",
              "name": "post_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Update single [datasource](#datasource) object with pk field matching param `id`. Expects JSON. Fields shown in `MODEL COLUMNS` below.",
          "endpoint": "/api/datasource/<id>",
          "method": "PATCH",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to ADMIN user only",
              "name": "assert_current_user_is_admin"
            },
            {
              "doc": "Admins only (any admin, not just the creator)",
              "name": "patch_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get list of [datasource](#datasource) objects matching API query. See [Making API search queries](#api_query) for instructions on making search queries",
          "endpoint": "/api/datasource",
          "fields": [
            "id",
            "name",
            "campaign_search",
            "datafile_pattern",
            "datafile_search",
            "deployment_search",
            "media_pattern",
            "mediadir_search",
            "thumb_pattern",
            "thumbdir_search",
            "urlbase_browse",
            "datafile_operations",
            "datasource_type",
            "datasource_type.id",
            "datasource_type.name",
            "platform",
            "platform.id",
            "platform.name",
            "user_id",
            "created_at",
            "credential_key",
            "params",
            "description",
            "is_active",
            "current_user_is_custodian",
            "current_user_can_view",
            "plugin_info"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_many_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get single [datasource](#datasource) object with pk field matching param `id`",
          "endpoint": "/api/datasource/<id>",
          "fields": [
            "id",
            "name",
            "campaign_search",
            "datafile_pattern",
            "datafile_search",
            "deployment_search",
            "media_pattern",
            "mediadir_search",
            "thumb_pattern",
            "thumbdir_search",
            "urlbase_browse",
            "datafile_operations",
            "datasource_type",
            "datasource_type.id",
            "datasource_type.name",
            "platform",
            "platform.id",
            "platform.name",
            "user_id",
            "created_at",
            "credential_key",
            "params",
            "description",
            "is_active",
            "current_user_is_custodian",
            "current_user_can_view",
            "plugin_info"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_single_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Delete single [datasource](#datasource) object with pk field matching param `id`",
          "endpoint": "/api/datasource/<id>",
          "method": "DELETE",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to ADMIN user only",
              "name": "assert_current_user_is_admin"
            },
            {
              "doc": "Admins only. Deleting a datasource deletes all its deployments: if any have labelled annotations, the admin\n        must also be a custodian of the datasource and confirm with `?confirm=<datasource name>`",
              "name": "delete_auth_preprocessor"
            }
          ]
        },
        {
          "description": "\n        List the campaigns in the datasource's repository, with their local status: `local.campaign_id` and\n        `local.deployment_count` (deployments of this datasource already imported). Admins and custodians.\n        Querystring: `upload_ids` (eg: a survey list upload), `refresh=1` to bypass the 5 minute cache.\n        ",
          "endpoint": "/api/datasource/<int:id>/remote/campaigns",
          "method": "GET"
        },
        {
          "description": "\n        List the deployments of a remote campaign (`campaign_key`), with their local status: `missing`, `imported`\n        or `invalid` (incomplete import). Admins and custodians. Querystring: `campaign_key` (required),\n        `upload_ids`, `refresh=1`.\n        ",
          "endpoint": "/api/datasource/<int:id>/remote/deployments",
          "method": "GET"
        },
        {
          "description": "\n        Dry run of the import of one deployment: resolved datafile, first `n` parsed rows and validation messages.\n        Nothing is saved. Admins and custodians. Querystring: `campaign_key`, `deployment_key`, `n` (default 20),\n        `upload_ids`.\n        ",
          "endpoint": "/api/datasource/<int:id>/remote/preview",
          "method": "GET"
        },
        {
          "description": "\n        ADMIN: test unsaved changes to the datasource definition. JSON body: any of the definition fields\n        (`urlbase_browse`, `campaign_search`, `deployment_search`, `datafile_pattern`, `datafile_search`,\n        `media_pattern`, `datafile_operations`, `params`, ...), optionally `datasource_type_id`, `campaign_key` and\n        `deployment_key` (default: the first campaign / deployment found), `upload_ids` and `n`.\n        Returns the campaigns found and a preview of one deployment. Nothing is saved.\n        ",
          "endpoint": "/api/datasource/<int:id>/sandbox",
          "method": "POST"
        },
        {
          "description": "\n        Upload a file for a sync into one of the datasource plugin's upload slots (eg: `survey_list`, or `datafile`\n        for a specific deployment). Multipart form: `file`, `slot`, and for deployment scoped slots `campaign_key`\n        and `deployment_key`. The upload is pending until used by a sync (`upload_ids`). Custodians only.\n        ",
          "endpoint": "/api/datasource/<int:id>/upload",
          "method": "POST"
        },
        {
          "description": "\n        Queue a sync job. JSON body: `scope` (datasource | campaign | deployment), `campaign_keys`,\n        `deployment_keys`, `update_existing`, `upload_ids`, `notify_emails`. Custodians only. Returns 202 with\n        `status_url` / `result_url` (compatible with sqapi's task polling). 409 if a job is already active.\n        ",
          "endpoint": "/api/datasource/<int:id>/sync",
          "method": "POST"
        }
      ],
      "hybrid_properties": [],
      "methods": [
        {
          "doc": "Whether the current user can view this datasource in the datasource manager (admins and custodians)",
          "name": "current_user_can_view",
          "type": "method"
        },
        {
          "doc": "Whether the current user is a custodian of this datasource",
          "name": "current_user_is_custodian",
          "type": "method"
        },
        {
          "doc": "Plugin of this datasource: availability, whether it is external (API push), upload slots, params schema",
          "name": "plugin_info",
          "type": "method"
        }
      ],
      "relations": [
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "datasource_type",
          "model": "datasource_type"
        },
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "platform",
          "model": "platform"
        },
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "user",
          "model": "users"
        },
        {
          "direction": "ONETOMANY",
          "doc": null,
          "key": "deployments",
          "model": "deployment"
        },
        {
          "direction": "ONETOMANY",
          "doc": null,
          "key": "custodians",
          "model": "datasource_custodian"
        },
        {
          "direction": "ONETOMANY",
          "doc": null,
          "key": "sync_jobs",
          "model": "datasource_sync_job"
        },
        {
          "direction": "ONETOMANY",
          "doc": null,
          "key": "uploads",
          "model": "datasource_upload"
        }
      ]
    },
    {
      "association_proxies": [],
      "collection": "datasource_custodian",
      "columns": [
        {
          "default": null,
          "doc": "Primary key `id`",
          "foreign_key": null,
          "name": "id",
          "nullable": false,
          "primary_key": true,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": "datasource.id",
          "name": "datasource_id",
          "nullable": false,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": "users.id",
          "name": "user_id",
          "nullable": false,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": "The admin that assigned this custodian",
          "foreign_key": "users.id",
          "name": "added_by_id",
          "nullable": true,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": "True",
          "doc": "Whether this custodian receives sync report emails",
          "foreign_key": null,
          "name": "notify_on_sync",
          "nullable": false,
          "primary_key": false,
          "type": "Boolean()",
          "unique": null
        },
        {
          "default": "function",
          "doc": null,
          "foreign_key": null,
          "name": "created_at",
          "nullable": false,
          "primary_key": false,
          "type": "DateTime()",
          "unique": null
        }
      ],
      "description": "\n    Datasource custodian resource: users that manage the datasets of a [datasource](#datasource). Only admins can\n    add or remove custodians. Custodians can only change their own `notify_on_sync`.\n    ",
      "endpoints": [
        {
          "description": "Create new [datasource_custodian](#datasource_custodian) object. Expects JSON. Fields shown in `MODEL COLUMNS` below. A simple constructor that allows initialization from kwargs.\n\n    Sets attributes on the constructed instance using the names and\n    values in ``kwargs``.\n\n    Only keys that are present as\n    attributes of the instance's class are allowed. These could be,\n    for example, any mapped columns or relationships.\n    ",
          "endpoint": "/api/datasource_custodian",
          "method": "POST",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Admins only. `user_id` and `datasource_id` are required",
              "name": "post_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Update single [datasource_custodian](#datasource_custodian) object with pk field matching param `id`. Expects JSON. Fields shown in `MODEL COLUMNS` below.",
          "endpoint": "/api/datasource_custodian/<id>",
          "method": "PATCH",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Only `notify_on_sync` can be changed: by admins, or by the custodian themselves",
              "name": "patch_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get list of [datasource_custodian](#datasource_custodian) objects matching API query. See [Making API search queries](#api_query) for instructions on making search queries",
          "endpoint": "/api/datasource_custodian",
          "fields": [
            "id",
            "datasource_id",
            "user_id",
            "user",
            "user.id",
            "user.username",
            "user.first_name",
            "user.last_name",
            "added_by_id",
            "notify_on_sync",
            "created_at"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Admins see all custodians, custodians see the custodians of their datasources",
              "name": "get_many_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get single [datasource_custodian](#datasource_custodian) object with pk field matching param `id`",
          "endpoint": "/api/datasource_custodian/<id>",
          "fields": [
            "id",
            "datasource_id",
            "user_id",
            "user",
            "user.id",
            "user.username",
            "user.first_name",
            "user.last_name",
            "added_by_id",
            "notify_on_sync",
            "created_at"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Admins and custodians of the datasource",
              "name": "get_single_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Delete single [datasource_custodian](#datasource_custodian) object with pk field matching param `id`",
          "endpoint": "/api/datasource_custodian/<id>",
          "method": "DELETE",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Admins only",
              "name": "delete_auth_preprocessor"
            }
          ]
        }
      ],
      "hybrid_properties": [],
      "methods": [],
      "relations": [
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "datasource",
          "model": "datasource"
        },
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "user",
          "model": "users"
        },
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "added_by",
          "model": "users"
        }
      ]
    },
    {
      "association_proxies": [],
      "collection": "datasource_sync_job",
      "columns": [
        {
          "default": null,
          "doc": "Primary key `id`",
          "foreign_key": null,
          "name": "id",
          "nullable": false,
          "primary_key": true,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": "datasource.id",
          "name": "datasource_id",
          "nullable": false,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": "The user that requested the sync (NULL for scheduled / command line syncs)",
          "foreign_key": "users.id",
          "name": "user_id",
          "nullable": true,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": "datasource",
          "doc": null,
          "foreign_key": null,
          "name": "scope",
          "nullable": false,
          "primary_key": false,
          "type": "String(length=20)",
          "unique": null
        },
        {
          "default": null,
          "doc": "Campaigns to sync (scope campaign/deployment)",
          "foreign_key": null,
          "name": "campaign_keys",
          "nullable": true,
          "primary_key": false,
          "type": "JSON()",
          "unique": null
        },
        {
          "default": null,
          "doc": "Deployments to sync (scope deployment)",
          "foreign_key": null,
          "name": "deployment_keys",
          "nullable": true,
          "primary_key": false,
          "type": "JSON()",
          "unique": null
        },
        {
          "default": null,
          "doc": "Sync options, eg: {update_existing: true}",
          "foreign_key": null,
          "name": "options",
          "nullable": true,
          "primary_key": false,
          "type": "JSON()",
          "unique": null
        },
        {
          "default": "queued",
          "doc": null,
          "foreign_key": null,
          "name": "status",
          "nullable": false,
          "primary_key": false,
          "type": "String(length=20)",
          "unique": null
        },
        {
          "default": "False",
          "doc": null,
          "foreign_key": null,
          "name": "cancel_requested",
          "nullable": false,
          "primary_key": false,
          "type": "Boolean()",
          "unique": null
        },
        {
          "default": null,
          "doc": "eg: {total, processed, current}",
          "foreign_key": null,
          "name": "progress",
          "nullable": true,
          "primary_key": false,
          "type": "JSON()",
          "unique": null
        },
        {
          "default": null,
          "doc": "List of per deployment results {status, campaign, deployment, message}",
          "foreign_key": null,
          "name": "results",
          "nullable": true,
          "primary_key": false,
          "type": "JSON()",
          "unique": null
        },
        {
          "default": null,
          "doc": "Summary or error message",
          "foreign_key": null,
          "name": "message",
          "nullable": true,
          "primary_key": false,
          "type": "Text()",
          "unique": null
        },
        {
          "default": null,
          "doc": "Captured plugin/importer log (truncated)",
          "foreign_key": null,
          "name": "log",
          "nullable": true,
          "primary_key": false,
          "type": "Text()",
          "unique": null
        },
        {
          "default": null,
          "doc": "Additional sync report recipients (registered users only)",
          "foreign_key": null,
          "name": "notify_emails",
          "nullable": true,
          "primary_key": false,
          "type": "JSON()",
          "unique": null
        },
        {
          "default": "function",
          "doc": null,
          "foreign_key": null,
          "name": "created_at",
          "nullable": false,
          "primary_key": false,
          "type": "DateTime()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "started_at",
          "nullable": true,
          "primary_key": false,
          "type": "DateTime()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "completed_at",
          "nullable": true,
          "primary_key": false,
          "type": "DateTime()",
          "unique": null
        },
        {
          "default": null,
          "doc": "Last worker heartbeat while running",
          "foreign_key": null,
          "name": "heartbeat_at",
          "nullable": true,
          "primary_key": false,
          "type": "DateTime()",
          "unique": null
        }
      ],
      "description": "\n    Datasource sync job resource: queued / running / completed syncs of a [datasource](#datasource) (created with\n    `POST /api/datasource/<id>/sync`). Visible to admins and the datasource's custodians.\n    ",
      "endpoints": [
        {
          "description": "Get list of [datasource_sync_job](#datasource_sync_job) objects matching API query. See [Making API search queries](#api_query) for instructions on making search queries",
          "endpoint": "/api/datasource_sync_job",
          "fields": [
            "id",
            "datasource_id",
            "user_id",
            "user",
            "user.id",
            "user.username",
            "scope",
            "campaign_keys",
            "deployment_keys",
            "options",
            "status",
            "cancel_requested",
            "progress",
            "message",
            "created_at",
            "started_at",
            "completed_at",
            "heartbeat_at"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Admins see all jobs, custodians the jobs of their datasources",
              "name": "get_many_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get single [datasource_sync_job](#datasource_sync_job) object with pk field matching param `id`",
          "endpoint": "/api/datasource_sync_job/<id>",
          "fields": [
            "id",
            "datasource_id",
            "user_id",
            "user",
            "user.id",
            "user.username",
            "scope",
            "campaign_keys",
            "deployment_keys",
            "options",
            "status",
            "cancel_requested",
            "progress",
            "message",
            "created_at",
            "started_at",
            "completed_at",
            "heartbeat_at",
            "results",
            "log",
            "notify_emails"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": null,
              "name": "get_single_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Job status in the `task_manager` polling format (used by sqapi): `status` (queued | started | done |\n        error), `progress`, `message` and `result_available`; `job_status` is the actual job status",
          "endpoint": "/api/datasource_sync_job/<int:id>/status",
          "method": "GET"
        },
        {
          "description": "Per deployment results of the job",
          "endpoint": "/api/datasource_sync_job/<int:id>/results",
          "method": "GET"
        },
        {
          "description": "Cancel a queued (immediately) or running (between deployments) job. Custodians only",
          "endpoint": "/api/datasource_sync_job/<int:id>/cancel",
          "method": "POST"
        }
      ],
      "hybrid_properties": [],
      "methods": [
        {
          "doc": null,
          "name": "is_active",
          "type": "property"
        }
      ],
      "relations": [
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "datasource",
          "model": "datasource"
        },
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "user",
          "model": "users"
        },
        {
          "direction": "ONETOMANY",
          "doc": null,
          "key": "uploads",
          "model": "datasource_upload"
        }
      ]
    },
    {
      "association_proxies": [],
      "collection": "datasource_type",
      "columns": [
        {
          "default": null,
          "doc": "Primary key `id`",
          "foreign_key": null,
          "name": "id",
          "nullable": false,
          "primary_key": true,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "name",
          "nullable": false,
          "primary_key": false,
          "type": "String(length=80)",
          "unique": true
        },
        {
          "default": "function",
          "doc": null,
          "foreign_key": null,
          "name": "created_at",
          "nullable": false,
          "primary_key": false,
          "type": "DateTime()",
          "unique": null
        },
        {
          "default": null,
          "doc": "Reference to the datasource plugin class, eg: `marinedb.datasources.plugins.httpdir:HTTPDir`",
          "foreign_key": null,
          "name": "module",
          "nullable": true,
          "primary_key": false,
          "type": "Text()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "description",
          "nullable": true,
          "primary_key": false,
          "type": "Text()",
          "unique": null
        },
        {
          "default": "True",
          "doc": "Datasources of a disabled type can not be synced",
          "foreign_key": null,
          "name": "is_enabled",
          "nullable": false,
          "primary_key": false,
          "type": "Boolean()",
          "unique": null
        }
      ],
      "description": "\n    Datasource Type resource: defines mapping to a datasource plugin (`module`, eg:\n    `marinedb.datasources.plugins.httpdir:HTTPDir`). Types without a `module` are external datasources (datasets are\n    pushed through the API). Admins can create and edit types; a `module` is test loaded when saved.\n    ",
      "endpoints": [
        {
          "description": "Create new [datasource_type](#datasource_type) object. Expects JSON. Fields shown in `MODEL COLUMNS` below. A simple constructor that allows initialization from kwargs.\n\n    Sets attributes on the constructed instance using the names and\n    values in ``kwargs``.\n\n    Only keys that are present as\n    attributes of the instance's class are allowed. These could be,\n    for example, any mapped columns or relationships.\n    ",
          "endpoint": "/api/datasource_type",
          "method": "POST",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Admins only. A `module` must reference a loadable plugin (it is test loaded)",
              "name": "assert_admin_and_valid_module"
            },
            {
              "doc": "Restrict request to LOGGED IN users only",
              "name": "post_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Update single [datasource_type](#datasource_type) object with pk field matching param `id`. Expects JSON. Fields shown in `MODEL COLUMNS` below.",
          "endpoint": "/api/datasource_type/<id>",
          "method": "PATCH",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Admins only. A `module` must reference a loadable plugin (it is test loaded)",
              "name": "assert_admin_and_valid_module"
            },
            {
              "doc": "Admins only (types have no owner)",
              "name": "patch_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get list of [datasource_type](#datasource_type) objects matching API query. See [Making API search queries](#api_query) for instructions on making search queries",
          "endpoint": "/api/datasource_type",
          "fields": [
            "id",
            "name",
            "created_at",
            "module",
            "description",
            "is_enabled",
            "plugin_status"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_many_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get single [datasource_type](#datasource_type) object with pk field matching param `id`",
          "endpoint": "/api/datasource_type/<id>",
          "fields": [
            "id",
            "name",
            "created_at",
            "module",
            "description",
            "is_enabled",
            "plugin_status"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_single_auth_preprocessor"
            }
          ]
        },
        {
          "description": "ADMIN: plugins that are installed (in-tree modules and entry points), without importing them",
          "endpoint": "/api/datasource_type/discover",
          "method": "GET"
        }
      ],
      "hybrid_properties": [],
      "methods": [
        {
          "doc": "Availability of this type's plugin (`external` if it has no plugin: datasets are pushed via the API)",
          "name": "plugin_status",
          "type": "method"
        }
      ],
      "relations": [
        {
          "direction": "ONETOMANY",
          "doc": null,
          "key": "datasources",
          "model": "datasource"
        }
      ]
    },
    {
      "association_proxies": [],
      "collection": "datasource_upload",
      "columns": [
        {
          "default": null,
          "doc": "Primary key `id`",
          "foreign_key": null,
          "name": "id",
          "nullable": false,
          "primary_key": true,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": "Sequence of file operations performed at last save",
          "foreign_key": null,
          "name": "last_save",
          "nullable": true,
          "primary_key": false,
          "type": "JSON()",
          "unique": null
        },
        {
          "default": null,
          "doc": "The name of the file (optional). Defaults to `basename` of either `file_url` or the path of the uploaded file",
          "foreign_key": null,
          "name": "name",
          "nullable": false,
          "primary_key": false,
          "type": "Text()",
          "unique": false
        },
        {
          "default": null,
          "doc": "The URL of the file to be loaded dynamically (if `data` field is not set)",
          "foreign_key": null,
          "name": "file_url",
          "nullable": true,
          "primary_key": false,
          "type": "Text()",
          "unique": false
        },
        {
          "default": null,
          "doc": "The description of the file (optional)",
          "foreign_key": null,
          "name": "description",
          "nullable": true,
          "primary_key": false,
          "type": "Text()",
          "unique": null
        },
        {
          "default": null,
          "doc": "The raw file storage for the file. This is not directly accessible through the API",
          "foreign_key": null,
          "name": "_rawfiledata",
          "nullable": true,
          "primary_key": false,
          "type": "LargeBinary()",
          "unique": null
        },
        {
          "default": "False",
          "doc": "Whether or not the file is compressed or not. If so, it will be automatically decompressed upon access.",
          "foreign_key": null,
          "name": "iscompressed",
          "nullable": true,
          "primary_key": false,
          "type": "Boolean()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": "datasource.id",
          "name": "datasource_id",
          "nullable": false,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": "datasource_sync_job.id",
          "name": "job_id",
          "nullable": true,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": "The user that uploaded the file",
          "foreign_key": "users.id",
          "name": "user_id",
          "nullable": true,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": "Upload slot of the datasource plugin, eg: survey_list, datafile",
          "foreign_key": null,
          "name": "slot",
          "nullable": false,
          "primary_key": false,
          "type": "String(length=80)",
          "unique": null
        },
        {
          "default": null,
          "doc": "Campaign key (deployment scoped slots)",
          "foreign_key": null,
          "name": "campaign_key",
          "nullable": true,
          "primary_key": false,
          "type": "Text()",
          "unique": null
        },
        {
          "default": null,
          "doc": "Deployment key (deployment scoped slots)",
          "foreign_key": null,
          "name": "deployment_key",
          "nullable": true,
          "primary_key": false,
          "type": "Text()",
          "unique": null
        },
        {
          "default": "function",
          "doc": null,
          "foreign_key": null,
          "name": "created_at",
          "nullable": false,
          "primary_key": false,
          "type": "DateTime()",
          "unique": null
        }
      ],
      "description": "\n    Datasource upload resource: files uploaded for syncs (`POST /api/datasource/<id>/upload`). Pending uploads\n    (not yet used by a sync) can be deleted by custodians. File content is not returned.\n    ",
      "endpoints": [
        {
          "description": "Get list of [datasource_upload](#datasource_upload) objects matching API query. See [Making API search queries](#api_query) for instructions on making search queries",
          "endpoint": "/api/datasource_upload",
          "fields": [
            "id",
            "name",
            "datasource_id",
            "job_id",
            "user_id",
            "slot",
            "campaign_key",
            "deployment_key",
            "created_at"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": null,
              "name": "get_many_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get single [datasource_upload](#datasource_upload) object with pk field matching param `id`",
          "endpoint": "/api/datasource_upload/<id>",
          "fields": [
            "id",
            "name",
            "datasource_id",
            "job_id",
            "user_id",
            "slot",
            "campaign_key",
            "deployment_key",
            "created_at"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": null,
              "name": "get_single_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Delete single [datasource_upload](#datasource_upload) object with pk field matching param `id`",
          "endpoint": "/api/datasource_upload/<id>",
          "method": "DELETE",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Custodians, pending uploads only",
              "name": "delete_auth_preprocessor"
            }
          ]
        }
      ],
      "hybrid_properties": [],
      "methods": [
        {
          "doc": "The dict format expected by `DataSourcePlugin(uploads=[...])`",
          "name": "as_plugin_upload",
          "type": "method"
        },
        {
          "doc": null,
          "name": "data",
          "type": "property"
        },
        {
          "doc": null,
          "name": "is_pending",
          "type": "property"
        }
      ],
      "relations": [
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "datasource",
          "model": "datasource"
        },
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "job",
          "model": "datasource_sync_job"
        },
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "user",
          "model": "users"
        }
      ]
    },
    {
      "association_proxies": [],
      "collection": "deployment",
      "columns": [
        {
          "default": null,
          "doc": "Primary key `id`",
          "foreign_key": null,
          "name": "id",
          "nullable": false,
          "primary_key": true,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "name",
          "nullable": false,
          "primary_key": false,
          "type": "String(length=80)",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "key",
          "nullable": false,
          "primary_key": false,
          "type": "String(length=80)",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "path",
          "nullable": true,
          "primary_key": false,
          "type": "Text()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": "campaign.id",
          "name": "campaign_id",
          "nullable": false,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": "users.id",
          "name": "user_id",
          "nullable": false,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "description",
          "nullable": true,
          "primary_key": false,
          "type": "Text()",
          "unique": null
        },
        {
          "default": "function",
          "doc": null,
          "foreign_key": null,
          "name": "created_at",
          "nullable": false,
          "primary_key": false,
          "type": "DateTime()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": "platform.id",
          "name": "platform_id",
          "nullable": false,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": "datasource.id",
          "name": "datasource_id",
          "nullable": false,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": "True",
          "doc": null,
          "foreign_key": null,
          "name": "is_valid",
          "nullable": true,
          "primary_key": false,
          "type": "Boolean()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "geom_line",
          "nullable": true,
          "primary_key": false,
          "type": "Geometry(srid=4326, from_text='ST_GeomFromEWKT', name='geometry')",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "geom_start",
          "nullable": true,
          "primary_key": false,
          "type": "Geometry(geometry_type='POINT', srid=4326, from_text='ST_GeomFromEWKT', name='geometry')",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "geom_end",
          "nullable": true,
          "primary_key": false,
          "type": "Geometry(geometry_type='POINT', srid=4326, from_text='ST_GeomFromEWKT', name='geometry')",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "geom_centroid",
          "nullable": true,
          "primary_key": false,
          "type": "Geometry(geometry_type='POINT', srid=4326, from_text='ST_GeomFromEWKT', name='geometry')",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "dep_min",
          "nullable": true,
          "primary_key": false,
          "type": "Float()",
          "unique": false
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "dep_max",
          "nullable": true,
          "primary_key": false,
          "type": "Float()",
          "unique": false
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "alt_min",
          "nullable": true,
          "primary_key": false,
          "type": "Float()",
          "unique": false
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "alt_max",
          "nullable": true,
          "primary_key": false,
          "type": "Float()",
          "unique": false
        },
        {
          "default": "function",
          "doc": null,
          "foreign_key": null,
          "name": "timestamp_start",
          "nullable": true,
          "primary_key": false,
          "type": "DateTime()",
          "unique": null
        },
        {
          "default": "function",
          "doc": null,
          "foreign_key": null,
          "name": "timestamp_end",
          "nullable": true,
          "primary_key": false,
          "type": "DateTime()",
          "unique": null
        },
        {
          "default": "0",
          "doc": null,
          "foreign_key": null,
          "name": "pose_count",
          "nullable": true,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": "0",
          "doc": null,
          "foreign_key": null,
          "name": "media_count",
          "nullable": true,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        }
      ],
      "description": "\n    Deployment resource: a dataset containing a group of [media](#media) objects collected from an operation of the [platform](#platform), eg: a survey, transect or mission\n    ",
      "endpoints": [
        {
          "description": "Create new [deployment](#deployment) object. Expects JSON. Fields shown in `MODEL COLUMNS` below. Add user_id to post payload if not supplied",
          "endpoint": "/api/deployment",
          "method": "POST",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict to custodians of the deployment's datasource (`datasource_id`)",
              "name": "post_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Update single [deployment](#deployment) object with pk field matching param `id`. Expects JSON. Fields shown in `MODEL COLUMNS` below.",
          "endpoint": "/api/deployment/<id>",
          "method": "PATCH",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict to custodians of the deployment's datasource",
              "name": "patch_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get list of [deployment](#deployment) objects matching API query. See [Making API search queries](#api_query) for instructions on making search queries",
          "endpoint": "/api/deployment",
          "fields": [
            "name",
            "key",
            "id",
            "created_at",
            "campaign",
            "campaign.id",
            "campaign.name",
            "platform",
            "platform.id",
            "platform.name",
            "is_valid",
            "dep_max",
            "alt_min",
            "media_count",
            "dep_min",
            "alt_max",
            "pose_count",
            "timestamp_end",
            "timestamp_start",
            "color",
            "pose"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_many_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get single [deployment](#deployment) object with pk field matching param `id`",
          "endpoint": "/api/deployment/<id>",
          "fields": [
            "name",
            "key",
            "id",
            "created_at",
            "campaign",
            "campaign.id",
            "campaign.name",
            "platform",
            "platform.id",
            "platform.name",
            "is_valid",
            "dep_max",
            "alt_min",
            "media_count",
            "dep_min",
            "alt_max",
            "pose_count",
            "timestamp_end",
            "timestamp_start",
            "color",
            "pose",
            "user_id",
            "created_at",
            "description",
            "campaign.key",
            "platform",
            "platform.id",
            "platform.name",
            "platform.key",
            "files",
            "files.id",
            "files.name",
            "files.file_url",
            "media_count",
            "pose_stats",
            "layers",
            "total_annotation_count",
            "public_annotation_count",
            "annotated_media_count",
            "extent"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_single_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Delete single [deployment](#deployment) object with pk field matching param `id`",
          "endpoint": "/api/deployment/<id>",
          "method": "DELETE",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict to custodians of the deployment's datasource. Deployments with labelled annotations can only be\n        deleted by custodians that are admins, with `?confirm=<deployment key>`",
              "name": "delete_auth_preprocessor"
            }
          ]
        },
        {
          "description": "\n        Deployment resource\n\n        Minimal Deployment Resource for map data - result is cached for fast loading. Cache is cleared when new deployments are saved.\n\n        :param GET: json: q: restless search query.\n        :returns GET: json: a json string containing the structure of stuff\n        ",
          "endpoint": "/api/deployment/map",
          "method": "GET"
        },
        {
          "description": "\n        Deployment resource\n\n        Fast approximate spatial extent of matching deployments, computed from the cached deployment geometries\n        instead of aggregating poses. Deployments without cached geometries are ignored.\n\n        :param GET: json: q: restless search query.\n        :param GET: geom: `line` (default) for the extent of the full deployment tracks, or `start` for the extent of\n            the deployment start positions (as shown by map markers, and not affected by outlier positions mid-track)\n        :returns GET: json: `lat_min`, `lat_max`, `lon_min`, `lon_max` (null if nothing matches) and `count` (number of\n            matching deployments with a cached geometry)\n        ",
          "endpoint": "/api/deployment/extent",
          "method": "GET"
        },
        {
          "description": "\n        Export [media](#media) from [deployment](#deployment) matching `id`. Additional filters on the\n        [media](#media) can be set in `q` (eg: only media items with logged events).\n        \n        Export [media](#media) matching query defined in `q`.\n        Search queries are executed on the [media](#media) model. \n\n        \n        Querystring parameters are:\n\n        ```?q={...}&f={...}&disposition=...&template=...&include_columns=[...]```\n\n        Where `q` is a JSON search query (see [Making API search queries](#api_query)) on the collection model,\n        where `f` is a JSON dictionary containing a sequence of operations for transforming the data\n        (see [Data transformation API](#api_data_transform) for more info),\n        `disposition` defines the download type which can be `attachment` (default, triggers a download) or `inline` (displays in\n        the browser),\n        `template` is optional depending on the output of the steps in `f` and can be used to define the export format,\n        `include_columns` is a JSON list of column fields for the exported model.\n        Nested fields for related models delimited with a `.`\n        If `include_columns` is omitted, all allowed columns will be returned (or the exporter's `default_columns`, if\n        it defines them).\n\n        Metadata for the dataset is also returned in the response. Depending on the output\n        format, this could be as part of the response body in a `metadata` field (e.g., Json) or in the response headers with the key\n        `X-Content-Metadata` (e.g., CSV or HTML).\n    \n\n        Allowed fields include:\n\n        `id`, `key`, `data`, `is_valid`,`media_type.id`,`media_type.name`, `path_best`, `timestamp_start`,\n        `timestamp_start_local`, `path_best_thm`, `pose.timestamp`, `pose.timestamp_local`, `pose.lat`, `pose.lon`,\n        `pose.alt`, `pose.dep`, `pose.data`, `pose.id`, `deployment.campaign.id`, `deployment.campaign.key`,\n        `deployment.campaign.name`, `deployment.key`, `deployment.id`, `deployment.name`,\n        `dims`, `camera_installation_id`, `camera_installation.name`, `camera_source`, `camera.key`, `camera.name`\n\n        `dims` is the resolved pixel dimensions (`{\"width\", \"height\", \"source\"}`, or `null` if unknown): the media\n        item's own measured / declared dimensions, or the default of its [camera_installation](#camera_installation)\n        (`source: \"installation\"`). `camera` is the [camera](#camera) of that installation, and\n        `camera_installation.name` its name (eg: the position of one of several units of the same camera).\n\n        See [media](#media) model columns, relations and attributes for more information on each of the included fields.\n        \n        \n\n        **EXAMPLES**\n\n        ```\n        # Export media (key, url, position) from deployment with id=285 as a CSV file\n        /api/deployment/285/export?template=dataframe.csv&include_columns=[\"key\",\"path_best\",\"pose.lat\",\"pose.lon\",\"pose.dep\"]&f={\"operations\":[{\"module\":\"pandas\",\"method\":\"json_normalize\"}]}\n\n        # Download a plain text list of image URLs (one per line, no header) to load into a download manager\n        /api/deployment/285/export?template=dataframe.txt&disposition=attachment&include_columns=[\"path_best\"]&f={\"operations\":[{\"module\":\"pandas\",\"method\":\"json_normalize\"}]}\n        ```\n        ",
          "endpoint": "/api/deployment/<int:id>/export",
          "method": "GET"
        },
        {
          "description": "\n        Export [deployments](#deployment) matching a search query (`q`), eg: the deployments matching the filters on\n        the explore page. Exports deployment metadata (one row per deployment), not the related media. To export the\n        [media](#media) for a single deployment, see the `export` endpoint for a deployment `id`.\n\n        \n        Querystring parameters are:\n\n        ```?q={...}&f={...}&disposition=...&template=...&include_columns=[...]```\n\n        Where `q` is a JSON search query (see [Making API search queries](#api_query)) on the collection model,\n        where `f` is a JSON dictionary containing a sequence of operations for transforming the data\n        (see [Data transformation API](#api_data_transform) for more info),\n        `disposition` defines the download type which can be `attachment` (default, triggers a download) or `inline` (displays in\n        the browser),\n        `template` is optional depending on the output of the steps in `f` and can be used to define the export format,\n        `include_columns` is a JSON list of column fields for the exported model.\n        Nested fields for related models delimited with a `.`\n        If `include_columns` is omitted, all allowed columns will be returned (or the exporter's `default_columns`, if\n        it defines them).\n\n        Metadata for the dataset is also returned in the response. Depending on the output\n        format, this could be as part of the response body in a `metadata` field (e.g., Json) or in the response headers with the key\n        `X-Content-Metadata` (e.g., CSV or HTML).\n    \n\n        Allowed columns include: `id`, `key`, `name`, `description`, `created_at`, `is_valid`, `timestamp_start`,\n        `timestamp_end`, `dep_min`, `dep_max`, `alt_min`, `alt_max`, `media_count`, `pose_count`, `latlon`,\n        `campaign.id`, `campaign.key`, `campaign.name`, `platform.id`, `platform.key`, `platform.name`, `user.id`,\n        `user.first_name`, `user.last_name`\n\n        **EXAMPLES**\n\n        ```\n        # Export valid deployments in campaign with id=27 as a CSV file\n        /api/deployment/export?template=dataframe.csv&q={\"filters\":[{\"name\":\"is_valid\",\"op\":\"eq\",\"val\":true},{\"name\":\"campaign_id\",\"op\":\"in\",\"val\":[27]}]}&f={\"operations\":[{\"module\":\"pandas\",\"method\":\"json_normalize\"}]}\n        ```\n        ",
          "endpoint": "/api/deployment/export",
          "method": "GET"
        },
        {
          "description": "Finalise the deployment setting `is_valid=True` and computing cached `pose` metrics and 'geo' properties",
          "endpoint": "/api/deployment/<int:id>/finalise",
          "method": "PATCH"
        },
        {
          "description": "Whether the current user can delete this deployment, and what would be deleted (labelled annotations,\n        annotation sets and their owners). Pass `?confirm=<deployment key>` to check a confirmed deletion.",
          "endpoint": "/api/deployment/<int:id>/delete_check",
          "method": "GET"
        },
        {
          "description": "\n        Get ecoregion info from ESRI API Marine Ecoregions Of the World (MEOW) feature layer. Uses `latlon` of deployment to\n        determine the relevant ecoregion. Accepts querystring parameter: `fields` which is a comma-separated list\n        of properties to return, which can be a subset of:\n        `fields = FID, ECO_CODE, ECOREGION, PROV_CODE, PROVINCE, RLM_CODE, REALM, ALT_CODE, ECO_CODE_X, Lat_Zone, Shape__Area, Shape__Length`\n        if not set, it will default to `fields=*`, which will return all properties.\n        ",
          "endpoint": "/api/deployment/<int:id>/ecoregion",
          "method": "GET"
        },
        {
          "description": "\n        Assign the media of this deployment to the camera installations of its platform, by pattern (see\n        [camera_installation](#camera_installation)). Manual assignments are kept, unless `reset_manual=true` (URL or\n        JSON parameter), which first clears them. Custodians of the deployment's datasource only. Use this after\n        adding media through the API (imports run it automatically). Returns `{\"assigned\": <n>, \"cleared\": <n>}`.\n        ",
          "endpoint": "/api/deployment/<int:id>/assign_cameras",
          "method": "POST"
        }
      ],
      "hybrid_properties": [
        {
          "args": [],
          "doc": "Number of [media](#media) objects with one or more labeled [annotations](#annotation) in this `deployment`",
          "name": "annotated_media_count",
          "type": "property"
        },
        {
          "args": [],
          "doc": "The centroid `geom` point of all the [poses](#pose) contained in this `deployment`",
          "name": "geom",
          "type": "property"
        },
        {
          "args": [],
          "doc": "A `timestamp` from the [poses](#pose) contained in this `deployment`",
          "name": "timestamp",
          "type": "property"
        },
        {
          "args": [],
          "doc": "Fetch total annotation count from the materialized view.",
          "name": "total_annotation_count",
          "type": "property"
        },
        {
          "args": [],
          "doc": "Fetch public annotation count from the materialized view.",
          "name": "public_annotation_count",
          "type": "property"
        }
      ],
      "methods": [
        {
          "doc": null,
          "name": "color",
          "type": "method"
        },
        {
          "doc": "\n        Compute spatial extent of Campaign\n        :return: list with format [[SW_LAT, SW_LON],[NE_LAT,NE_LON]]\n        ",
          "name": "extent",
          "type": "method"
        },
        {
          "doc": null,
          "name": "layers",
          "type": "method"
        },
        {
          "doc": null,
          "name": "pose_stats",
          "type": "method"
        },
        {
          "doc": null,
          "name": "timestamp_range",
          "type": "method"
        },
        {
          "doc": "Whether the current user can edit this deployment (custodian of its datasource). NOTE: a property, as\n        `SaveCollectionMixin.get_relation_collection` reads it without calling it",
          "name": "current_user_can_edit",
          "type": "property"
        },
        {
          "doc": null,
          "name": "latlon",
          "type": "property"
        },
        {
          "doc": null,
          "name": "pose",
          "type": "property"
        }
      ],
      "relations": [
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "campaign",
          "model": "campaign"
        },
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "user",
          "model": "users"
        },
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "platform",
          "model": "platform"
        },
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "datasource",
          "model": "datasource"
        },
        {
          "direction": "ONETOMANY",
          "doc": null,
          "key": "media",
          "model": "media"
        },
        {
          "direction": "ONETOMANY",
          "doc": null,
          "key": "events",
          "model": "deployment_event"
        },
        {
          "direction": "ONETOMANY",
          "doc": null,
          "key": "files",
          "model": "deployment_file"
        }
      ]
    },
    {
      "association_proxies": [],
      "collection": "deployment_event",
      "columns": [
        {
          "default": null,
          "doc": "Primary key `id`",
          "foreign_key": null,
          "name": "id",
          "nullable": false,
          "primary_key": true,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "description",
          "nullable": false,
          "primary_key": false,
          "type": "Text()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": "users.id",
          "name": "user_id",
          "nullable": false,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": "function",
          "doc": null,
          "foreign_key": null,
          "name": "created_at",
          "nullable": false,
          "primary_key": false,
          "type": "DateTime()",
          "unique": null
        },
        {
          "default": "function",
          "doc": null,
          "foreign_key": null,
          "name": "timestamp",
          "nullable": false,
          "primary_key": false,
          "type": "DateTime()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": "pose.id",
          "name": "pose_id",
          "nullable": true,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": "media.id",
          "name": "media_id",
          "nullable": true,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": "deployment_event_type.id",
          "name": "deployment_event_type_id",
          "nullable": false,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": "deployment.id",
          "name": "deployment_id",
          "nullable": false,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        }
      ],
      "description": "\n    Deployment Event resource: a freeform text log that can be associated with a [pose](#pose) and/or a [media](#media) object.\n    ",
      "endpoints": [
        {
          "description": "Create new [deployment_event](#deployment_event) object. Expects JSON. Fields shown in `MODEL COLUMNS` below. A simple constructor that allows initialization from kwargs.\n\n    Sets attributes on the constructed instance using the names and\n    values in ``kwargs``.\n\n    Only keys that are present as\n    attributes of the instance's class are allowed. These could be,\n    for example, any mapped columns or relationships.\n    ",
          "endpoint": "/api/deployment_event",
          "method": "POST",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to LOGGED IN users only",
              "name": "post_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Update single [deployment_event](#deployment_event) object with pk field matching param `id`. Expects JSON. Fields shown in `MODEL COLUMNS` below.",
          "endpoint": "/api/deployment_event/<id>",
          "method": "PATCH",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to OWNER only",
              "name": "patch_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get list of [deployment_event](#deployment_event) objects matching API query. See [Making API search queries](#api_query) for instructions on making search queries",
          "endpoint": "/api/deployment_event",
          "fields": [
            "media",
            "media.id",
            "media.key",
            "media.path_best",
            "media.path_best_thm",
            "user_id",
            "description",
            "timestamp",
            "created_at",
            "pose",
            "pose.lat",
            "pose.lon",
            "pose.alt",
            "pose.dep",
            "pose.timestamp",
            "deployment",
            "deployment.name",
            "deployment.key",
            "deployment.id",
            "deployment.created_at",
            "deployment.campaign_id",
            "deployment_event_type",
            "user",
            "user.username",
            "user.info",
            "user.first_name",
            "user.last_name",
            "user.email",
            "user.id",
            "deployment_event_type_id",
            "media_id",
            "deployment_id",
            "id"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_many_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get single [deployment_event](#deployment_event) object with pk field matching param `id`",
          "endpoint": "/api/deployment_event/<id>",
          "fields": [
            "media",
            "media.id",
            "media.key",
            "media.path_best",
            "media.path_best_thm",
            "user_id",
            "description",
            "timestamp",
            "created_at",
            "pose",
            "pose.lat",
            "pose.lon",
            "pose.alt",
            "pose.dep",
            "pose.timestamp",
            "deployment",
            "deployment.name",
            "deployment.key",
            "deployment.id",
            "deployment.created_at",
            "deployment.campaign_id",
            "deployment_event_type",
            "user",
            "user.username",
            "user.info",
            "user.first_name",
            "user.last_name",
            "user.email",
            "user.id",
            "deployment_event_type_id",
            "media_id",
            "deployment_id",
            "id"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_single_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Delete single [deployment_event](#deployment_event) object with pk field matching param `id`",
          "endpoint": "/api/deployment_event/<id>",
          "method": "DELETE",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to OWNER only",
              "name": "delete_auth_preprocessor"
            }
          ]
        }
      ],
      "hybrid_properties": [],
      "methods": [],
      "relations": [
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "user",
          "model": "users"
        },
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "pose",
          "model": "pose"
        },
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "media",
          "model": "media"
        },
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "deployment_event_type",
          "model": "deployment_event_type"
        },
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "deployment",
          "model": "deployment"
        }
      ]
    },
    {
      "association_proxies": [],
      "collection": "deployment_event_type",
      "columns": [
        {
          "default": null,
          "doc": "Primary key `id`",
          "foreign_key": null,
          "name": "id",
          "nullable": false,
          "primary_key": true,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": "{}",
          "doc": "Text field containing JSON properties for this resource",
          "foreign_key": null,
          "name": "data",
          "nullable": true,
          "primary_key": false,
          "type": "JSON()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "name",
          "nullable": false,
          "primary_key": false,
          "type": "String(length=80)",
          "unique": true
        }
      ],
      "description": "\n    Deployment Event resource: timestamped freeform text observation with optional link to [media](#media) and [pose](#pose) objects.\n    ",
      "endpoints": [
        {
          "description": "Create new [deployment_event_type](#deployment_event_type) object. Expects JSON. Fields shown in `MODEL COLUMNS` below. A simple constructor that allows initialization from kwargs.\n\n    Sets attributes on the constructed instance using the names and\n    values in ``kwargs``.\n\n    Only keys that are present as\n    attributes of the instance's class are allowed. These could be,\n    for example, any mapped columns or relationships.\n    ",
          "endpoint": "/api/deployment_event_type",
          "method": "POST",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to LOGGED IN users only",
              "name": "post_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Update single [deployment_event_type](#deployment_event_type) object with pk field matching param `id`. Expects JSON. Fields shown in `MODEL COLUMNS` below.",
          "endpoint": "/api/deployment_event_type/<id>",
          "method": "PATCH",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to OWNER only",
              "name": "patch_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get list of [deployment_event_type](#deployment_event_type) objects matching API query. See [Making API search queries](#api_query) for instructions on making search queries",
          "endpoint": "/api/deployment_event_type",
          "fields": [
            "name",
            "id",
            "data"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_many_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get single [deployment_event_type](#deployment_event_type) object with pk field matching param `id`",
          "endpoint": "/api/deployment_event_type/<id>",
          "fields": [
            "name",
            "id",
            "data"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_single_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Delete single [deployment_event_type](#deployment_event_type) object with pk field matching param `id`",
          "endpoint": "/api/deployment_event_type/<id>",
          "method": "DELETE",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to OWNER only",
              "name": "delete_auth_preprocessor"
            }
          ]
        }
      ],
      "hybrid_properties": [],
      "methods": [],
      "relations": [
        {
          "direction": "ONETOMANY",
          "doc": null,
          "key": "deployment_events",
          "model": "deployment_event"
        }
      ]
    },
    {
      "association_proxies": [],
      "collection": "deployment_file",
      "columns": [
        {
          "default": null,
          "doc": "Primary key `id`",
          "foreign_key": null,
          "name": "id",
          "nullable": false,
          "primary_key": true,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": "Sequence of file operations performed at last save",
          "foreign_key": null,
          "name": "last_save",
          "nullable": true,
          "primary_key": false,
          "type": "JSON()",
          "unique": null
        },
        {
          "default": null,
          "doc": "The name of the file (optional). Defaults to `basename` of either `file_url` or the path of the uploaded file",
          "foreign_key": null,
          "name": "name",
          "nullable": false,
          "primary_key": false,
          "type": "Text()",
          "unique": false
        },
        {
          "default": null,
          "doc": "The URL of the file to be loaded dynamically (if `data` field is not set)",
          "foreign_key": null,
          "name": "file_url",
          "nullable": true,
          "primary_key": false,
          "type": "Text()",
          "unique": false
        },
        {
          "default": null,
          "doc": "The description of the file (optional)",
          "foreign_key": null,
          "name": "description",
          "nullable": true,
          "primary_key": false,
          "type": "Text()",
          "unique": null
        },
        {
          "default": null,
          "doc": "The raw file storage for the file. This is not directly accessible through the API",
          "foreign_key": null,
          "name": "_rawfiledata",
          "nullable": true,
          "primary_key": false,
          "type": "LargeBinary()",
          "unique": null
        },
        {
          "default": "False",
          "doc": "Whether or not the file is compressed or not. If so, it will be automatically decompressed upon access.",
          "foreign_key": null,
          "name": "iscompressed",
          "nullable": true,
          "primary_key": false,
          "type": "Boolean()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": "users.id",
          "name": "user_id",
          "nullable": false,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": "deployment.id",
          "name": "deployment_id",
          "nullable": false,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": "function",
          "doc": null,
          "foreign_key": null,
          "name": "created_at",
          "nullable": false,
          "primary_key": false,
          "type": "DateTime()",
          "unique": null
        },
        {
          "default": "function",
          "doc": "Updated time (UTC)",
          "foreign_key": null,
          "name": "updated_at",
          "nullable": true,
          "primary_key": false,
          "type": "DateTime()",
          "unique": null
        }
      ],
      "description": "\n    Deployment File resource: a file associated with a [deployment](#deployment) object. Can be used for batch importing / updating\n    of [media](#media), [pose](#pose) and [pose_data](#pose_data) objects.\n    ",
      "endpoints": [
        {
          "description": "Create new [deployment_file](#deployment_file) object. Expects JSON. Fields shown in `MODEL COLUMNS` below. Add user_id to post payload if not supplied",
          "endpoint": "/api/deployment_file",
          "method": "POST",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict to custodians of the deployment's datasource",
              "name": "post_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Update single [deployment_file](#deployment_file) object with pk field matching param `id`. Expects JSON. Fields shown in `MODEL COLUMNS` below.",
          "endpoint": "/api/deployment_file/<id>",
          "method": "PATCH",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict to custodians of the deployment's datasource",
              "name": "patch_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get list of [deployment_file](#deployment_file) objects matching API query. See [Making API search queries](#api_query) for instructions on making search queries",
          "endpoint": "/api/deployment_file",
          "fields": [
            "user_id",
            "description",
            "iscompressed",
            "deployment_id",
            "file_url",
            "id",
            "name",
            "last_save"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_many_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get single [deployment_file](#deployment_file) object with pk field matching param `id`",
          "endpoint": "/api/deployment_file/<id>",
          "fields": [
            "user_id",
            "description",
            "iscompressed",
            "deployment_id",
            "file_url",
            "id",
            "name",
            "last_save"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_single_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Delete single [deployment_file](#deployment_file) object with pk field matching param `id`",
          "endpoint": "/api/deployment_file/<id>",
          "method": "DELETE",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict to custodians of the deployment's datasource",
              "name": "delete_auth_preprocessor"
            }
          ]
        },
        {
          "description": "\n        Deployment file resource. \n        Get the data for the file resource matching `fid`. This endpoint also provides options to manipulate, transform\n        and save data to the database. The querystring takes the following form:\n        ```\n        ?f={...}&save={...}&disposition=...&template=...\n        ```\n        where `f` is a JSON dictionary containing a sequence of operations for transforming the data\n        (see [Data transformation API](#api_data_transform) for more info),\n        `disposition` is optional and defines the download type which can be `inline` (default, displays in\n        the browser) or `attachment` (triggers a download) ,\n        `template` is optional depending on the output of the steps in `f` and can be used to define the export format,\n        `save` is a JSON dictionary that defines batch save operations. This can be used to save the file content or the\n        output of the operations in `f` to a related database model collection.\n\n        \n\n        **Example1:** convert CSV file into serialized, nested JSON expected for [media](#media) resource and batch save rows to the related `deployment.media` collection for this model\n        ```\n        /api/deployment_file/2/data?save={\"collection\": \"deployment.media\"}&f={\"operations\": [{\"module\": \"pandas\", \"method\": \"read_csv\", \"kwargs\": {\"parse_dates\": [\"time\"], \"skiprows\": 2, \"usecols\": [2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]}}, {\"method\": \"rename\", \"kwargs\": {\"columns\": {\"image_filename\": \"key\", \"longitude\": \"pose.lon\", \"latitude\": \"pose.lat\", \"depth_sensor\": \"pose.data.dep\", \"altitude_sensor\": \"pose.alt\", \"depth\": \"pose.dep\", \"sea_water_temperature\": \"pose.data.temp\", \"sea_water_salinity\": \"pose.data.salinity\", \"chlorophyll_concentration_in_sea_water\": \"pose.data.chlorophyll\", \"backscattering_ratio\": \"pose.data.backscater\", \"colored_dissolved_organic_matter\": \"pose.data.colored_dissolved_organic_matter\", \"time\": \"timestamp_start\", \"cluster_tag\": \"pose.data.cluster_tag\"}}}, {\"method\": \"to_dict\", \"kwargs\": {\"orient\": \"records\"}}, {\"module\": \"data\", \"method\": \"unflatten_dicts\", \"kwargs\": {}}]}\n        ```\n\n        **Example 2:** similar to above, but perform an update rather than an insert. Can optinally create missing. This is slower.\n        ```\n        /api/deployment_file/4/data?save={\"collection\": \"deployment.media\", \"update_existing\": true, \"match_on\": [\"key\"], \"create_missing\": true}&f={\"operations\": [{\"module\": \"pandas\", \"method\": \"read_csv\", \"kwargs\": {\"parse_dates\": [\"time\"], \"skiprows\": 2, \"usecols\": [2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]}}, {\"method\": \"rename\", \"kwargs\": {\"columns\": {\"image_filename\": \"key\", \"longitude\": \"pose.lon\", \"latitude\": \"pose.lat\", \"depth_sensor\": \"pose.data.dep\", \"altitude_sensor\": \"pose.alt\", \"depth\": \"pose.dep\", \"sea_water_temperature\": \"pose.data.temp\", \"sea_water_salinity\": \"pose.data.salinity\", \"chlorophyll_concentration_in_sea_water\": \"pose.data.chlorophyll\", \"backscattering_ratio\": \"pose.data.backscater\", \"colored_dissolved_organic_matter\": \"pose.data.colored_dissolved_organic_matter\", \"time\": \"timestamp_start\", \"cluster_tag\": \"pose.data.cluster_tag\"}}}, {\"method\": \"to_dict\", \"kwargs\": {\"orient\": \"records\"}}, {\"module\": \"data\", \"method\": \"unflatten_dicts\", \"kwargs\": {}}]}\n        ```\n        ",
          "endpoint": "/api/deployment_file/<int:fid>/data",
          "method": "GET"
        },
        {
          "description": "\n        Upload a file for a deployment (multipart form post with `file` and the fields of the object, incl.\n        `deployment_id`). Restricted to custodians of the deployment's datasource.\n        ",
          "endpoint": "/api/deployment_file/data",
          "method": "POST"
        }
      ],
      "hybrid_properties": [],
      "methods": [
        {
          "doc": null,
          "name": "data",
          "type": "property"
        }
      ],
      "relations": [
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "user",
          "model": "users"
        },
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "deployment",
          "model": "deployment"
        }
      ]
    },
    {
      "association_proxies": [],
      "collection": "group_dashboard",
      "columns": [
        {
          "default": null,
          "doc": "Primary key `id`",
          "foreign_key": null,
          "name": "id",
          "nullable": false,
          "primary_key": true,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": "Name of Dashboard",
          "foreign_key": null,
          "name": "name",
          "nullable": false,
          "primary_key": false,
          "type": "String(length=128)",
          "unique": null
        },
        {
          "default": "function",
          "doc": "The API resources the Dashboard works with, which also decide where it's offered: datasets (`annotation_set`, `media_collection`: on their sharing panel) and / or query resources (`deployment`, `media`, `pose`, `annotation`: on the Explore page)",
          "foreign_key": null,
          "name": "resources",
          "nullable": false,
          "primary_key": false,
          "type": "ARRAY(String(length=64))",
          "unique": null
        },
        {
          "default": "function",
          "doc": "Date this was created",
          "foreign_key": null,
          "name": "created_at",
          "nullable": true,
          "primary_key": false,
          "type": "DateTime()",
          "unique": null
        },
        {
          "default": null,
          "doc": "URL to launch the Dashboard for a dataset, with `{token}` where the signed token goes, eg: `https://bot.example.org/{token}`. Required for dataset resources",
          "foreign_key": null,
          "name": "url_base",
          "nullable": true,
          "primary_key": false,
          "type": "String(length=256)",
          "unique": null
        },
        {
          "default": null,
          "doc": "URL that receives Explore page launches (a form POST with a `token` field). Required for query resources",
          "foreign_key": null,
          "name": "explore_launch_url",
          "nullable": true,
          "primary_key": false,
          "type": "String(length=256)",
          "unique": null
        },
        {
          "default": "False",
          "doc": "Checked by an admin and offered on the Explore page to all signed-in users (not just group members). Only admins can set it",
          "foreign_key": null,
          "name": "is_featured",
          "nullable": false,
          "primary_key": false,
          "type": "Boolean()",
          "unique": null
        },
        {
          "default": null,
          "doc": "Description for this dashboard",
          "foreign_key": null,
          "name": "description",
          "nullable": true,
          "primary_key": false,
          "type": "Text()",
          "unique": null
        },
        {
          "default": "3600",
          "doc": "How long (seconds) a launch token stays valid: 60 to 86400 (24 hours). Default: 3600",
          "foreign_key": null,
          "name": "token_max_age",
          "nullable": false,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": "Optional metadata for the Dashboard (not used by SQUIDLE+)",
          "foreign_key": null,
          "name": "data",
          "nullable": true,
          "primary_key": false,
          "type": "JSON()",
          "unique": null
        },
        {
          "default": null,
          "doc": "Foreign key `id` for owner [user](#users) object",
          "foreign_key": "users.id",
          "name": "user_id",
          "nullable": false,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": "Foreign key `id` for the [group](#groups) that offers the Dashboard",
          "foreign_key": "groups.id",
          "name": "group_id",
          "nullable": false,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": "False",
          "doc": "Whether User must be an approved member of the Group",
          "foreign_key": null,
          "name": "requires_user_is_member",
          "nullable": false,
          "primary_key": false,
          "type": "Boolean()",
          "unique": null
        },
        {
          "default": "False",
          "doc": "Whether User must be the Dataset owner",
          "foreign_key": null,
          "name": "requires_user_is_owner",
          "nullable": false,
          "primary_key": false,
          "type": "Boolean()",
          "unique": null
        },
        {
          "default": "False",
          "doc": "Whether User needs Dataset edit permission",
          "foreign_key": null,
          "name": "requires_user_can_edit",
          "nullable": false,
          "primary_key": false,
          "type": "Boolean()",
          "unique": null
        },
        {
          "default": "False",
          "doc": "Whether User can share data to Group",
          "foreign_key": null,
          "name": "requires_user_can_share_data",
          "nullable": false,
          "primary_key": false,
          "type": "Boolean()",
          "unique": null
        },
        {
          "default": "False",
          "doc": "Whether User can add members to Group",
          "foreign_key": null,
          "name": "requires_user_can_add_member",
          "nullable": false,
          "primary_key": false,
          "type": "Boolean()",
          "unique": null
        }
      ],
      "description": "\n    Group Dashboard resource. Enables sharing of dashboards through [groups](#groups). A dashboard is an external web\n    tool (eg: a machine learning model server, a visualisation or a processing service) that a group offers. Its\n    `resources` are the API resources it works with, which also decide where it's offered:\n\n    - **datasets** (`annotation_set`, `media_collection`): when a dataset of one of those types is shared with the\n      dashboard's group, the dashboard is listed on the dataset's sharing panel (**Connect to Dashboard(s)**) and from\n      the dataset's `dashboards` endpoint (eg: `/api/annotation_set/<id>/dashboards`), and opened at `url_base`.\n    - **query resources** (`deployment`, `media`, `pose`, `annotation`): the dashboard is offered on the Explore page\n      (`/api/group_dashboard/explore`) to approved members of its group, or to all signed-in users if it's featured\n      (`is_featured`, set by admins). It's launched with a form POST to `explore_launch_url`, and gets the user's\n      Explore filters and a query for each of its query resources (see the `launch` endpoint).\n\n    Group custodians manage them on the group's **Dashboards** tab.\n\n    **LAUNCHING AND THE TOKEN**\n\n    When a signed-in user who can view the dataset and passes the dashboard's permission tests (the `requires_*`\n    fields: every one that is `true` must pass) launches it, the dashboard is opened at `url_base` with the\n    placeholder `{token}` replaced by a signed, time-stamped token. The token encodes:\n\n    ```\n    {\"v\": 2, \"resource\": \"annotation_set\", \"id\": 1234, \"dashboard_id\": 7, \"host\": \"squidle.org\", \"user_id\": 56}\n    ```\n\n    where `v` is the payload version, `resource` and `id` identify the dataset (`resource` is the entry point it was\n    launched from), `dashboard_id` is the `id` of this dashboard (useful if the same dashboard is offered by more than\n    one group), `host` is the SQUIDLE+ host that issued the token and `user_id` is the [user](#users) who launched\n    it. The token is **signed, not encrypted**: anyone holding it can read the payload, but it can't be changed or\n    forged. It does not give access to the API. The dashboard reads the dataset with its own API token (usually a bot\n    account that is a member of the group, so it can see the datasets shared in it), and uses `user_id` to know who it\n    is working for.\n\n    Tokens also have `context` (`{\"page\": \"dataset\"}`, or `{\"page\": \"explore\", \"tab\": ...}` for Explore launches,\n    whose payload is described under the `launch` endpoint).\n\n    To check and decode a token, the dashboard calls `GET /decode_token/<token>?max_age=<seconds>` on the host that\n    issued it (no sign in needed), or `POST /decode_token` with `{\"token\": ..., \"max_age\": ...}` (JSON or form fields)\n    for long tokens such as Explore launches. It returns the payload as JSON (status `200`), `410` if the token is older than\n    `max_age` (default and maximum: 24 hours) or the dashboard's `token_max_age`, or if the dashboard has been\n    deleted, or `400` if it is not valid. Dashboards should decode the token on every request that acts for the user.\n\n    `requires_user_is_owner` and `requires_user_can_edit` test the user's permissions on the dataset;\n    `requires_user_is_member`, `requires_user_can_share_data` and `requires_user_can_add_member` test their membership\n    and permissions in the dashboard's group. Listing a dataset's dashboards needs view permission on the dataset;\n    users who are not signed in can see the dashboards of public datasets but can't launch them.\n\n    **CREATING A DASHBOARD**\n\n    Only the custodian of the group (or an admin) can add, edit or delete its dashboards; the dashboard's creator\n    (`user_id`, set to the signed-in user) can also delete it, and only admins can change `user_id`.\n    `current_user_can_manage` says whether the current user can edit it. `resources` is a list of one or more of\n    `annotation_set`, `media_collection`, `deployment`, `media`, `pose` and `annotation`. (A single `resource` value is\n    still accepted when creating or editing, for backwards compatibility, but is deprecated.) `url_base` is required\n    for dataset resources: it must start with `http://` or `https://` and contain `{token}` once, with no other curly\n    braces. `explore_launch_url` is required for query resources: an `http(s)://` URL with no curly braces.\n    `token_max_age` (seconds, 60 to 86400, default 3600) is how long a launch token stays valid. Only admins can set\n    `is_featured`; when anyone else changes a featured dashboard's `url_base` or `explore_launch_url`, it stops being\n    featured.\n\n    **EXAMPLES**\n\n    ```\n    # Create a dashboard for annotation sets and media collections shared with group 42, for members with edit\n    # permission on the dataset, with launch links valid for 15 minutes\n    POST /api/group_dashboard\n    {\"name\": \"Run a classifier\", \"description\": \"Suggest labels for the points in your annotation set\",\n     \"group_id\": 42, \"resources\": [\"annotation_set\", \"media_collection\"],\n     \"url_base\": \"https://bot.example.org/{token}\", \"token_max_age\": 900,\n     \"requires_user_is_member\": true, \"requires_user_can_edit\": true}\n\n    # List the dashboards of group 42\n    /api/group_dashboard?q={\"filters\":[{\"name\":\"group_id\",\"op\":\"eq\",\"val\":42}]}\n\n    # Dashboards available for annotation set 1234, with a launch URL (or the failed permission tests) for the\n    # current user\n    /api/annotation_set/1234/dashboards\n\n    # Launch URL of dashboard 7 for annotation set 1234 (eg: to test it)\n    /api/group_dashboard/7/launch?resource=annotation_set&id=1234\n\n    # Create a dashboard for the Explore page that works with media and annotations\n    POST /api/group_dashboard\n    {\"name\": \"Classify the selection\", \"group_id\": 42, \"resources\": [\"media\", \"annotation\"],\n     \"explore_launch_url\": \"https://bot.example.org/explore\"}\n\n    # Explore page dashboards for the current user\n    /api/group_dashboard/explore\n\n    # Decode a token received by a dashboard (accept tokens up to 1 hour old)\n    /decode_token/<token>?max_age=3600\n    ```\n\n    See the user manual (`/wiki/instructions_and_tutorials/dashboards`) for more information, and the\n    [SQBot](https://bitbucket.org/ariell/sqbot) model server for a working example of a dashboard.\n    ",
      "endpoints": [
        {
          "description": "Create new [group_dashboard](#group_dashboard) object. Expects JSON. Fields shown in `MODEL COLUMNS` below. A simple constructor that allows initialization from kwargs.\n\n    Sets attributes on the constructed instance using the names and\n    values in ``kwargs``.\n\n    Only keys that are present as\n    attributes of the instance's class are allowed. These could be,\n    for example, any mapped columns or relationships.\n    ",
          "endpoint": "/api/group_dashboard",
          "method": "POST",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Accept `resource` (a single value, used before `resources`) for backwards compatibility",
              "name": "resource_compat_preprocessor"
            },
            {
              "doc": "Restrict request to the custodian of the dashboard's group (or admin). Only admins can set `is_featured`",
              "name": "post_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Update single [group_dashboard](#group_dashboard) object with pk field matching param `id`. Expects JSON. Fields shown in `MODEL COLUMNS` below.",
          "endpoint": "/api/group_dashboard/<id>",
          "method": "PATCH",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Accept `resource` (a single value, used before `resources`) for backwards compatibility",
              "name": "resource_compat_preprocessor"
            },
            {
              "doc": "Restrict request to the custodian of the dashboard's group (or admin). Moving it to another group needs\n        custodian permission on that group too, and only admins can change its owner (`user_id`)",
              "name": "patch_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get list of [group_dashboard](#group_dashboard) objects matching API query. See [Making API search queries](#api_query) for instructions on making search queries",
          "endpoint": "/api/group_dashboard",
          "fields": [
            "id",
            "name",
            "url_base",
            "explore_launch_url",
            "description",
            "data",
            "created_at",
            "user_id",
            "group",
            "group.id",
            "group.name",
            "resources",
            "token_max_age",
            "is_featured",
            "requires_user_is_owner",
            "requires_user_is_member",
            "requires_user_can_edit",
            "requires_user_can_share_data",
            "requires_user_can_add_member",
            "current_user_can_manage"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_many_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get single [group_dashboard](#group_dashboard) object with pk field matching param `id`",
          "endpoint": "/api/group_dashboard/<id>",
          "fields": [
            "id",
            "name",
            "url_base",
            "explore_launch_url",
            "description",
            "data",
            "created_at",
            "user_id",
            "group",
            "group.id",
            "group.name",
            "resources",
            "token_max_age",
            "is_featured",
            "requires_user_is_owner",
            "requires_user_is_member",
            "requires_user_can_edit",
            "requires_user_can_share_data",
            "requires_user_can_add_member",
            "current_user_can_manage"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_single_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Delete single [group_dashboard](#group_dashboard) object with pk field matching param `id`",
          "endpoint": "/api/group_dashboard/<id>",
          "method": "DELETE",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to the custodian of the dashboard's group, the dashboard's creator (or admin)",
              "name": "delete_auth_preprocessor"
            }
          ]
        },
        {
          "description": "\n        Launch this [group_dashboard](#group_dashboard).\n\n        **GET: for a dataset.** Launch details for the current user and one dataset, given by the query parameters\n        `resource` (eg: `annotation_set`) and `id`. The dataset must be shared in the dashboard's group and the current\n        user must be able to view it. Returns `url` (or `null`) and `permission_tests`, as in the `authorized` field of\n        the dataset's `dashboards` endpoint. Used by the **Test** button on the group's Dashboards tab.\n\n        **POST: from the Explore page.** Requires sign in, and the dashboard must work with at least one query resource\n        (`deployment`, `media`, `pose`, `annotation`) and be available to the user (offered by a group they're a member\n        of, or featured). JSON body: `{\"filters\": <Explore filter state>, \"tab\": \"map|img|deployments|annotations\"}`.\n        The filters are validated (unknown keys or bad values: `400`), and the server builds a query for each of the\n        dashboard's query resources. The `annotation` query only matches annotation sets the user can view. Returns\n        `{\"url\": <explore_launch_url>, \"method\": \"POST\", \"fields\": {\"token\": <token>}}`: the page then POSTs the\n        fields to the URL as a form. `403` (with `permission_tests`) if the user can't launch it. The token's payload:\n\n        ```\n        {\"v\": 2, \"resource\": null, \"id\": null, \"dashboard_id\": 7, \"host\": \"squidle.org\", \"user_id\": 56,\n         \"context\": {\"page\": \"explore\", \"tab\": \"annotations\"}, \"resources\": [\"media\", \"annotation\"],\n         \"filters\": {...}, \"queries\": {\"media\": {\"filters\": [...], \"order_by\": [...]}, \"annotation\": {\"filters\": [...]}},\n         \"explore_url\": \"https://squidle.org/geodata/explore?filters=...\"}\n        ```\n\n        **EXAMPLES**\n\n        ```\n        # Launch URL of dashboard 7 for annotation set 1234\n        /api/group_dashboard/7/launch?resource=annotation_set&id=1234\n\n        # Launch dashboard 7 from the Explore page (POST, JSON body)\n        POST /api/group_dashboard/7/launch\n        {\"filters\": {\"campaign_ids\": [54], \"dep_max\": 50}, \"tab\": \"img\"}\n        ```\n        ",
          "endpoint": "/api/group_dashboard/<int:id>/launch",
          "method": "GET"
        },
        {
          "description": "\n        Launch this [group_dashboard](#group_dashboard).\n\n        **GET: for a dataset.** Launch details for the current user and one dataset, given by the query parameters\n        `resource` (eg: `annotation_set`) and `id`. The dataset must be shared in the dashboard's group and the current\n        user must be able to view it. Returns `url` (or `null`) and `permission_tests`, as in the `authorized` field of\n        the dataset's `dashboards` endpoint. Used by the **Test** button on the group's Dashboards tab.\n\n        **POST: from the Explore page.** Requires sign in, and the dashboard must work with at least one query resource\n        (`deployment`, `media`, `pose`, `annotation`) and be available to the user (offered by a group they're a member\n        of, or featured). JSON body: `{\"filters\": <Explore filter state>, \"tab\": \"map|img|deployments|annotations\"}`.\n        The filters are validated (unknown keys or bad values: `400`), and the server builds a query for each of the\n        dashboard's query resources. The `annotation` query only matches annotation sets the user can view. Returns\n        `{\"url\": <explore_launch_url>, \"method\": \"POST\", \"fields\": {\"token\": <token>}}`: the page then POSTs the\n        fields to the URL as a form. `403` (with `permission_tests`) if the user can't launch it. The token's payload:\n\n        ```\n        {\"v\": 2, \"resource\": null, \"id\": null, \"dashboard_id\": 7, \"host\": \"squidle.org\", \"user_id\": 56,\n         \"context\": {\"page\": \"explore\", \"tab\": \"annotations\"}, \"resources\": [\"media\", \"annotation\"],\n         \"filters\": {...}, \"queries\": {\"media\": {\"filters\": [...], \"order_by\": [...]}, \"annotation\": {\"filters\": [...]}},\n         \"explore_url\": \"https://squidle.org/geodata/explore?filters=...\"}\n        ```\n\n        **EXAMPLES**\n\n        ```\n        # Launch URL of dashboard 7 for annotation set 1234\n        /api/group_dashboard/7/launch?resource=annotation_set&id=1234\n\n        # Launch dashboard 7 from the Explore page (POST, JSON body)\n        POST /api/group_dashboard/7/launch\n        {\"filters\": {\"campaign_ids\": [54], \"dep_max\": 50}, \"tab\": \"img\"}\n        ```\n        ",
          "endpoint": "/api/group_dashboard/<int:id>/launch",
          "method": "POST"
        },
        {
          "description": "\n        Dashboards offered on the Explore page to the current user: those that work with a query resource\n        (`deployment`, `media`, `pose`, `annotation`) and are offered by a group the user is an approved member (or\n        the custodian) of, or are featured (checked by an admin and offered to all signed-in users). Featured ones\n        first. Each result includes `explore_authorized` (`can_launch` and `permission_tests`), `custodian_name` and\n        `launch_host`. Empty if not signed in. Launch one with `POST /api/group_dashboard/<id>/launch`.\n\n        **EXAMPLES**\n\n        ```\n        # Explore page dashboards for the current user\n        /api/group_dashboard/explore\n        ```\n        ",
          "endpoint": "/api/group_dashboard/explore",
          "method": "GET"
        }
      ],
      "hybrid_properties": [],
      "methods": [
        {
          "doc": "Whether the current user can edit or delete this dashboard: the group's custodian, or an admin",
          "name": "current_user_can_manage",
          "type": "method"
        },
        {
          "doc": "Name of the custodian of the dashboard's group",
          "name": "custodian_name",
          "type": "method"
        },
        {
          "doc": "Whether the current user can launch this dashboard from the Explore page (`can_launch`), with the result of\n        each test (`null` for tests that don't apply: the dataset tests don't apply on the Explore page)",
          "name": "explore_authorized",
          "type": "method"
        },
        {
          "doc": "Host that launching this dashboard goes to (eg: `bot.example.org`), from the Explore or dataset URL",
          "name": "launch_host",
          "type": "method"
        }
      ],
      "relations": [
        {
          "direction": "MANYTOONE",
          "doc": "Related owner [user](#users) object",
          "key": "user",
          "model": "users"
        },
        {
          "direction": "MANYTOONE",
          "doc": "Related [group](#groups) object",
          "key": "group",
          "model": "groups"
        }
      ]
    },
    {
      "association_proxies": [],
      "collection": "group_types",
      "columns": [
        {
          "default": null,
          "doc": "Primary key `id`",
          "foreign_key": null,
          "name": "id",
          "nullable": false,
          "primary_key": true,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "name",
          "nullable": false,
          "primary_key": false,
          "type": "String(length=128)",
          "unique": null
        }
      ],
      "description": "\n    Group Type resource.\n    ",
      "endpoints": [
        {
          "description": "Get list of [group_types](#group_types) objects matching API query. See [Making API search queries](#api_query) for instructions on making search queries",
          "endpoint": "/api/group_types",
          "fields": [],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_many_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get single [group_types](#group_types) object with pk field matching param `id`",
          "endpoint": "/api/group_types/<id>",
          "fields": [],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_single_auth_preprocessor"
            }
          ]
        }
      ],
      "hybrid_properties": [],
      "methods": [],
      "relations": []
    },
    {
      "association_proxies": [],
      "collection": "groups",
      "columns": [
        {
          "default": null,
          "doc": "Primary key `id`",
          "foreign_key": null,
          "name": "id",
          "nullable": false,
          "primary_key": true,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": "Name of Group",
          "foreign_key": null,
          "name": "name",
          "nullable": false,
          "primary_key": false,
          "type": "String(length=128)",
          "unique": null
        },
        {
          "default": "False",
          "doc": "Whether or not contents are publicly viewable",
          "foreign_key": null,
          "name": "is_public",
          "nullable": true,
          "primary_key": false,
          "type": "Boolean()",
          "unique": null
        },
        {
          "default": "True",
          "doc": "Whether or not members can see other member's datasets",
          "foreign_key": null,
          "name": "is_restricted",
          "nullable": true,
          "primary_key": false,
          "type": "Boolean()",
          "unique": null
        },
        {
          "default": "True",
          "doc": "Whether or not custodian approval is required",
          "foreign_key": null,
          "name": "requires_approval",
          "nullable": true,
          "primary_key": false,
          "type": "Boolean()",
          "unique": null
        },
        {
          "default": "False",
          "doc": "Whether or not members need to agree to Data Usage Agreement (DUA)",
          "foreign_key": null,
          "name": "requires_agreement",
          "nullable": true,
          "primary_key": false,
          "type": "Boolean()",
          "unique": null
        },
        {
          "default": null,
          "doc": "Extra information about the Group",
          "foreign_key": null,
          "name": "description",
          "nullable": true,
          "primary_key": false,
          "type": "Text()",
          "unique": null
        },
        {
          "default": null,
          "doc": "Data Usage Agreement (DUA) link. Must be an HTTP accessible, embeddable document",
          "foreign_key": null,
          "name": "dua_link",
          "nullable": true,
          "primary_key": false,
          "type": "Text()",
          "unique": null
        },
        {
          "default": null,
          "doc": "`id` of group custodian [user](#users)",
          "foreign_key": "users.id",
          "name": "user_id",
          "nullable": true,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": "`id` of related [group_type](#group_type)",
          "foreign_key": "group_types.id",
          "name": "group_type_id",
          "nullable": false,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": "Shorter description / tagline of Group",
          "foreign_key": null,
          "name": "groupinfo",
          "nullable": true,
          "primary_key": false,
          "type": "Text()",
          "unique": null
        },
        {
          "default": "function",
          "doc": "Datetime of creation",
          "foreign_key": null,
          "name": "created_at",
          "nullable": false,
          "primary_key": false,
          "type": "DateTime()",
          "unique": null
        }
      ],
      "description": "\n    Group resource: user groups for managing shared resources and permissions.\n    ",
      "endpoints": [
        {
          "description": "Create new [groups](#groups) object. Expects JSON. Fields shown in `MODEL COLUMNS` below. ",
          "endpoint": "/api/groups",
          "method": "POST",
          "postprocessors": [
            {
              "doc": null,
              "name": "post_postprocessor"
            }
          ],
          "preprocessors": [
            {
              "doc": "Handle group_type_name parameter and secure against membership/dataset tampering",
              "name": "group_data_preprocessor"
            }
          ]
        },
        {
          "description": "Update single [groups](#groups) object with pk field matching param `id`. Expects JSON. Fields shown in `MODEL COLUMNS` below.",
          "endpoint": "/api/groups/<id>",
          "method": "PATCH",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Handle group_type_name parameter and secure against membership/dataset tampering",
              "name": "group_data_preprocessor"
            },
            {
              "doc": "Restrict request to OWNER only",
              "name": "patch_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get list of [groups](#groups) objects matching API query. See [Making API search queries](#api_query) for instructions on making search queries",
          "endpoint": "/api/groups",
          "fields": [
            "id",
            "name",
            "is_public",
            "dua_link",
            "user",
            "user.id",
            "user.first_name",
            "user.last_name",
            "user.username",
            "is_restricted",
            "group_type",
            "groupinfo",
            "created_at",
            "current_user_is_edit_member",
            "current_user_is_member",
            "current_user_is_owner",
            "current_user_can_share_data",
            "current_user_can_add_member",
            "current_user_has_agreed",
            "current_user_is_pending_approval",
            "requires_agreement",
            "requires_approval",
            "member_count",
            "pending_member_count"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_many_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get single [groups](#groups) object with pk field matching param `id`",
          "endpoint": "/api/groups/<id>",
          "fields": [
            "id",
            "name",
            "is_public",
            "dua_link",
            "user",
            "user.id",
            "user.first_name",
            "user.last_name",
            "user.username",
            "is_restricted",
            "group_type",
            "groupinfo",
            "created_at",
            "current_user_is_edit_member",
            "current_user_is_member",
            "current_user_is_owner",
            "current_user_can_share_data",
            "current_user_can_add_member",
            "current_user_has_agreed",
            "current_user_is_pending_approval",
            "requires_agreement",
            "requires_approval",
            "member_count",
            "pending_member_count",
            "description",
            "dataset_counts",
            "dashboard_count"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_single_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Delete single [groups](#groups) object with pk field matching param `id`",
          "endpoint": "/api/groups/<id>",
          "method": "DELETE",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to OWNER only",
              "name": "delete_auth_preprocessor"
            }
          ]
        }
      ],
      "hybrid_properties": [
        {
          "args": [],
          "doc": "\n\n        :return:\n        ",
          "name": "current_user_is_owner",
          "type": "property"
        },
        {
          "args": [],
          "doc": "\n\n        :return:\n        ",
          "name": "current_user_is_pending_approval",
          "type": "property"
        },
        {
          "args": [],
          "doc": "\n\n        :return:\n        ",
          "name": "current_user_is_member",
          "type": "property"
        },
        {
          "args": [],
          "doc": "\n\n        :return:\n        ",
          "name": "current_user_is_edit_member",
          "type": "property"
        },
        {
          "args": [],
          "doc": "BOOL, whether current_user has permission to share",
          "name": "current_user_can_share_data",
          "type": "property"
        },
        {
          "args": [],
          "doc": "BOOL, whether current_user has permission to share",
          "name": "current_user_can_add_member",
          "type": "property"
        },
        {
          "args": [],
          "doc": "BOOL, whether current_user has permission to share",
          "name": "current_user_has_agreed",
          "type": "property"
        }
      ],
      "methods": [
        {
          "doc": "the number of dashboards offered by this group",
          "name": "dashboard_count",
          "type": "method"
        },
        {
          "doc": "the number of different datasets that are shared in this group",
          "name": "dataset_counts",
          "type": "method"
        },
        {
          "doc": null,
          "name": "member_count",
          "type": "method"
        },
        {
          "doc": null,
          "name": "pending_member_count",
          "type": "method"
        }
      ],
      "relations": [
        {
          "direction": "MANYTOONE",
          "doc": "Related [user](#users) for group custodian",
          "key": "user",
          "model": "users"
        },
        {
          "direction": "MANYTOONE",
          "doc": "related [group_type](#group_type) object",
          "key": "group_type",
          "model": "group_types"
        },
        {
          "direction": "MANYTOMANY",
          "doc": null,
          "key": "members",
          "model": "users"
        },
        {
          "direction": "ONETOMANY",
          "doc": null,
          "key": "usergroups",
          "model": "usergroups"
        },
        {
          "direction": "ONETOMANY",
          "doc": "Dashboards for this Group",
          "key": "dashboards",
          "model": "group_dashboard"
        },
        {
          "direction": "MANYTOMANY",
          "doc": null,
          "key": "shared_label_schemes",
          "model": "label_scheme"
        },
        {
          "direction": "MANYTOMANY",
          "doc": null,
          "key": "shared_annotation_sets",
          "model": "annotation_set"
        },
        {
          "direction": "MANYTOMANY",
          "doc": null,
          "key": "shared_media_collections",
          "model": "media_collection"
        }
      ]
    },
    {
      "association_proxies": [
        {
          "model": "tag",
          "name": "tags",
          "target_collection": "label_tags"
        }
      ],
      "collection": "label",
      "columns": [
        {
          "default": null,
          "doc": "Primary key `id`",
          "foreign_key": null,
          "name": "id",
          "nullable": false,
          "primary_key": true,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": "A universally unique identifier for this object",
          "foreign_key": null,
          "name": "uuid",
          "nullable": true,
          "primary_key": false,
          "type": "UUID(as_uuid=True)",
          "unique": true
        },
        {
          "default": null,
          "doc": "The name of this class label",
          "foreign_key": null,
          "name": "name",
          "nullable": false,
          "primary_key": false,
          "type": "String(length=160)",
          "unique": false
        },
        {
          "default": "function",
          "doc": "The colour of this class label (hex code, including #)",
          "foreign_key": null,
          "name": "color",
          "nullable": true,
          "primary_key": false,
          "type": "String(length=10)",
          "unique": false
        },
        {
          "default": null,
          "doc": "The `id` of the user who owns or created this class label",
          "foreign_key": "users.id",
          "name": "user_id",
          "nullable": false,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": "The `id` of the annotation scheme ([label_scheme](#label_scheme)) containing this class label",
          "foreign_key": "label_scheme.id",
          "name": "label_scheme_id",
          "nullable": false,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": "`id` of the parent class label",
          "foreign_key": "label.id",
          "name": "parent_id",
          "nullable": true,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": "False",
          "doc": "Whether this class label has been approved by the custodian",
          "foreign_key": null,
          "name": "is_approved",
          "nullable": true,
          "primary_key": false,
          "type": "Boolean()",
          "unique": null
        },
        {
          "default": "function",
          "doc": "Creation time (UTC)",
          "foreign_key": null,
          "name": "created_at",
          "nullable": true,
          "primary_key": false,
          "type": "DateTime()",
          "unique": null
        },
        {
          "default": "function",
          "doc": "Updated time (UTC)",
          "foreign_key": null,
          "name": "updated_at",
          "nullable": true,
          "primary_key": false,
          "type": "TIMESTAMP()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "origin_code",
          "nullable": true,
          "primary_key": false,
          "type": "String(length=80)",
          "unique": false
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "parent_origin_code",
          "nullable": true,
          "primary_key": false,
          "type": "String(length=80)",
          "unique": false
        }
      ],
      "description": "\n    Label resource. This defines the list of labels contained in a [label_scheme](#label_scheme) and the labels to be applied to\n    [annotation](#annotation) objects. Each label can also have suggested [tag](#tag) objects linked to it.\n    ",
      "endpoints": [
        {
          "description": "Create new [label](#label) object. Expects JSON. Fields shown in `MODEL COLUMNS` below. ",
          "endpoint": "/api/label",
          "method": "POST",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "\n        if `parent_id` is set, checks that nominated parent class label is valid, i.e.: that the `parent_id` exists,\n        is from the same annotation scheme (`label_scheme_id`) and is not a circular reference to itself (witch can break\n        things).\n        ",
              "name": "validate_preprocessor"
            },
            {
              "doc": null,
              "name": "post_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Update single [label](#label) object with pk field matching param `id`. Expects JSON. Fields shown in `MODEL COLUMNS` below.",
          "endpoint": "/api/label/<id>",
          "method": "PATCH",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "\n        if `parent_id` is set, checks that nominated parent class label is valid, i.e.: that the `parent_id` exists,\n        is from the same annotation scheme (`label_scheme_id`) and is not a circular reference to itself (witch can break\n        things).\n        ",
              "name": "validate_preprocessor"
            },
            {
              "doc": "\n        checks that the current user has permission to edit this class label.\n        ",
              "name": "patch_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get list of [label](#label) objects matching API query. See [Making API search queries](#api_query) for instructions on making search queries",
          "endpoint": "/api/label",
          "fields": [
            "user_id",
            "name",
            "color",
            "parent_id",
            "label_scheme_id",
            "id",
            "uuid",
            "is_child",
            "is_parent",
            "created_at",
            "updated_at",
            "is_approved",
            "origin_code",
            "parent_origin_code",
            "name_path",
            "lineage"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_many_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get single [label](#label) object with pk field matching param `id`",
          "endpoint": "/api/label/<id>",
          "fields": [
            "user_id",
            "name",
            "color",
            "parent_id",
            "label_scheme_id",
            "id",
            "uuid",
            "is_child",
            "is_parent",
            "created_at",
            "updated_at",
            "is_approved",
            "origin_code",
            "parent_origin_code",
            "name_path",
            "lineage",
            "info",
            "info.name",
            "info.value",
            "info.id",
            "tags",
            "tags.id",
            "tags.name",
            "label_scheme",
            "label_scheme.id",
            "label_scheme.name",
            "label_scheme.user_id",
            "parent",
            "parent.id",
            "parent.name",
            "user",
            "user.id",
            "user.username",
            "user.last_login",
            "user.first_name",
            "user.last_name",
            "user.active",
            "user.info",
            "user.role",
            "annotation_count",
            "descendant_count",
            "exemplar_annotation_sets",
            "label_scheme_custodian",
            "current_user_can_edit",
            "current_user_is_custodian"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_single_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Delete single [label](#label) object with pk field matching param `id`",
          "endpoint": "/api/label/<id>",
          "method": "DELETE",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "\n        checks that the class label does not have any children or annotations which may be orphaned by delete.\n        ",
              "name": "delete_auth_preprocessor"
            }
          ]
        },
        {
          "description": null,
          "endpoint": "/api/label/<int:id>/tag/<int:tag_id>",
          "method": "DELETE"
        },
        {
          "description": null,
          "endpoint": "/api/label/<int:id>/tag/<int:tag_id>",
          "method": "POST"
        },
        {
          "description": "\n        Get list of exemplar images for the label_scheme with the ID matching `id`. Optionally you can specify an exemplar\n        `annontation_set_id` if there are more than one for this scheme. If not `annotation_set_id` is specified.\n        All will be returned.\n        :param id:\n        :param annotation_set_id:\n        :return:\n        ",
          "endpoint": "/api/label/<int:id>/exemplars",
          "method": "GET"
        },
        {
          "description": "\n        Get list of exemplar images for the label_scheme with the ID matching `id`. Optionally you can specify an exemplar\n        `annontation_set_id` if there are more than one for this scheme. If not `annotation_set_id` is specified.\n        All will be returned.\n        :param id:\n        :param annotation_set_id:\n        :return:\n        ",
          "endpoint": "/api/label/<int:id>/exemplars/<int:annotation_set_id>",
          "method": "GET"
        },
        {
          "description": "\n        Translate the [label](#label) matching `id` to a target [label_scheme](#label_scheme). Useful for example to\n        map the classes of a model trained on one label scheme to the labels of another. To translate many labels at\n        once, use the `export` endpoint of the [label_scheme](#label_scheme) resource with the `translated.*` columns.\n        \n        The `translate` querystring parameter translates [labels](#label) to a target [label_scheme](#label_scheme).\n        It is a JSON object:\n\n        ```\n        &translate={\"target_label_scheme_id\": ..., \"vocab_registry_keys\": [...], \"match\": ..., \"mapping_override\": {...}}\n        ```\n        - `target_label_scheme_id` [required]: the `id` of the target [label_scheme](#label_scheme).\n        - `vocab_registry_keys` [optional]: the vocab registries used for semantic matching, in priority order\n          (default: `[\"worms\", \"caab\", \"catami\"]`).\n        - `match` [optional]: how to choose between several target labels that share vocab elements with a label.\n          `\"consensus\"` (default) picks the target label sharing vocab elements from the most registries, then the\n          most vocab elements, then the best ranked registry. `\"priority\"` picks a match from the first registry in\n          `vocab_registry_keys` order that has one.\n        - `mapping_override` [optional]: `{source label.id: target label.id}` overrides the translation of a label,\n          and of its descendants that have no closer match of their own.\n\n        Each label is matched by its `mapping_override`, then by `tree_traversal` (the label is in the target scheme or\n        a scheme it extends), then by `semantic` translation (shared vocab elements). If a label has no match, its\n        parent is tried, and so on up the tree. A match on the label itself always takes precedence over a match on an\n        ancestor. When several target labels match equally well, the most general one (fewest ancestors) is chosen.\n\n        The `translation_info` output describes the match as `<method>.<level>[.<vocab elements>]`:\n        - `method` is `mapping_override`, `tree_traversal` or `semantic`;\n        - `level` is `direct` (matched on the label itself) or `relative-<id>` (matched on the ancestor label with\n          that `id`);\n        - for `semantic` matches, the matched vocab elements are listed as `<registry>-<key>`, delimited by `+`.\n\n        For example: `semantic.direct.worms-217362+caab-37320000`, `semantic.relative-123.worms-217362`,\n        `tree_traversal.direct` or `mapping_override.relative-123`.\n        \n        The response contains `source` and `target` (`id`, `uuid`, `name`, `lineage_names`, `label_scheme_id` and\n        `label_scheme_name`), `translation_info` and the resolved translation `parameters` (including defaults).\n        `target` and `translation_info` are `null` if no match is found.\n\n        **EXAMPLES**\n\n        ```\n        # Translate label 1234 to label scheme 2 (with the default parameters)\n        /api/label/1234/translate?translate={\"target_label_scheme_id\": 2}\n\n        # Same, using only the worms registry and the previous registry-priority matching\n        /api/label/1234/translate?translate={\"target_label_scheme_id\": 2, \"vocab_registry_keys\": [\"worms\"], \"match\": \"priority\"}\n        ```\n        ",
          "endpoint": "/api/label/<int:id>/translate",
          "method": "GET"
        }
      ],
      "hybrid_properties": [
        {
          "args": [],
          "doc": "BOOLEAN, whether or not this class label has a parent class label",
          "name": "is_child",
          "type": "property"
        },
        {
          "args": [],
          "doc": "BOOLEAN, whether this label has one or more vocab_element mappings",
          "name": "is_mapped",
          "type": "property"
        }
      ],
      "methods": [
        {
          "doc": "Number of annotations that have been assigned with this label",
          "name": "annotation_count",
          "type": "method"
        },
        {
          "doc": "Number of direct children labels nested under this label",
          "name": "descendant_count",
          "type": "method"
        },
        {
          "doc": null,
          "name": "exemplar_annotation_sets",
          "type": "method"
        },
        {
          "doc": null,
          "name": "label_scheme_custodian",
          "type": "method"
        },
        {
          "doc": null,
          "name": "current_user_can_edit",
          "type": "property"
        },
        {
          "doc": null,
          "name": "current_user_is_custodian",
          "type": "property"
        },
        {
          "doc": null,
          "name": "name_path",
          "type": "property"
        },
        {
          "doc": "Comma-delimited names of applied tags. Can also be used to set tags using comma-delimited tags when creating annotaions",
          "name": "tag_names",
          "type": "property"
        },
        {
          "doc": "Special API property returns [label](#label) object in target label scheme.\n        Requires the `translate` query parameter (see the `translate` endpoint of the [label](#label) resource).",
          "name": "translated",
          "type": "property"
        },
        {
          "doc": "Dictionary representation of `vocab_elements` by registry key (conveniently formatted for exporting schemes)",
          "name": "vocab_registry",
          "type": "property"
        }
      ],
      "relations": [
        {
          "direction": "MANYTOONE",
          "doc": "The user who owns or created this class label",
          "key": "user",
          "model": "users"
        },
        {
          "direction": "MANYTOONE",
          "doc": "The annotation scheme containing this class label",
          "key": "label_scheme",
          "model": "label_scheme"
        },
        {
          "direction": "MANYTOONE",
          "doc": "The parent class label (linked observation)",
          "key": "parent",
          "model": "label"
        },
        {
          "direction": "MANYTOMANY",
          "doc": "A list of `vocab_elements` linked to this `label`",
          "key": "vocab_elements",
          "model": "vocab_element"
        },
        {
          "direction": "ONETOMANY",
          "doc": null,
          "key": "children",
          "model": "label"
        },
        {
          "direction": "ONETOMANY",
          "doc": null,
          "key": "label_tags",
          "model": "label_tags"
        },
        {
          "direction": "ONETOMANY",
          "doc": null,
          "key": "info",
          "model": "label_info"
        },
        {
          "direction": "ONETOMANY",
          "doc": null,
          "key": "label_vocab_element",
          "model": "label_vocab_element"
        },
        {
          "direction": "ONETOMANY",
          "doc": "List of related [annotation](#annotation) objects",
          "key": "annotations",
          "model": "annotation"
        }
      ]
    },
    {
      "association_proxies": [],
      "collection": "label_info",
      "columns": [
        {
          "default": null,
          "doc": "Primary key `id`",
          "foreign_key": null,
          "name": "id",
          "nullable": false,
          "primary_key": true,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "name",
          "nullable": false,
          "primary_key": false,
          "type": "String(length=80)",
          "unique": false
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "value",
          "nullable": true,
          "primary_key": false,
          "type": "Text()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": "label.id",
          "name": "label_id",
          "nullable": true,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        }
      ],
      "description": "\n    Label Info resource. Attaches name-value information to [label](#label) objects.\n    ",
      "endpoints": [
        {
          "description": "Create new [label_info](#label_info) object. Expects JSON. Fields shown in `MODEL COLUMNS` below. ",
          "endpoint": "/api/label_info",
          "method": "POST",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to LOGGED IN users only",
              "name": "post_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Update single [label_info](#label_info) object with pk field matching param `id`. Expects JSON. Fields shown in `MODEL COLUMNS` below.",
          "endpoint": "/api/label_info/<id>",
          "method": "PATCH",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to OWNER only",
              "name": "patch_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get list of [label_info](#label_info) objects matching API query. See [Making API search queries](#api_query) for instructions on making search queries",
          "endpoint": "/api/label_info",
          "fields": [],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_many_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get single [label_info](#label_info) object with pk field matching param `id`",
          "endpoint": "/api/label_info/<id>",
          "fields": [],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_single_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Delete single [label_info](#label_info) object with pk field matching param `id`",
          "endpoint": "/api/label_info/<id>",
          "method": "DELETE",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to OWNER only",
              "name": "delete_auth_preprocessor"
            }
          ]
        }
      ],
      "hybrid_properties": [],
      "methods": [],
      "relations": [
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "label",
          "model": "label"
        }
      ]
    },
    {
      "association_proxies": [],
      "collection": "label_scheme",
      "columns": [
        {
          "default": null,
          "doc": "Primary key `id`",
          "foreign_key": null,
          "name": "id",
          "nullable": false,
          "primary_key": true,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "name",
          "nullable": false,
          "primary_key": false,
          "type": "String(length=80)",
          "unique": false
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "description",
          "nullable": true,
          "primary_key": false,
          "type": "Text()",
          "unique": null
        },
        {
          "default": null,
          "doc": "Foreign key reference for ID of related owner [users](#users) model",
          "foreign_key": "users.id",
          "name": "user_id",
          "nullable": false,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": "False",
          "doc": null,
          "foreign_key": null,
          "name": "is_hierarchy",
          "nullable": true,
          "primary_key": false,
          "type": "Boolean()",
          "unique": null
        },
        {
          "default": "function",
          "doc": "Creation time (UTC)",
          "foreign_key": null,
          "name": "created_at",
          "nullable": true,
          "primary_key": false,
          "type": "DateTime()",
          "unique": null
        },
        {
          "default": "function",
          "doc": "Updated time (UTC)",
          "foreign_key": null,
          "name": "updated_at",
          "nullable": true,
          "primary_key": false,
          "type": "TIMESTAMP()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": "label_scheme.id",
          "name": "parent_label_scheme_id",
          "nullable": true,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        }
      ],
      "description": "\n    Label Scheme resource. This resource is for managing and define label schemes otherwise known as (annotation scheme,\n    taxonomic hierarchy, category lists, label lists, classification scheme)\n    ",
      "endpoints": [
        {
          "description": "Create new [label_scheme](#label_scheme) object. Expects JSON. Fields shown in `MODEL COLUMNS` below. ",
          "endpoint": "/api/label_scheme",
          "method": "POST",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to LOGGED IN users only",
              "name": "post_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Update single [label_scheme](#label_scheme) object with pk field matching param `id`. Expects JSON. Fields shown in `MODEL COLUMNS` below.",
          "endpoint": "/api/label_scheme/<id>",
          "method": "PATCH",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Assert object edit permission from shared `usergroups`. Checks current_user has edit permission.",
              "name": "patch_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get list of [label_scheme](#label_scheme) objects matching API query. See [Making API search queries](#api_query) for instructions on making search queries",
          "endpoint": "/api/label_scheme",
          "fields": [
            "user_id",
            "description",
            "is_hierarchy",
            "id",
            "name",
            "user",
            "user.username",
            "user.first_name",
            "user.last_name",
            "user.id",
            "label_scheme_files",
            "label_scheme_files.description",
            "label_scheme_files.file_url",
            "label_scheme_files.id",
            "label_scheme_files.name",
            "current_user_can_view",
            "current_user_is_owner",
            "current_user_is_member",
            "current_user_can_edit",
            "is_public",
            "is_child",
            "parent_label_scheme",
            "parent_label_scheme.id",
            "parent_label_scheme.name",
            "created_at",
            "updated_at",
            "usergroup_count",
            "annotation_set_count",
            "exemplar_annotation_set_count",
            "label_count"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_many_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get single [label_scheme](#label_scheme) object with pk field matching param `id`",
          "endpoint": "/api/label_scheme/<id>",
          "fields": [
            "user_id",
            "description",
            "is_hierarchy",
            "id",
            "name",
            "user",
            "user.username",
            "user.first_name",
            "user.last_name",
            "user.id",
            "label_scheme_files",
            "label_scheme_files.description",
            "label_scheme_files.file_url",
            "label_scheme_files.id",
            "label_scheme_files.name",
            "current_user_can_view",
            "current_user_is_owner",
            "current_user_is_member",
            "current_user_can_edit",
            "is_public",
            "is_child",
            "parent_label_scheme",
            "parent_label_scheme.id",
            "parent_label_scheme.name",
            "created_at",
            "updated_at",
            "usergroup_count",
            "annotation_set_count",
            "exemplar_annotation_set_count",
            "label_count",
            "parent_label_scheme_ids"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": null,
              "name": "get_single_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Delete single [label_scheme](#label_scheme) object with pk field matching param `id`",
          "endpoint": "/api/label_scheme/<id>",
          "method": "DELETE",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "\n        checks that the scheme does not contain annotation sets or children.\n        ",
              "name": "delete_preprocessor"
            },
            {
              "doc": "Assert object delete permission from shared `usergroups`. Checks current user is owner and object is not\n        shared in a `usergroup`",
              "name": "delete_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Add object with id `instance_id` to group with id `group_id`",
          "endpoint": "/api/label_scheme/<int:instance_id>/group/<int:group_id>",
          "method": "POST"
        },
        {
          "description": "Remove resource with id `instance_id` from group with id `group_id`",
          "endpoint": "/api/label_scheme/<int:instance_id>/group/<int:group_id>",
          "method": "DELETE"
        },
        {
          "description": "\n        Reset [labels](#label) parents for `label_scheme` with `id` matching `label_scheme_id`.\n        Uses `origin_code` and `parent_origin_code` to match up [labels](#label). Accepts optional query string argument\n        `replace_existing=true`, which will reset parent_ids for labels that are already set. By default this is set to `false`\n        ",
          "endpoint": "/api/label_scheme/<int:label_scheme_id>/reset_label_parents",
          "method": "PATCH"
        },
        {
          "description": "\n        Export [labels](#label) collection from [label_scheme](#label_scheme) matching `id`.\n        Search queries are executed on the [label](#label) model.\n\n        \n        Querystring parameters are:\n\n        ```?q={...}&f={...}&disposition=...&template=...&include_columns=[...]```\n\n        Where `q` is a JSON search query (see [Making API search queries](#api_query)) on the collection model,\n        where `f` is a JSON dictionary containing a sequence of operations for transforming the data\n        (see [Data transformation API](#api_data_transform) for more info),\n        `disposition` defines the download type which can be `attachment` (default, triggers a download) or `inline` (displays in\n        the browser),\n        `template` is optional depending on the output of the steps in `f` and can be used to define the export format,\n        `include_columns` is a JSON list of column fields for the exported model.\n        Nested fields for related models delimited with a `.`\n        If `include_columns` is omitted, all allowed columns will be returned (or the exporter's `default_columns`, if\n        it defines them).\n\n        Metadata for the dataset is also returned in the response. Depending on the output\n        format, this could be as part of the response body in a `metadata` field (e.g., Json) or in the response headers with the key\n        `X-Content-Metadata` (e.g., CSV or HTML).\n    \n\n        Allowed fields include:\n\n        `id`, `parent_id`, `uuid`, `name`, `color`, `user.id`, `user.full_name`, `label_scheme.id`,\n        `label_scheme.name`, `lineage_names`, `is_approved`, `tags`, `vocab_registry`,\n        `created_at`, `updated_at`, `origin_code`, `parent_origin_code`, `is_mapped`\n\n        See [label](#label) model columns, relations and attributes for more information on each of the included fields.\n\n        **TRANSLATING TO OTHER LABEL_SCHEMES**\n        \n        The `translate` querystring parameter translates [labels](#label) to a target [label_scheme](#label_scheme).\n        It is a JSON object:\n\n        ```\n        &translate={\"target_label_scheme_id\": ..., \"vocab_registry_keys\": [...], \"match\": ..., \"mapping_override\": {...}}\n        ```\n        - `target_label_scheme_id` [required]: the `id` of the target [label_scheme](#label_scheme).\n        - `vocab_registry_keys` [optional]: the vocab registries used for semantic matching, in priority order\n          (default: `[\"worms\", \"caab\", \"catami\"]`).\n        - `match` [optional]: how to choose between several target labels that share vocab elements with a label.\n          `\"consensus\"` (default) picks the target label sharing vocab elements from the most registries, then the\n          most vocab elements, then the best ranked registry. `\"priority\"` picks a match from the first registry in\n          `vocab_registry_keys` order that has one.\n        - `mapping_override` [optional]: `{source label.id: target label.id}` overrides the translation of a label,\n          and of its descendants that have no closer match of their own.\n\n        Each label is matched by its `mapping_override`, then by `tree_traversal` (the label is in the target scheme or\n        a scheme it extends), then by `semantic` translation (shared vocab elements). If a label has no match, its\n        parent is tried, and so on up the tree. A match on the label itself always takes precedence over a match on an\n        ancestor. When several target labels match equally well, the most general one (fewest ancestors) is chosen.\n\n        The `translation_info` output describes the match as `<method>.<level>[.<vocab elements>]`:\n        - `method` is `mapping_override`, `tree_traversal` or `semantic`;\n        - `level` is `direct` (matched on the label itself) or `relative-<id>` (matched on the ancestor label with\n          that `id`);\n        - for `semantic` matches, the matched vocab elements are listed as `<registry>-<key>`, delimited by `+`.\n\n        For example: `semantic.direct.worms-217362+caab-37320000`, `semantic.relative-123.worms-217362`,\n        `tree_traversal.direct` or `mapping_override.relative-123`.\n        \n        NOTE: you also need to add the `translated.*` columns to obtain the translation output. These columns are\n        ignored if no `translate` query parameter is supplied.\n\n        **EXAMPLES**\n\n        ```\n        # Example1: get all columns as an HTML table in the browser (including all labels from base scheme)\n        /api/label_scheme/7/export?template=data.html&disposition=inline\n\n        # Example2: get all columns as a downloaded CSV file (including all labels from base scheme)\n        /api/label_scheme/7/export?template=data.csv&disposition=inline\n\n        # Example3: get all columns as an HTML table in the browser, but only for labels defined in the extended scheme (not the base scheme)\n        /api/label_scheme/7/export?template=data.html&disposition=inline&q={\"filters\":[{\"name\":\"label_scheme_id\",\"op\":\"eq\",\"val\":7}]}\n\n        # Example4: get translation lookup between schemes, and only return specific columns\n        /api/label_scheme/8/export?disposition=inline&translate={\"vocab_registry_keys\":[\"worms\",\"caab\",\"catami\"],\"target_label_scheme_id\":\"7\"}\n          &include_columns=[\"label_scheme.name\",\"lineage_names\",\"name\",\"id\",\"translated.id\",\"translated.name\",\"translated.lineage_names\",\n          \"translated.translation_info\",\"translated.label_scheme.name\"]\n\n        # MORE TO COME... Need something else or an example added here, please ask...\n        ```\n        ",
          "endpoint": "/api/label_scheme/<int:label_scheme_id>/export",
          "method": "GET"
        },
        {
          "description": null,
          "endpoint": "/api/label_scheme/<int:label_scheme_id>/labels",
          "method": "GET"
        },
        {
          "description": null,
          "endpoint": "/api/label_scheme/<int:label_scheme_id>/labels/<int:label_parent_id>",
          "method": "GET"
        }
      ],
      "hybrid_properties": [
        {
          "args": [],
          "doc": "BOOLEAN, whether or not this class label has a parent class label",
          "name": "is_child",
          "type": "property"
        },
        {
          "args": [],
          "doc": "Whether or not this object is public (i.e. shared in a public group)",
          "name": "is_public",
          "type": "property"
        },
        {
          "args": [],
          "doc": "Whether the current logged in user is the owner of this object",
          "name": "current_user_is_owner",
          "type": "property"
        },
        {
          "args": [],
          "doc": "Whether the current logged in user is a member of a group that includes this object",
          "name": "current_user_is_member",
          "type": "property"
        },
        {
          "args": [],
          "doc": "Whether the current logged in user is a member with edit permission of a group that includes this object",
          "name": "current_user_is_edit_member",
          "type": "property"
        },
        {
          "args": [],
          "doc": "Whether the current logged in user is the owner of a group that includes this object",
          "name": "current_user_is_group_owner",
          "type": "property"
        },
        {
          "args": [],
          "doc": "Whether or not the current user has permission to view this object",
          "name": "current_user_can_view",
          "type": "property"
        },
        {
          "args": [],
          "doc": "Whether the current logged in user has edit permission (owner or edit_member)",
          "name": "current_user_can_edit",
          "type": "property"
        },
        {
          "args": [
            "user_id"
          ],
          "doc": "Whether the specified user is the owner of this object",
          "name": "user_is_owner",
          "type": "method"
        },
        {
          "args": [
            "user_id"
          ],
          "doc": "Whether the specified user is a member of a group that includes this object",
          "name": "user_is_member",
          "type": "method"
        },
        {
          "args": [
            "user_id"
          ],
          "doc": "Whether the specified user is a member with edit permission of a group that includes this object",
          "name": "user_is_edit_member",
          "type": "method"
        },
        {
          "args": [
            "user_id"
          ],
          "doc": "Whether the specified user is the owner of a group that includes this object",
          "name": "user_is_group_owner",
          "type": "method"
        },
        {
          "args": [
            "user_id"
          ],
          "doc": "Returns true is user is owner, dataset belongs to a public group, user owns a group or dataset belongs to an\n        unrestricted group that user is a member of",
          "name": "user_can_view",
          "type": "method"
        },
        {
          "args": [
            "user_id"
          ],
          "doc": "Whether the specified user has edit permission (owner or edit_member)",
          "name": "user_can_edit",
          "type": "method"
        }
      ],
      "methods": [
        {
          "doc": null,
          "name": "annotation_set_count",
          "type": "method"
        },
        {
          "doc": null,
          "name": "exemplar_annotation_set_count",
          "type": "method"
        },
        {
          "doc": null,
          "name": "label_count",
          "type": "method"
        },
        {
          "doc": null,
          "name": "usergroup_count",
          "type": "method"
        }
      ],
      "relations": [
        {
          "direction": "MANYTOONE",
          "doc": "Related owner [users](#users) model",
          "key": "user",
          "model": "users"
        },
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "parent_label_scheme",
          "model": "label_scheme"
        },
        {
          "direction": "ONETOMANY",
          "doc": null,
          "key": "annotation_sets",
          "model": "annotation_set"
        },
        {
          "direction": "MANYTOMANY",
          "doc": "List of [groups](#groups) objects that contain this resource",
          "key": "usergroups",
          "model": "groups"
        },
        {
          "direction": "ONETOMANY",
          "doc": null,
          "key": "label_scheme_files",
          "model": "label_scheme_file"
        },
        {
          "direction": "ONETOMANY",
          "doc": null,
          "key": "children",
          "model": "label_scheme"
        },
        {
          "direction": "ONETOMANY",
          "doc": null,
          "key": "labels",
          "model": "label"
        }
      ]
    },
    {
      "association_proxies": [],
      "collection": "label_scheme_file",
      "columns": [
        {
          "default": null,
          "doc": "Primary key `id`",
          "foreign_key": null,
          "name": "id",
          "nullable": false,
          "primary_key": true,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": "Sequence of file operations performed at last save",
          "foreign_key": null,
          "name": "last_save",
          "nullable": true,
          "primary_key": false,
          "type": "JSON()",
          "unique": null
        },
        {
          "default": null,
          "doc": "The name of the file (optional). Defaults to `basename` of either `file_url` or the path of the uploaded file",
          "foreign_key": null,
          "name": "name",
          "nullable": false,
          "primary_key": false,
          "type": "Text()",
          "unique": false
        },
        {
          "default": null,
          "doc": "The URL of the file to be loaded dynamically (if `data` field is not set)",
          "foreign_key": null,
          "name": "file_url",
          "nullable": true,
          "primary_key": false,
          "type": "Text()",
          "unique": false
        },
        {
          "default": null,
          "doc": "The description of the file (optional)",
          "foreign_key": null,
          "name": "description",
          "nullable": true,
          "primary_key": false,
          "type": "Text()",
          "unique": null
        },
        {
          "default": null,
          "doc": "The raw file storage for the file. This is not directly accessible through the API",
          "foreign_key": null,
          "name": "_rawfiledata",
          "nullable": true,
          "primary_key": false,
          "type": "LargeBinary()",
          "unique": null
        },
        {
          "default": "False",
          "doc": "Whether or not the file is compressed or not. If so, it will be automatically decompressed upon access.",
          "foreign_key": null,
          "name": "iscompressed",
          "nullable": true,
          "primary_key": false,
          "type": "Boolean()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": "label_scheme.id",
          "name": "label_scheme_id",
          "nullable": false,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        }
      ],
      "description": "\n    Label Scheme File resource. Files that can be used for batch update / creation of [label](#label) objects attached\n    to [label_scheme](#label_scheme) objects.\n    ",
      "endpoints": [
        {
          "description": "Create new [label_scheme_file](#label_scheme_file) object. Expects JSON. Fields shown in `MODEL COLUMNS` below. ",
          "endpoint": "/api/label_scheme_file",
          "method": "POST",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to LOGGED IN users only",
              "name": "post_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Update single [label_scheme_file](#label_scheme_file) object with pk field matching param `id`. Expects JSON. Fields shown in `MODEL COLUMNS` below.",
          "endpoint": "/api/label_scheme_file/<id>",
          "method": "PATCH",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to OWNER only",
              "name": "patch_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get list of [label_scheme_file](#label_scheme_file) objects matching API query. See [Making API search queries](#api_query) for instructions on making search queries",
          "endpoint": "/api/label_scheme_file",
          "fields": [
            "description",
            "iscompressed",
            "label_scheme",
            "file_url",
            "label_scheme_id",
            "id",
            "name",
            "last_save"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_many_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get single [label_scheme_file](#label_scheme_file) object with pk field matching param `id`",
          "endpoint": "/api/label_scheme_file/<id>",
          "fields": [
            "description",
            "iscompressed",
            "label_scheme",
            "file_url",
            "label_scheme_id",
            "id",
            "name",
            "last_save",
            "current_user_can_edit",
            "stored_size"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_single_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Delete single [label_scheme_file](#label_scheme_file) object with pk field matching param `id`",
          "endpoint": "/api/label_scheme_file/<id>",
          "method": "DELETE",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to users with edit rights to the parent label_scheme (files have no owner of their own)",
              "name": "delete_auth_preprocessor"
            }
          ]
        },
        {
          "description": "\n        Get the data for the file resource matching `fid`. This endpoint also provides options to manipulate, transform\n        and save data to the database. The querystring takes the following form:\n        ```\n        ?f={...}&save={...}&disposition=...&template=...\n        ```\n        where `f` is a JSON dictionary containing a sequence of operations for transforming the data\n        (see [Data transformation API](#api_data_transform) for more info),\n        `disposition` is optional and defines the download type which can be `inline` (default, displays in\n        the browser) or `attachment` (triggers a download) ,\n        `template` is optional depending on the output of the steps in `f` and can be used to define the export format,\n        `save` is a JSON dictionary that defines batch save operations. This can be used to save the file content or the\n        output of the operations in `f` to a related database model collection.\n\n        ",
          "endpoint": "/api/label_scheme_file/<int:fid>/data",
          "method": "GET"
        },
        {
          "description": "\n        Save file data to database. Use this if it is not possible to dynamically link the file using the `file_url` or\n        if the `file_url` is potentially unstable / ephemeral. This should be a multipart form post with `file`\n        parameter set to the uploaded file and all other fields as in the object definition below.\n        ",
          "endpoint": "/api/label_scheme_file/data",
          "method": "POST"
        }
      ],
      "hybrid_properties": [],
      "methods": [
        {
          "doc": "BOOLEAN, whether the current user has edit rights to the parent [label_scheme](#label_scheme)",
          "name": "current_user_can_edit",
          "type": "method"
        },
        {
          "doc": "Size (bytes) of the file data stored in the database, or null if the file is linked by `file_url`",
          "name": "stored_size",
          "type": "method"
        },
        {
          "doc": null,
          "name": "data",
          "type": "property"
        }
      ],
      "relations": [
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "label_scheme",
          "model": "label_scheme"
        }
      ]
    },
    {
      "association_proxies": [],
      "collection": "label_tags",
      "columns": [
        {
          "default": null,
          "doc": null,
          "foreign_key": "label.id",
          "name": "label_id",
          "nullable": false,
          "primary_key": true,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": "tag.id",
          "name": "tag_id",
          "nullable": false,
          "primary_key": true,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": "function",
          "doc": null,
          "foreign_key": null,
          "name": "assoc_created_at",
          "nullable": true,
          "primary_key": false,
          "type": "DateTime()",
          "unique": null
        }
      ],
      "description": "\n    Label tag associations. Links suggested [tag](#tag) objects to [label](#label) objects. Provides convenience for quickly\n    assigning tags to certain labels\n    ",
      "endpoints": [
        {
          "description": "Create new [label_tags](#label_tags) object. Expects JSON. Fields shown in `MODEL COLUMNS` below. A simple constructor that allows initialization from kwargs.\n\n    Sets attributes on the constructed instance using the names and\n    values in ``kwargs``.\n\n    Only keys that are present as\n    attributes of the instance's class are allowed. These could be,\n    for example, any mapped columns or relationships.\n    ",
          "endpoint": "/api/label_tags",
          "method": "POST",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to LOGGED IN users only",
              "name": "post_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Update single [label_tags](#label_tags) object with pk field matching param `label_id`. Expects JSON. Fields shown in `MODEL COLUMNS` below.",
          "endpoint": "/api/label_tags/<label_id>",
          "method": "PATCH",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to OWNER only",
              "name": "patch_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get list of [label_tags](#label_tags) objects matching API query. See [Making API search queries](#api_query) for instructions on making search queries",
          "endpoint": "/api/label_tags",
          "fields": [],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_many_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get single [label_tags](#label_tags) object with pk field matching param `label_id`",
          "endpoint": "/api/label_tags/<label_id>",
          "fields": [],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_single_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Delete single [label_tags](#label_tags) object with pk field matching param `label_id`",
          "endpoint": "/api/label_tags/<label_id>",
          "method": "DELETE",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to OWNER only",
              "name": "delete_auth_preprocessor"
            }
          ]
        }
      ],
      "hybrid_properties": [],
      "methods": [],
      "relations": [
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "label",
          "model": "label"
        },
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "tag",
          "model": "tag"
        }
      ]
    },
    {
      "association_proxies": [],
      "collection": "maplayer",
      "columns": [
        {
          "default": null,
          "doc": "Primary key `id`",
          "foreign_key": null,
          "name": "id",
          "nullable": false,
          "primary_key": true,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "name",
          "nullable": false,
          "primary_key": false,
          "type": "String(length=255)",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "baseurl",
          "nullable": false,
          "primary_key": false,
          "type": "String(length=255)",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "layertype",
          "nullable": false,
          "primary_key": false,
          "type": "String(length=128)",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "properties",
          "nullable": true,
          "primary_key": false,
          "type": "JSON(astext_type=Text())",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "filters",
          "nullable": true,
          "primary_key": false,
          "type": "JSON(astext_type=Text())",
          "unique": null
        },
        {
          "default": "False",
          "doc": null,
          "foreign_key": null,
          "name": "is_active",
          "nullable": true,
          "primary_key": false,
          "type": "Boolean()",
          "unique": null
        },
        {
          "default": "False",
          "doc": null,
          "foreign_key": null,
          "name": "disabled",
          "nullable": true,
          "primary_key": false,
          "type": "Boolean()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": "maplayer_group.id",
          "name": "maplayer_group_id",
          "nullable": false,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        }
      ],
      "description": "\n    Map Layer resource: defines properties of additional map layers for integration into explore interface\n    ",
      "endpoints": [
        {
          "description": "Create new [maplayer](#maplayer) object. Expects JSON. Fields shown in `MODEL COLUMNS` below. A simple constructor that allows initialization from kwargs.\n\n    Sets attributes on the constructed instance using the names and\n    values in ``kwargs``.\n\n    Only keys that are present as\n    attributes of the instance's class are allowed. These could be,\n    for example, any mapped columns or relationships.\n    ",
          "endpoint": "/api/maplayer",
          "method": "POST",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to ADMIN user only",
              "name": "assert_current_user_is_admin"
            },
            {
              "doc": "Restrict request to LOGGED IN users only",
              "name": "post_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Update single [maplayer](#maplayer) object with pk field matching param `id`. Expects JSON. Fields shown in `MODEL COLUMNS` below.",
          "endpoint": "/api/maplayer/<id>",
          "method": "PATCH",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to ADMIN user only",
              "name": "assert_current_user_is_admin"
            },
            {
              "doc": "Restrict request to OWNER only",
              "name": "patch_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get list of [maplayer](#maplayer) objects matching API query. See [Making API search queries](#api_query) for instructions on making search queries",
          "endpoint": "/api/maplayer",
          "fields": [],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_many_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get single [maplayer](#maplayer) object with pk field matching param `id`",
          "endpoint": "/api/maplayer/<id>",
          "fields": [],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_single_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Delete single [maplayer](#maplayer) object with pk field matching param `id`",
          "endpoint": "/api/maplayer/<id>",
          "method": "DELETE",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to ADMIN user only",
              "name": "assert_current_user_is_admin"
            },
            {
              "doc": "Restrict request to OWNER only",
              "name": "delete_auth_preprocessor"
            }
          ]
        }
      ],
      "hybrid_properties": [],
      "methods": [],
      "relations": [
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "maplayer_group",
          "model": "maplayer_group"
        }
      ]
    },
    {
      "association_proxies": [],
      "collection": "maplayer_group",
      "columns": [
        {
          "default": null,
          "doc": "Primary key `id`",
          "foreign_key": null,
          "name": "id",
          "nullable": false,
          "primary_key": true,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "name",
          "nullable": false,
          "primary_key": false,
          "type": "String(length=255)",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "pane",
          "nullable": true,
          "primary_key": false,
          "type": "String(length=255)",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "zindex",
          "nullable": false,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        }
      ],
      "description": "\n    Map Layer Group resource: defines properties of additional map layer groups for integration into explore interface\n    ",
      "endpoints": [
        {
          "description": "Create new [maplayer_group](#maplayer_group) object. Expects JSON. Fields shown in `MODEL COLUMNS` below. A simple constructor that allows initialization from kwargs.\n\n    Sets attributes on the constructed instance using the names and\n    values in ``kwargs``.\n\n    Only keys that are present as\n    attributes of the instance's class are allowed. These could be,\n    for example, any mapped columns or relationships.\n    ",
          "endpoint": "/api/maplayer_group",
          "method": "POST",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to ADMIN user only",
              "name": "assert_current_user_is_admin"
            },
            {
              "doc": "Restrict request to LOGGED IN users only",
              "name": "post_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Update single [maplayer_group](#maplayer_group) object with pk field matching param `id`. Expects JSON. Fields shown in `MODEL COLUMNS` below.",
          "endpoint": "/api/maplayer_group/<id>",
          "method": "PATCH",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to ADMIN user only",
              "name": "assert_current_user_is_admin"
            },
            {
              "doc": "Restrict request to OWNER only",
              "name": "patch_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get list of [maplayer_group](#maplayer_group) objects matching API query. See [Making API search queries](#api_query) for instructions on making search queries",
          "endpoint": "/api/maplayer_group",
          "fields": [],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_many_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get single [maplayer_group](#maplayer_group) object with pk field matching param `id`",
          "endpoint": "/api/maplayer_group/<id>",
          "fields": [],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_single_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Delete single [maplayer_group](#maplayer_group) object with pk field matching param `id`",
          "endpoint": "/api/maplayer_group/<id>",
          "method": "DELETE",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to ADMIN user only",
              "name": "assert_current_user_is_admin"
            },
            {
              "doc": "Restrict request to OWNER only",
              "name": "delete_auth_preprocessor"
            }
          ]
        }
      ],
      "hybrid_properties": [],
      "methods": [],
      "relations": [
        {
          "direction": "ONETOMANY",
          "doc": null,
          "key": "maplayers",
          "model": "maplayer"
        }
      ]
    },
    {
      "association_proxies": [
        {
          "model": "media_collection",
          "name": "media_collections",
          "target_collection": "media_collection_media"
        }
      ],
      "collection": "media",
      "columns": [
        {
          "default": null,
          "doc": "Primary key `id`",
          "foreign_key": null,
          "name": "id",
          "nullable": false,
          "primary_key": true,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": "{}",
          "doc": "Text field containing JSON properties for this resource",
          "foreign_key": null,
          "name": "data",
          "nullable": true,
          "primary_key": false,
          "type": "JSON()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "key",
          "nullable": false,
          "primary_key": false,
          "type": "String(length=128)",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "path",
          "nullable": true,
          "primary_key": false,
          "type": "Text()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "path_thm",
          "nullable": true,
          "primary_key": false,
          "type": "Text()",
          "unique": null
        },
        {
          "default": "True",
          "doc": null,
          "foreign_key": null,
          "name": "is_valid",
          "nullable": true,
          "primary_key": false,
          "type": "Boolean()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": "deployment.id",
          "name": "deployment_id",
          "nullable": false,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": "media_type.id",
          "name": "media_type_id",
          "nullable": false,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": "The [camera_installation](#camera_installation) that captured this media item (set by camera assignment, see `camera_source`)",
          "foreign_key": "camera_installation.id",
          "name": "camera_installation_id",
          "nullable": true,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": "How `camera_installation_id` was set: `pattern` (automatic) or `manual`. Automatic camera assignment never changes `manual` assignments",
          "foreign_key": null,
          "name": "camera_source",
          "nullable": true,
          "primary_key": false,
          "type": "String(length=8)",
          "unique": null
        },
        {
          "default": null,
          "doc": "Pixel width of this media item (displayed orientation), if known. See `dims` for the resolved dimensions",
          "foreign_key": null,
          "name": "width",
          "nullable": true,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": "Pixel height of this media item (displayed orientation), if known",
          "foreign_key": null,
          "name": "height",
          "nullable": true,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": "Where `width` / `height` came from, in increasing precedence: `declared` (datafile, annotation import or bot), `probe`, `observed` (image loaded by the UI or thumbnailer), `manual`",
          "foreign_key": null,
          "name": "dims_source",
          "nullable": true,
          "primary_key": false,
          "type": "String(length=10)",
          "unique": null
        },
        {
          "default": "function",
          "doc": null,
          "foreign_key": null,
          "name": "timestamp_start",
          "nullable": true,
          "primary_key": false,
          "type": "DateTime()",
          "unique": null
        },
        {
          "default": "function",
          "doc": null,
          "foreign_key": null,
          "name": "created_at",
          "nullable": true,
          "primary_key": false,
          "type": "DateTime()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": "media.id",
          "name": "parent_id",
          "nullable": true,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        }
      ],
      "description": "\n    Media resource: a generic media object definition that can be used to link in media in a variety of formats,\n    including images, videos, photo-mosaics and other media formats. Note that at the moment only images and video\n    framegrabs have annotation support. Annotation viewers for video and mosaics coming soon.\n    ",
      "endpoints": [
        {
          "description": "Update single [media](#media) object with pk field matching param `id`. Expects JSON. Fields shown in `MODEL COLUMNS` below.",
          "endpoint": "/api/media/<id>",
          "method": "PATCH",
          "postprocessors": [
            {
              "doc": "Clears the request cache object for this resource (to cause cache refresh on next request)",
              "name": "_clear_cache"
            }
          ],
          "preprocessors": [
            {
              "doc": "Restrict to custodians of the deployment's datasource. Setting `width` / `height` or\n        `camera_installation_id` marks them as set manually (`dims_source` / `camera_source`)",
              "name": "patch_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get list of [media](#media) objects matching API query. See [Making API search queries](#api_query) for instructions on making search queries",
          "endpoint": "/api/media",
          "fields": [
            "created_at",
            "timestamp_start",
            "is_valid",
            "key",
            "deployment",
            "deployment.id",
            "deployment.key",
            "campaign",
            "campaign.id",
            "campaign.key",
            "deployment_id",
            "data",
            "id",
            "media_type",
            "media_type.id",
            "media_type.name",
            "camera_installation_id",
            "camera_source",
            "width",
            "height",
            "dims_source",
            "path_best",
            "path_best_thm",
            "event_count",
            "dims"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_many_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get single [media](#media) object with pk field matching param `id`",
          "endpoint": "/api/media/<id>",
          "fields": [
            "created_at",
            "timestamp_start",
            "is_valid",
            "key",
            "deployment",
            "deployment.id",
            "deployment.key",
            "campaign",
            "campaign.id",
            "campaign.key",
            "deployment_id",
            "data",
            "id",
            "media_type",
            "media_type.id",
            "media_type.name",
            "camera_installation_id",
            "camera_source",
            "width",
            "height",
            "dims_source",
            "path_best",
            "path_best_thm",
            "event_count",
            "dims",
            "current_user_can_edit"
          ],
          "method": "GET",
          "postprocessors": [
            {
              "doc": null,
              "name": "get_single_postprocessor"
            }
          ],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_single_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Delete single [media](#media) object with pk field matching param `id`",
          "endpoint": "/api/media/<id>",
          "method": "DELETE",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict to custodians of the deployment's datasource. Media with labelled annotations can only be deleted\n        by custodians that are admins, with `?confirm=<media key>`",
              "name": "delete_auth_preprocessor"
            }
          ]
        },
        {
          "description": null,
          "endpoint": "/api/media/<int:media_id>/annotations/<int:annotation_set_id>",
          "method": "GET"
        },
        {
          "description": "\n        Media UPLOAD resource.\n\n        Used to upload Media to predefined location set out in server config file.\n\n        `file`: file data input containing image file to upload.\n        `json`: json string containing parameters for new [media](#media) item\n        ",
          "endpoint": "/api/media/save",
          "method": "POST"
        },
        {
          "description": "\n        In addition to the `MODEL COLUMNS` below, the JSON body can contain the following parameters:\n        `pose`: a dict containing parameters for a single [pose](#pose) including associated pose data,\n        `poses`: a list of dicts as above if linking multiple poses to a single media object (eg: video),\n        `media_type`: OPTIONAL (default=\"image\"), a string containing the [media_type](#media_type) name.\n\n        Here are some example payloads for creating [media](#media) objects:\n        ```\n        # example JSON payload for media item with a single pose (eg: still image)\n        {\n            \"pose\": {\"lat\":-35.53153264, \"lon\":150.43962917, \"alt\":3.558, \"dep\":28.85, \"data\":[\n                {\"name\":\"temperature\",\"value\":16.602},\n                {\"name\":\"salinity\",\"value\":35.260222}\n            ]},\n            \"key\": \"PR_20101117_002241_698_LC16\",\n            \"deployment_id\": 5,\n            \"timestamp_start\": \"2018-06-07T00:47:17.273514\"\n        }\n\n        # Same as above, but with dict data\n        {\n            \"pose\": {\"lat\":-35.53153264, \"lon\":150.43962917, \"alt\":3.558, \"dep\":28.85, \"data\":{\n                \"temperature\":16.602,\n                \"salinity\":35.260222\n            }},\n            \"key\": \"TEST_20101117_002241_698_LC16\",\n            \"deployment_id\": 13170,\n            \"timestamp_start\": \"2018-06-07T00:47:17.273514\"\n        }\n\n        # To add multiple poses to a media object (i.e. video)\n        {\n            \"poses\":\n                [{\n                    \"timestamp\": \"2018-06-07T00:47:17.273517\",\n                    \"lat\":-35.53153264,\n                    \"lon\":150.43962917,\n                    \"alt\":3.558,\n                    \"dep\":28.85,\n                    \"data\":{\n                        \"temperature\":16.602,\n                        \"salinity\":35.260222\n                    }\n                },{\n                    \"timestamp\": \"2018-06-07T00:47:18.273517\",\n                    \"lat\":-35.531532654,\n                    \"lon\":150.439629345,\n                    \"alt\":6.558,\n                    \"dep\":29.85,\n                    \"data\":{\n                        \"temperature\":16.602,\n                        \"salinity\":35.260222\n                    }\n                },{\n                    \"timestamp\": \"2018-06-07T00:47:19.273517\",\n                    \"lat\":-35.531534564,\n                    \"lon\":150.43962934,\n                    \"alt\":4.558,\n                    \"dep\":28.85,\n                    \"data\":{\n                        \"temperature\":16.60256,\n                        \"salinity\":35.260234\n                    }\n                }],\n            \"key\": \"KEY_OF_VIDEO_FILE_NAME\",\n            \"deployment_id\": 13170,\n            \"timestamp_start\": \"2018-06-07T00:47:17.273514\",\n            \"media_type\": \"rawvideo\"\n        }\n        ```\n        ",
          "endpoint": "/api/media",
          "method": "POST"
        },
        {
          "description": "\n        The list of [pose](#pose) for the [media](#media) item matching `id`. For still images, it will normally just\n        be a single [pose](#pose), but video-like [media_types](#media_type) can have more.\n        ",
          "endpoint": "/api/media/<int:id>/poses",
          "method": "GET"
        },
        {
          "description": "\n        Dynamically create and serve thumbnail.\n\n        If user is logged in, then they can request different sizes.\n        ",
          "endpoint": "/api/media/<int:id>/thumbnail",
          "method": "GET"
        },
        {
          "description": "\n        Dynamically create and serve media image for different media types.\n        For video, supply `t` which is the runtime in seconds of the frame to be returned.\n        For wms, supply `bbox` to return the specific region of interest from the WMS layer..\n        ",
          "endpoint": "/api/media/<int:id>/image",
          "method": "GET"
        },
        {
          "description": "Download media object with associated metadata as a zip file",
          "endpoint": "/api/media/<int:id>/download",
          "method": "GET"
        },
        {
          "description": "\n        Export [media](#media). This endpoint is limited to a maximum of 200,000 media items\n        in any single query. You can export more in separate queries using a combination of `limit` and `offset`\n        parameters. To export media from a single `deployment` without limits, see the `export` endpoint in the\n        [deployment](deployment) resource.\n\n        \n        Export [media](#media) matching query defined in `q`.\n        Search queries are executed on the [media](#media) model. \n\n        \n        Querystring parameters are:\n\n        ```?q={...}&f={...}&disposition=...&template=...&include_columns=[...]```\n\n        Where `q` is a JSON search query (see [Making API search queries](#api_query)) on the collection model,\n        where `f` is a JSON dictionary containing a sequence of operations for transforming the data\n        (see [Data transformation API](#api_data_transform) for more info),\n        `disposition` defines the download type which can be `attachment` (default, triggers a download) or `inline` (displays in\n        the browser),\n        `template` is optional depending on the output of the steps in `f` and can be used to define the export format,\n        `include_columns` is a JSON list of column fields for the exported model.\n        Nested fields for related models delimited with a `.`\n        If `include_columns` is omitted, all allowed columns will be returned (or the exporter's `default_columns`, if\n        it defines them).\n\n        Metadata for the dataset is also returned in the response. Depending on the output\n        format, this could be as part of the response body in a `metadata` field (e.g., Json) or in the response headers with the key\n        `X-Content-Metadata` (e.g., CSV or HTML).\n    \n\n        Allowed fields include:\n\n        `id`, `key`, `data`, `is_valid`,`media_type.id`,`media_type.name`, `path_best`, `timestamp_start`,\n        `timestamp_start_local`, `path_best_thm`, `pose.timestamp`, `pose.timestamp_local`, `pose.lat`, `pose.lon`,\n        `pose.alt`, `pose.dep`, `pose.data`, `pose.id`, `deployment.campaign.id`, `deployment.campaign.key`,\n        `deployment.campaign.name`, `deployment.key`, `deployment.id`, `deployment.name`,\n        `dims`, `camera_installation_id`, `camera_installation.name`, `camera_source`, `camera.key`, `camera.name`\n\n        `dims` is the resolved pixel dimensions (`{\"width\", \"height\", \"source\"}`, or `null` if unknown): the media\n        item's own measured / declared dimensions, or the default of its [camera_installation](#camera_installation)\n        (`source: \"installation\"`). `camera` is the [camera](#camera) of that installation, and\n        `camera_installation.name` its name (eg: the position of one of several units of the same camera).\n\n        See [media](#media) model columns, relations and attributes for more information on each of the included fields.\n        \n        \n\n        **EXAMPLES**\n\n        ```\n        ```\n        ",
          "endpoint": "/api/media/export",
          "method": "GET"
        },
        {
          "description": "\n        Get a tally of [media](#media).\n\n        \n        The tally of [media](#media) can be grouped by different properties. `group_by` can be one of\n        [`month`, `year_collected`, `month_collected`, `user`, `platform`, `campaign`, `deployment`, `camera`, `media_type`,\n        `media_collection`^, `is_valid`]. Set `q` in querystring to filter selected [media](#media) as per\n        [Making API search queries](#api_query). Note, the same query in `q` can be applied to all `group_by` types to\n        filter the list of [media](#media) that are included in the tally. Results are also paginated with a default\n        of `100` and a maximum of `5000` returned per page. This can be controlled by setting the `results_per_page`\n        parameter in the query string.\n        `month` groups by the date the media was added (`created_at`), while `year_collected` and `month_collected`\n        group by the date the media was captured (`timestamp_start`). `user` groups by the owner of the\n        [deployment](#deployment) that the media belongs to.\n        Also accepts a query string parameter `template` which formats the data using a predefined template. Some example\n        templates include: `data.html` which returns an HTML table, `json.html` which returns HTML-formatted JSON, `data.csv`\n        which returns a CSV file for download. If left blank, raw JSON will be returned.\n\n        ^ **NOTE**: the counts in the `media_collection` tally should be interpreted with care. If a media item belongs\n        to more than one [media_collection](#media_collection), then it will contribute to each of them, and media that\n        do not belong to any [media_collection](#media_collection) will not be counted in the tally.\n        \n\n        **EXAMPLES**\n\n        ```\n        # Example: tally of media by platform returned as raw JSON\n        /api/media/tally/platform\n\n        # Example: tally of media for the top 2000 deployments returned as an HTML table\n        /api/media/tally/deployment?template=data.html&results_per_page=2000\n\n        # Example: tally of media by campaign returned as a CSV file\n        /api/media/tally/campaign?template=data.csv\n\n        # Example: tally of media by year of collection for platform(s) containing \"IMOS\" in their name, returned as an HTML table\n        /api/media/tally/year_collected?q={\"filters\": [{\"name\":\"deployment\",\"op\":\"has\",\"val\": {\"name\":\"platform\",\"op\":\"has\",\"val\": {\"name\":\"name\",\"op\":\"ilike\",\"val\":\"%IMOS%\"}}}]}&template=data.html\n\n        # Example: tally of media by media_collection for collections containing media from deployment with id=10306\n        /api/media/tally/media_collection?q={\"filters\":[{\"name\":\"deployment_id\",\"op\":\"eq\",\"val\":10306}]}&template=data.html\n\n        # Example: tally of media added each month during 2024 returned as an HTML table\n        /api/media/tally/month?q={\"filters\": [{\"name\":\"created_at\",\"op\":\"gt\",\"val\":\"2024-01-01\"}, {\"name\":\"created_at\",\"op\":\"lt\",\"val\":\"2025-01-01\"}]}&template=data.html\n        ```\n        ",
          "endpoint": "/api/media/tally/<group_by>",
          "method": "GET"
        },
        {
          "description": "\n        Report the pixel dimensions of this media item, as observed by a client that loaded the image (`path_best`)\n        at its native resolution (eg: the annotation UI, or a bot). JSON body: `{\"width\": <int>, \"height\": <int>}`, in\n        the displayed (EXIF corrected) orientation. Logged in users only. Stored as `dims_source = observed`, unless\n        better information is already known (a disagreement is recorded in `data.dims_mismatch`).\n        Returns the resolved `dims`.\n        ",
          "endpoint": "/api/media/<int:id>/dims",
          "method": "POST"
        }
      ],
      "hybrid_properties": [
        {
          "args": [],
          "doc": null,
          "name": "geom",
          "type": "property"
        },
        {
          "args": [],
          "doc": "BOOLEAN, whether or not this has a parent",
          "name": "is_child",
          "type": "property"
        },
        {
          "args": [
            "annotation_set_id"
          ],
          "doc": "BOOL, whether or not the [media object](#media) contains unlabeled annotations from the\n        [annotation_set](annotation_set) with the id `annotation_set_id`",
          "name": "has_unlabeled_annotations",
          "type": "method"
        },
        {
          "args": [
            "annotation_set_id"
          ],
          "doc": "BOOL, whether or not the [media object](#media) contains points from the\n        [annotation_set](annotation_set) with the id `annotation_set_id`",
          "name": "has_points",
          "type": "method"
        },
        {
          "args": [
            "annotation_set_id"
          ],
          "doc": "BOOL, whether or not the [media object](#media) contains any annotations from the\n        [annotation_set](annotation_set) with the id `annotation_set_id`",
          "name": "has_annotations",
          "type": "method"
        },
        {
          "args": [
            "lat",
            "lon"
          ],
          "doc": "FLOAT, distance (in meters) of closest linked [pose](#pose) relative to `lat` and `lon` (which are both in decimal degrees)",
          "name": "distance",
          "type": "method"
        },
        {
          "args": [
            "ts"
          ],
          "doc": "Absolute difference in seconds of the in-situ timestamp and input `ts`, which is datetime string\n        eg: `\"2020-09-25T00:57:11.945009\"` (or in a format that is parsable by `dateutil.parser.parse`)",
          "name": "timestamp_proximity",
          "type": "method"
        }
      ],
      "methods": [
        {
          "doc": "Whether or not the current user can edit this media item (custodian of the deployment's datasource)",
          "name": "current_user_can_edit",
          "type": "method"
        },
        {
          "doc": null,
          "name": "event_log",
          "type": "method"
        },
        {
          "doc": "The [camera](#camera) that captured this media item (through its `camera_installation`), or None",
          "name": "camera",
          "type": "property"
        },
        {
          "doc": null,
          "name": "color",
          "type": "property"
        },
        {
          "doc": "\n        DICT, the resolved pixel dimensions of this media item: `{\"width\":..., \"height\":..., \"source\":...}`, or `null`\n        if unknown. Uses the media item's own `width` / `height` (`source` is its `dims_source`), otherwise the default\n        dimensions of its [camera_installation](#camera_installation) (`source: \"installation\"`).\n        ",
          "name": "dims",
          "type": "property"
        },
        {
          "doc": "BOOL, whether or not the [media object](#media) contains any logged [deployment_events](#deployment_event)",
          "name": "event_count",
          "type": "property"
        },
        {
          "doc": null,
          "name": "path_best",
          "type": "property"
        },
        {
          "doc": null,
          "name": "path_best_thm",
          "type": "property"
        },
        {
          "doc": "INT, height of the media item in pixels (the `height` of `dims`), or `null` if unknown. Can be overridden\n        with the URL parameter `&pixel_height=<int:height>`",
          "name": "pixel_height",
          "type": "property"
        },
        {
          "doc": "INT, width of the media item in pixels (the `width` of `dims`), or `null` if unknown. Can be overridden\n        with the URL parameter `&pixel_width=<int:width>`",
          "name": "pixel_width",
          "type": "property"
        },
        {
          "doc": "\n        The first pose from related `poses` or if child media item, it gets the closest matching pose from the\n        `parent_media` item based on `timestamp_start`\n        ",
          "name": "pose",
          "type": "property"
        },
        {
          "doc": "LOCAL datetime, converted using `pose.lat`, `pose.lon` and `timestamp_start`",
          "name": "timestamp_start_local",
          "type": "property"
        }
      ],
      "relations": [
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "deployment",
          "model": "deployment"
        },
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "media_type",
          "model": "media_type"
        },
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "camera_installation",
          "model": "camera_installation"
        },
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "parent",
          "model": "media"
        },
        {
          "direction": "ONETOMANY",
          "doc": "List of [point](#point) objects",
          "key": "annotations",
          "model": "point"
        },
        {
          "direction": "ONETOMANY",
          "doc": null,
          "key": "poses",
          "model": "pose"
        },
        {
          "direction": "ONETOMANY",
          "doc": null,
          "key": "children",
          "model": "media"
        },
        {
          "direction": "ONETOMANY",
          "doc": null,
          "key": "media_collection_media",
          "model": "media_collection_media"
        },
        {
          "direction": "ONETOMANY",
          "doc": null,
          "key": "events",
          "model": "deployment_event"
        }
      ]
    },
    {
      "association_proxies": [],
      "collection": "media_collection",
      "columns": [
        {
          "default": null,
          "doc": "Primary key `id`",
          "foreign_key": null,
          "name": "id",
          "nullable": false,
          "primary_key": true,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": "{}",
          "doc": "Text field containing JSON properties for this resource",
          "foreign_key": null,
          "name": "data",
          "nullable": true,
          "primary_key": false,
          "type": "JSON()",
          "unique": null
        },
        {
          "default": null,
          "doc": "The name of the `media_collection`",
          "foreign_key": null,
          "name": "name",
          "nullable": false,
          "primary_key": false,
          "type": "String(length=80)",
          "unique": null
        },
        {
          "default": null,
          "doc": "A concise description of the `media_collection`",
          "foreign_key": null,
          "name": "description",
          "nullable": true,
          "primary_key": false,
          "type": "Text()",
          "unique": null
        },
        {
          "default": null,
          "doc": "A reference to the ID of a parent `media_collection`",
          "foreign_key": "media_collection.id",
          "name": "parent_collection_id",
          "nullable": true,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": "function",
          "doc": "The creation date-time",
          "foreign_key": null,
          "name": "created_at",
          "nullable": false,
          "primary_key": false,
          "type": "DateTime()",
          "unique": null
        },
        {
          "default": null,
          "doc": "Foreign key reference for ID of related owner [users](#users) model",
          "foreign_key": "users.id",
          "name": "user_id",
          "nullable": true,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        }
      ],
      "description": "\n    Media Collection resource: a user-defined collection of [media](#media) objects grouped for further analysis.\n    Can be a subset of [media](#media) objects from one or more [deployments](#deployment)\n    ",
      "endpoints": [
        {
          "description": "Create new [media_collection](#media_collection) object. Expects JSON. Fields shown in `MODEL COLUMNS` below. ",
          "endpoint": "/api/media_collection",
          "method": "POST",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to LOGGED IN users only",
              "name": "post_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Update single [media_collection](#media_collection) object with pk field matching param `id`. Expects JSON. Fields shown in `MODEL COLUMNS` below.",
          "endpoint": "/api/media_collection/<id>",
          "method": "PATCH",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Assert object edit permission from shared `usergroups`. Checks current_user has edit permission.",
              "name": "patch_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get list of [media_collection](#media_collection) objects matching API query. See [Making API search queries](#api_query) for instructions on making search queries",
          "endpoint": "/api/media_collection",
          "fields": [
            "id",
            "name",
            "parent_collection_id",
            "description",
            "user",
            "created_at",
            "user.id",
            "user.first_name",
            "user.last_name",
            "user.username",
            "current_user_can_view",
            "current_user_is_owner",
            "current_user_is_member",
            "current_user_can_edit",
            "is_public",
            "usergroup_count",
            "annotation_set_count",
            "media_count"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_many_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get single [media_collection](#media_collection) object with pk field matching param `id`",
          "endpoint": "/api/media_collection/<id>",
          "fields": [
            "id",
            "name",
            "parent_collection_id",
            "description",
            "user",
            "created_at",
            "user.id",
            "user.first_name",
            "user.last_name",
            "user.username",
            "current_user_can_view",
            "current_user_is_owner",
            "current_user_is_member",
            "current_user_can_edit",
            "is_public",
            "usergroup_count",
            "annotation_set_count",
            "media_count",
            "data",
            "extent"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Preprocessor for single instance retrieval with authorization checks.",
              "name": "get_single_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Delete single [media_collection](#media_collection) object with pk field matching param `id`",
          "endpoint": "/api/media_collection/<id>",
          "method": "DELETE",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Assert object delete permission from shared `usergroups`. Checks current user is owner and object is not\n        shared in a `usergroup`",
              "name": "delete_auth_preprocessor"
            }
          ]
        },
        {
          "description": "\n        Add instance with ID of `instance_id` to the group with the ID `group_id`\n        ",
          "endpoint": "/api/media_collection/<int:instance_id>/group/<int:group_id>",
          "method": "POST"
        },
        {
          "description": "Remove resource with id `instance_id` from group with id `group_id`",
          "endpoint": "/api/media_collection/<int:instance_id>/group/<int:group_id>",
          "method": "DELETE"
        },
        {
          "description": "\n        Export [media](#media) collection from [media_collection](#media_collection) matching `id`.\n        Search queries are executed on the [media](#media) model.\n\n        \n        Querystring parameters are:\n\n        ```?q={...}&f={...}&disposition=...&template=...&include_columns=[...]```\n\n        Where `q` is a JSON search query (see [Making API search queries](#api_query)) on the collection model,\n        where `f` is a JSON dictionary containing a sequence of operations for transforming the data\n        (see [Data transformation API](#api_data_transform) for more info),\n        `disposition` defines the download type which can be `attachment` (default, triggers a download) or `inline` (displays in\n        the browser),\n        `template` is optional depending on the output of the steps in `f` and can be used to define the export format,\n        `include_columns` is a JSON list of column fields for the exported model.\n        Nested fields for related models delimited with a `.`\n        If `include_columns` is omitted, all allowed columns will be returned (or the exporter's `default_columns`, if\n        it defines them).\n\n        Metadata for the dataset is also returned in the response. Depending on the output\n        format, this could be as part of the response body in a `metadata` field (e.g., Json) or in the response headers with the key\n        `X-Content-Metadata` (e.g., CSV or HTML).\n    \n\n        Allowed columns include: `id`, `key`, `timestamp_start`, `path_best`,  `path_best_thm`, `pose.timestamp`, `pose.lat`,\n            `pose.lon`, `pose.alt`, `pose.dep`, `pose.data`, `pose.id`, `deployment.key`,\n            `deployment.campaign.key`, `deployment.id`, `deployment.campaign.id`, `event_log`, `dims`,\n            `camera_installation_id`, `camera_installation.name`, `camera_source`, `camera.key`, `camera.name`\n\n        `dims` is the resolved pixel dimensions (`{\"width\", \"height\", \"source\"}`, or `null` if unknown): the media\n        item's own measured / declared dimensions, or the default of its [camera_installation](#camera_installation)\n        (`source: \"installation\"`). `camera` is the [camera](#camera) of that installation.\n\n        ```\n        # Example1: export the media collection as a CSV file\n        /api/media_collection/1776/export?template=dataframe.csv&f={\"operations\": [{\"module\": \"pandas\", \"method\": \"json_normalize\"}]}\n\n        # Example2: download a plain text list of image URLs (one per line, no header) to load into a download manager\n        /api/media_collection/1776/export?template=dataframe.txt&disposition=attachment&include_columns=[\"path_best\"]&f={\"operations\": [{\"module\": \"pandas\", \"method\": \"json_normalize\"}]}\n\n        # Example3: JSON list of media keys, URLs and positions (eg: for a script that downloads the images)\n        /api/media_collection/1776/export?include_columns=[\"key\",\"path_best\",\"pose.lat\",\"pose.lon\",\"deployment.key\"]\n        ```\n\n        NB: the UI contains an \"ADVANCED\" option which can help build more complex export queries.\n        ",
          "endpoint": "/api/media_collection/<int:id>/export",
          "method": "GET"
        },
        {
          "description": "\n        Get a tally of [media](#media) for a `media_collection` matching `id`.\n\n        \n        The tally of [media](#media) can be grouped by different properties. `group_by` can be one of\n        [`month`, `year_collected`, `month_collected`, `user`, `platform`, `campaign`, `deployment`, `camera`, `media_type`,\n        `media_collection`^, `is_valid`]. Set `q` in querystring to filter selected [media](#media) as per\n        [Making API search queries](#api_query). Note, the same query in `q` can be applied to all `group_by` types to\n        filter the list of [media](#media) that are included in the tally. Results are also paginated with a default\n        of `100` and a maximum of `5000` returned per page. This can be controlled by setting the `results_per_page`\n        parameter in the query string.\n        `month` groups by the date the media was added (`created_at`), while `year_collected` and `month_collected`\n        group by the date the media was captured (`timestamp_start`). `user` groups by the owner of the\n        [deployment](#deployment) that the media belongs to.\n        Also accepts a query string parameter `template` which formats the data using a predefined template. Some example\n        templates include: `data.html` which returns an HTML table, `json.html` which returns HTML-formatted JSON, `data.csv`\n        which returns a CSV file for download. If left blank, raw JSON will be returned.\n\n        ^ **NOTE**: the counts in the `media_collection` tally should be interpreted with care. If a media item belongs\n        to more than one [media_collection](#media_collection), then it will contribute to each of them, and media that\n        do not belong to any [media_collection](#media_collection) will not be counted in the tally.\n        \n\n        **EXAMPLES**\n\n        ```\n        # Example: tally of media in media_collection with id=1776 by deployment, returned as an HTML table\n        /api/media_collection/1776/media/tally/deployment?template=data.html\n        ```\n        ",
          "endpoint": "/api/media_collection/<int:id>/media/tally/<group_by>",
          "method": "GET"
        },
        {
          "description": "\n        Get list of [media](#media) objects contained in the [media_collection](#media_collection) with an ID matching `media_collection_id`.\n        Accepts search query parameters. See [Making API search queries](#api_query) for instructions on making search queries\n        ",
          "endpoint": "/api/media_collection/<int:media_collection_id>/media",
          "method": "GET"
        },
        {
          "description": "\n        Add [media](#media) objects matching the search query defined in the json post parameter `q` to the [media_collection](#media_collection)\n        with an ID matching `media_collection_id`. `q` is a search query in the format defined in [Making API search queries](#api_query) section\n        and is sent as either a URL parameter or form post parameter.\n        Request returns the corresponding [media_collection](#media_collection).\n        ",
          "endpoint": "/api/media_collection/<int:media_collection_id>/media",
          "method": "POST"
        },
        {
          "description": "\n        Get the single [media](#media) object with the ID `media_id` from the [media_collection](#media_collection) with the ID `media_collection_id`\n        ",
          "endpoint": "/api/media_collection/<int:media_collection_id>/media/<int:media_id>",
          "method": "GET"
        },
        {
          "description": "\n        Add the [media](#media) object with the ID `media_id` to the [media_collection](#media_collection) with the ID `media_collection_id`\n        ",
          "endpoint": "/api/media_collection/<int:media_collection_id>/media/<int:media_id>",
          "method": "POST"
        },
        {
          "description": "\n        Remove the [media](#media) object with the ID `media_id` from the [media_collection](#media_collection) with the ID `media_collection_id`\n        ",
          "endpoint": "/api/media_collection/<int:media_collection_id>/media/<int:media_id>",
          "method": "DELETE"
        },
        {
          "description": "\n        List the [group_dashboards](#group_dashboard) available for this [media_collection](#media_collection): those offered\n        for `media_collection` datasets by the [groups](#groups) it is shared in. Each result includes `authorized`, with the launch `url`\n        for the current user (a signed token in place of `{token}` in the dashboard's `url_base`, or `null` if they\n        can't launch it) and the result of each of the dashboard's `permission_tests`. See\n        [group_dashboard](#group_dashboard) for the token and how a dashboard decodes it.\n\n        **EXAMPLES**\n\n        ```\n        # Dashboards for media_collection 1234, as JSON\n        /api/media_collection/1234/dashboards\n        ```\n        ",
          "endpoint": "/api/media_collection/<int:id>/dashboards",
          "method": "GET"
        },
        {
          "description": "\n        Public summary of a [media_collection](#media_collection) to help with dataset discovery. Returns non-sensitive\n        metadata (name, description, custodian, media / annotation_set / group counts) whether or not the current user\n        has permission to view the media_collection, as well as `current_user_can_view` and `is_public`. It does not\n        return any media or files. The groups that it is shared in can be listed with the [groups](#groups) resource,\n        eg: `/api/groups?q={\"filters\":[{\"name\":\"shared_media_collections\",\"op\":\"any\",\"val\":{\"name\":\"id\",\"op\":\"eq\",\"val\":ID}}]}`\n\n        **EXAMPLES**\n\n        ```\n        # Summary of media collection with id=5053 as JSON\n        /api/media_collection/5053/summary\n        ```\n        ",
          "endpoint": "/api/media_collection/<int:id>/summary",
          "method": "GET"
        }
      ],
      "hybrid_properties": [
        {
          "args": [],
          "doc": "Number of Media objects in this Media Collection",
          "name": "media_count",
          "type": "property"
        },
        {
          "args": [],
          "doc": "Number of annotation_sets in this Media Collection",
          "name": "annotation_set_count",
          "type": "property"
        },
        {
          "args": [],
          "doc": "Whether or not this object is public (i.e. shared in a public group)",
          "name": "is_public",
          "type": "property"
        },
        {
          "args": [],
          "doc": "Whether the current logged in user is the owner of this object",
          "name": "current_user_is_owner",
          "type": "property"
        },
        {
          "args": [],
          "doc": "Whether the current logged in user is a member of a group that includes this object",
          "name": "current_user_is_member",
          "type": "property"
        },
        {
          "args": [],
          "doc": "Whether the current logged in user is a member with edit permission of a group that includes this object",
          "name": "current_user_is_edit_member",
          "type": "property"
        },
        {
          "args": [],
          "doc": "Whether the current logged in user is the owner of a group that includes this object",
          "name": "current_user_is_group_owner",
          "type": "property"
        },
        {
          "args": [],
          "doc": "Whether or not the current user has permission to view this object",
          "name": "current_user_can_view",
          "type": "property"
        },
        {
          "args": [],
          "doc": "Whether the current logged in user has edit permission (owner or edit_member)",
          "name": "current_user_can_edit",
          "type": "property"
        },
        {
          "args": [
            "user_id"
          ],
          "doc": "Whether the specified user is the owner of this object",
          "name": "user_is_owner",
          "type": "method"
        },
        {
          "args": [
            "user_id"
          ],
          "doc": "Whether the specified user is a member of a group that includes this object",
          "name": "user_is_member",
          "type": "method"
        },
        {
          "args": [
            "user_id"
          ],
          "doc": "Whether the specified user is a member with edit permission of a group that includes this object",
          "name": "user_is_edit_member",
          "type": "method"
        },
        {
          "args": [
            "user_id"
          ],
          "doc": "Whether the specified user is the owner of a group that includes this object",
          "name": "user_is_group_owner",
          "type": "method"
        },
        {
          "args": [
            "user_id"
          ],
          "doc": "Returns true is user is owner, dataset belongs to a public group, user owns a group or dataset belongs to an\n        unrestricted group that user is a member of",
          "name": "user_can_view",
          "type": "method"
        },
        {
          "args": [
            "user_id"
          ],
          "doc": "Whether the specified user has edit permission (owner or edit_member)",
          "name": "user_can_edit",
          "type": "method"
        }
      ],
      "methods": [
        {
          "doc": "\n        Compute spatial extent of Media Collection\n        :return: list with format [[SW_LAT, SW_LON],[NE_LAT,NE_LON]]\n        ",
          "name": "extent",
          "type": "method"
        },
        {
          "doc": null,
          "name": "usergroup_count",
          "type": "method"
        }
      ],
      "relations": [
        {
          "direction": "MANYTOONE",
          "doc": "The parent `media_collection` instance",
          "key": "parent",
          "model": "media_collection"
        },
        {
          "direction": "MANYTOMANY",
          "doc": "A list of `media` contained in this `media_collection`",
          "key": "media",
          "model": "media"
        },
        {
          "direction": "MANYTOONE",
          "doc": "Related owner [users](#users) model",
          "key": "user",
          "model": "users"
        },
        {
          "direction": "MANYTOMANY",
          "doc": "List of [groups](#groups) objects that contain this resource",
          "key": "usergroups",
          "model": "groups"
        },
        {
          "direction": "ONETOMANY",
          "doc": null,
          "key": "annotation_sets",
          "model": "annotation_set"
        },
        {
          "direction": "ONETOMANY",
          "doc": "A list of childen `media_collections` that belong to this one",
          "key": "children",
          "model": "media_collection"
        },
        {
          "direction": "ONETOMANY",
          "doc": null,
          "key": "media_collection_media",
          "model": "media_collection_media"
        }
      ]
    },
    {
      "association_proxies": [],
      "collection": "media_collection_media",
      "columns": [
        {
          "default": null,
          "doc": null,
          "foreign_key": "media.id",
          "name": "media_id",
          "nullable": false,
          "primary_key": true,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": "media_collection.id",
          "name": "media_collection_id",
          "nullable": false,
          "primary_key": true,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": "function",
          "doc": null,
          "foreign_key": null,
          "name": "created_at",
          "nullable": false,
          "primary_key": false,
          "type": "DateTime()",
          "unique": null
        }
      ],
      "description": "\n    Media Collection Media Associate resource: a model for associating a subset of [media](#media) objects to a\n    [media_collection](#media_collection)\n    ",
      "endpoints": [
        {
          "description": "Create new [media_collection_media](#media_collection_media) object. Expects JSON. Fields shown in `MODEL COLUMNS` below. ",
          "endpoint": "/api/media_collection_media",
          "method": "POST",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": null,
              "name": "edit_auth_preprocessor"
            },
            {
              "doc": "Restrict request to LOGGED IN users only",
              "name": "post_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get list of [media_collection_media](#media_collection_media) objects matching API query. See [Making API search queries](#api_query) for instructions on making search queries",
          "endpoint": "/api/media_collection_media",
          "fields": [
            "created_at",
            "media_id",
            "media_collection_id"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_many_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get single [media_collection_media](#media_collection_media) object with pk field matching param `media_collection_id`",
          "endpoint": "/api/media_collection_media/<media_collection_id>",
          "fields": [
            "created_at",
            "media_id",
            "media_collection_id"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_single_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Delete single [media_collection_media](#media_collection_media) object with pk field matching param `media_collection_id`",
          "endpoint": "/api/media_collection_media/<media_collection_id>",
          "method": "DELETE",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": null,
              "name": "edit_auth_preprocessor"
            },
            {
              "doc": "Restrict request to OWNER only",
              "name": "delete_auth_preprocessor"
            }
          ]
        }
      ],
      "hybrid_properties": [],
      "methods": [],
      "relations": [
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "media",
          "model": "media"
        },
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "media_collection",
          "model": "media_collection"
        }
      ]
    },
    {
      "association_proxies": [],
      "collection": "media_type",
      "columns": [
        {
          "default": null,
          "doc": "Primary key `id`",
          "foreign_key": null,
          "name": "id",
          "nullable": false,
          "primary_key": true,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": "The name of the media type",
          "foreign_key": null,
          "name": "name",
          "nullable": false,
          "primary_key": false,
          "type": "String(length=80)",
          "unique": null
        }
      ],
      "description": "\n    Media Type resource: a modifier denoting the type for a [media](#media) resource. This is associated with\n    ",
      "endpoints": [
        {
          "description": "Create new [media_type](#media_type) object. Expects JSON. Fields shown in `MODEL COLUMNS` below. ",
          "endpoint": "/api/media_type",
          "method": "POST",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to ADMIN user only",
              "name": "assert_current_user_is_admin"
            },
            {
              "doc": "Restrict request to LOGGED IN users only",
              "name": "post_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get list of [media_type](#media_type) objects matching API query. See [Making API search queries](#api_query) for instructions on making search queries",
          "endpoint": "/api/media_type",
          "fields": [
            "id",
            "name"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_many_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get single [media_type](#media_type) object with pk field matching param `id`",
          "endpoint": "/api/media_type/<id>",
          "fields": [
            "id",
            "name"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_single_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Delete single [media_type](#media_type) object with pk field matching param `id`",
          "endpoint": "/api/media_type/<id>",
          "method": "DELETE",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to ADMIN user only",
              "name": "assert_current_user_is_admin"
            },
            {
              "doc": "Restrict request to OWNER only",
              "name": "delete_auth_preprocessor"
            }
          ]
        }
      ],
      "hybrid_properties": [],
      "methods": [],
      "relations": [
        {
          "direction": "ONETOMANY",
          "doc": null,
          "key": "media",
          "model": "media"
        }
      ]
    },
    {
      "association_proxies": [],
      "collection": "platform",
      "columns": [
        {
          "default": null,
          "doc": "Primary key `id`",
          "foreign_key": null,
          "name": "id",
          "nullable": false,
          "primary_key": true,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": "{}",
          "doc": "Text field containing JSON properties for this resource",
          "foreign_key": null,
          "name": "data",
          "nullable": true,
          "primary_key": false,
          "type": "JSON()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "name",
          "nullable": false,
          "primary_key": false,
          "type": "String(length=80)",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "key",
          "nullable": false,
          "primary_key": false,
          "type": "String(length=80)",
          "unique": true
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "description",
          "nullable": true,
          "primary_key": false,
          "type": "Text()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "reference",
          "nullable": true,
          "primary_key": false,
          "type": "Text()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": "users.id",
          "name": "user_id",
          "nullable": true,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": "function",
          "doc": null,
          "foreign_key": null,
          "name": "created_at",
          "nullable": false,
          "primary_key": false,
          "type": "DateTime()",
          "unique": null
        }
      ],
      "description": "\n    Platform resource: the equipment/method used to collect the imagery data (eg: a specific AUV, ROV or camera platform)\n    ",
      "endpoints": [
        {
          "description": "Create new [platform](#platform) object. Expects JSON. Fields shown in `MODEL COLUMNS` below. ",
          "endpoint": "/api/platform",
          "method": "POST",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to ADMIN user only",
              "name": "assert_current_user_is_admin"
            },
            {
              "doc": "Restrict request to LOGGED IN users only",
              "name": "post_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Update single [platform](#platform) object with pk field matching param `id`. Expects JSON. Fields shown in `MODEL COLUMNS` below.",
          "endpoint": "/api/platform/<id>",
          "method": "PATCH",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to ADMIN user only",
              "name": "assert_current_user_is_admin"
            },
            {
              "doc": "Restrict request to OWNER only",
              "name": "patch_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get list of [platform](#platform) objects matching API query. See [Making API search queries](#api_query) for instructions on making search queries",
          "endpoint": "/api/platform",
          "fields": [
            "created_at",
            "description",
            "id",
            "name",
            "reference",
            "user_id"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_many_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get single [platform](#platform) object with pk field matching param `id`",
          "endpoint": "/api/platform/<id>",
          "fields": [
            "created_at",
            "description",
            "id",
            "name",
            "reference",
            "user_id",
            "datasources",
            "data"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_single_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Delete single [platform](#platform) object with pk field matching param `id`",
          "endpoint": "/api/platform/<id>",
          "method": "DELETE",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to ADMIN user only",
              "name": "assert_current_user_is_admin"
            },
            {
              "doc": "Restrict request to OWNER only",
              "name": "delete_auth_preprocessor"
            }
          ]
        },
        {
          "description": "\n        Preview camera assignment for the media of this platform (nothing is changed): media counts and sample keys\n        per [camera_installation](#camera_installation), the observed pixel dimensions of their media, and the media\n        that would be unassigned, outside every installation's dates, matched by several installations or cleared.\n        A POST JSON body can contain unsaved `edits` (a list of installation dicts: with an `id` to change or, with\n        `\"_delete\": true`, remove a saved installation; without to add one) and `deployment_ids` to limit the preview.\n        Admins and custodians of a datasource of the platform.\n        ",
          "endpoint": "/api/platform/<int:id>/cameras/preview",
          "method": "GET"
        },
        {
          "description": "\n        Preview camera assignment for the media of this platform (nothing is changed): media counts and sample keys\n        per [camera_installation](#camera_installation), the observed pixel dimensions of their media, and the media\n        that would be unassigned, outside every installation's dates, matched by several installations or cleared.\n        A POST JSON body can contain unsaved `edits` (a list of installation dicts: with an `id` to change or, with\n        `\"_delete\": true`, remove a saved installation; without to add one) and `deployment_ids` to limit the preview.\n        Admins and custodians of a datasource of the platform.\n        ",
          "endpoint": "/api/platform/<int:id>/cameras/preview",
          "method": "POST"
        },
        {
          "description": "\n        Apply camera assignment to the existing media of this platform: queues a sync job (scope `cameras`) for each\n        datasource with deployments on the platform, run by the datasource worker (see `/api/datasource_sync_job`).\n        Manual assignments are kept. Datasources that already have an active job are skipped (`conflicts`: retry when\n        it is done). Admins and custodians of a datasource of the platform.\n        Returns `{\"jobs\": [{\"id\", \"datasource_id\", \"datasource_name\"}], \"conflicts\": [...]}` (202).\n        ",
          "endpoint": "/api/platform/<int:id>/cameras/apply",
          "method": "POST"
        },
        {
          "description": "\n        ADMIN: probe the pixel dimensions of media of this platform from their image headers (HTTP range requests of\n        the first bytes of `path_best`; video headers for videos). JSON body:\n        - `mode`: `sample` (probe `n` random media spread across deployments, default 20, and record them: to set or\n          verify an installation default; returns the sizes found, agreement with the default and a `suggested` size),\n          `estimate` (media in scope and estimated transfer, nothing is probed) or `backfill` (queue a `probe_dims`\n          datasource job per datasource, run by the datasource worker, that probes and records all media in scope).\n        - scope: `installation_id` (media of a camera installation) or `unassigned: true` (media without one),\n          `annotated: true` (only media with annotations), `only`: `all`, `unmeasured` (default: media without their\n          own dimensions) or `unresolved` (without their own nor an installation default), `deployment_ids`.\n        - `skip_default` (backfill, default true): do not store probed dimensions equal to the installation default.\n        Probed dimensions never replace dimensions observed by the UI or set manually (`dims_source`).\n        ",
          "endpoint": "/api/platform/<int:id>/cameras/probe",
          "method": "POST"
        }
      ],
      "hybrid_properties": [],
      "methods": [
        {
          "doc": null,
          "name": "current_user_is_owner",
          "type": "method"
        }
      ],
      "relations": [
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "user",
          "model": "users"
        },
        {
          "direction": "ONETOMANY",
          "doc": null,
          "key": "deployments",
          "model": "deployment"
        },
        {
          "direction": "ONETOMANY",
          "doc": null,
          "key": "datasources",
          "model": "datasource"
        },
        {
          "direction": "ONETOMANY",
          "doc": null,
          "key": "camera_installations",
          "model": "camera_installation"
        },
        {
          "direction": "ONETOMANY",
          "doc": null,
          "key": "layers",
          "model": "platform_maplayer"
        }
      ]
    },
    {
      "association_proxies": [],
      "collection": "platform_maplayer",
      "columns": [
        {
          "default": null,
          "doc": "Primary key `id`",
          "foreign_key": null,
          "name": "id",
          "nullable": false,
          "primary_key": true,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "name",
          "nullable": false,
          "primary_key": false,
          "type": "String(length=255)",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "baseurl",
          "nullable": false,
          "primary_key": false,
          "type": "String(length=255)",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "layertype",
          "nullable": false,
          "primary_key": false,
          "type": "String(length=128)",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "minzoom",
          "nullable": true,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "properties",
          "nullable": true,
          "primary_key": false,
          "type": "JSON(astext_type=Text())",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": "platform.id",
          "name": "platform_id",
          "nullable": true,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        }
      ],
      "description": "\n    Platform Map Layer resource: defines properties of additional map layers for each platform filtered by configurable parameters\n    ",
      "endpoints": [
        {
          "description": "Create new [platform_maplayer](#platform_maplayer) object. Expects JSON. Fields shown in `MODEL COLUMNS` below. A simple constructor that allows initialization from kwargs.\n\n    Sets attributes on the constructed instance using the names and\n    values in ``kwargs``.\n\n    Only keys that are present as\n    attributes of the instance's class are allowed. These could be,\n    for example, any mapped columns or relationships.\n    ",
          "endpoint": "/api/platform_maplayer",
          "method": "POST",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to ADMIN user only",
              "name": "assert_current_user_is_admin"
            },
            {
              "doc": "Restrict request to LOGGED IN users only",
              "name": "post_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Update single [platform_maplayer](#platform_maplayer) object with pk field matching param `id`. Expects JSON. Fields shown in `MODEL COLUMNS` below.",
          "endpoint": "/api/platform_maplayer/<id>",
          "method": "PATCH",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to ADMIN user only",
              "name": "assert_current_user_is_admin"
            },
            {
              "doc": "Restrict request to OWNER only",
              "name": "patch_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get list of [platform_maplayer](#platform_maplayer) objects matching API query. See [Making API search queries](#api_query) for instructions on making search queries",
          "endpoint": "/api/platform_maplayer",
          "fields": [
            "id",
            "name",
            "baseurl",
            "layertype",
            "minzoom",
            "properties",
            "platform",
            "platform.id",
            "platform.name",
            "platform.key",
            "platform.description"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_many_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get single [platform_maplayer](#platform_maplayer) object with pk field matching param `id`",
          "endpoint": "/api/platform_maplayer/<id>",
          "fields": [
            "id",
            "name",
            "baseurl",
            "layertype",
            "minzoom",
            "properties",
            "platform",
            "platform.id",
            "platform.name",
            "platform.key",
            "platform.description"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_single_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Delete single [platform_maplayer](#platform_maplayer) object with pk field matching param `id`",
          "endpoint": "/api/platform_maplayer/<id>",
          "method": "DELETE",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to ADMIN user only",
              "name": "assert_current_user_is_admin"
            },
            {
              "doc": "Restrict request to OWNER only",
              "name": "delete_auth_preprocessor"
            }
          ]
        }
      ],
      "hybrid_properties": [],
      "methods": [],
      "relations": [
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "platform",
          "model": "platform"
        }
      ]
    },
    {
      "association_proxies": [],
      "collection": "point",
      "columns": [
        {
          "default": null,
          "doc": "Primary key `id`",
          "foreign_key": null,
          "name": "id",
          "nullable": false,
          "primary_key": true,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": "{}",
          "doc": "Text field containing JSON properties for this resource",
          "foreign_key": null,
          "name": "data",
          "nullable": true,
          "primary_key": false,
          "type": "JSON()",
          "unique": null
        },
        {
          "default": null,
          "doc": "X location of point as a proportion across the frame width (0-1.0, measured from the left, positive right) or `latitude` for map objects",
          "foreign_key": null,
          "name": "x",
          "nullable": true,
          "primary_key": false,
          "type": "Float(precision=53)",
          "unique": false
        },
        {
          "default": null,
          "doc": "Y location of point as a proportion across the frame height (0-1.0, measured from the top, positive down) or `longitude` for map objects",
          "foreign_key": null,
          "name": "y",
          "nullable": true,
          "primary_key": false,
          "type": "Float(precision=53)",
          "unique": false
        },
        {
          "default": null,
          "doc": "Number of seconds of annotation relative to `media.start_time` (eg: for video)",
          "foreign_key": null,
          "name": "t",
          "nullable": true,
          "primary_key": false,
          "type": "Float(precision=53)",
          "unique": false
        },
        {
          "default": null,
          "doc": "Foreign key `id` of [media](#media) object linked to [point](#point)",
          "foreign_key": "media.id",
          "name": "media_id",
          "nullable": false,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": "Foreign key `id` of the parent/origin [annotation_set](#annotation_set). I.e.: the one linked to the initial creation of the [point](#point)",
          "foreign_key": "annotation_set.id",
          "name": "annotation_set_id",
          "nullable": false,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": "function",
          "doc": "Updated time (UTC)",
          "foreign_key": null,
          "name": "updated_at",
          "nullable": true,
          "primary_key": false,
          "type": "TIMESTAMP()",
          "unique": null
        },
        {
          "default": "False",
          "doc": "Flag denoting whether the Point was manually created to target a specific object",
          "foreign_key": null,
          "name": "is_targeted",
          "nullable": true,
          "primary_key": false,
          "type": "BOOLEAN()",
          "unique": null
        }
      ],
      "description": "\n    Annotation Point resource: an annotatable object on a media frame, captures x,y,t and can have multiple\n    [annotations](#annotation) associated with it. A [point](#point) can also be associated with a bounding box,\n    polygon, pixel map, etc... Each [point](#point) can have one or more [annotations](#annotation).\n    ",
      "endpoints": [
        {
          "description": "Update single [point](#point) object with pk field matching param `id`. Expects JSON. Fields shown in `MODEL COLUMNS` below.",
          "endpoint": "/api/point/<id>",
          "method": "PATCH",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Enforce implied permissions from parent [annotation_set](#annotation_set)",
              "name": "patch_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get list of [point](#point) objects matching API query. See [Making API search queries](#api_query) for instructions on making search queries",
          "endpoint": "/api/point",
          "fields": [
            "media_id",
            "annotation_set_id",
            "t",
            "x",
            "y",
            "supplementary_annotations",
            "data",
            "id",
            "timestamp",
            "annotations",
            "annotations.id",
            "annotations.annotation_set_id",
            "updated_at",
            "is_targeted",
            "has_polygon"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "\n        Filter results based on permissions from parent [annotation_set](#annotation_set)\n        ",
              "name": "get_many_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get single [point](#point) object with pk field matching param `id`",
          "endpoint": "/api/point/<id>",
          "fields": [
            "media_id",
            "annotation_set_id",
            "t",
            "x",
            "y",
            "supplementary_annotations",
            "data",
            "id",
            "timestamp",
            "annotations",
            "annotations.id",
            "annotations.annotation_set_id",
            "updated_at",
            "is_targeted",
            "has_polygon"
          ],
          "method": "GET",
          "postprocessors": [
            {
              "doc": "Adds `annotations` and `supplementary_annotations` fields to the response",
              "name": "get_single_postprocessor"
            }
          ],
          "preprocessors": [
            {
              "doc": "Enforce implied permissions from parent [annotation_set](#annotation_set)",
              "name": "get_single_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Delete single [point](#point) object with pk field matching param `id`",
          "endpoint": "/api/point/<id>",
          "method": "DELETE",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Enforce implied permissions from parent [annotation_set](#annotation_set)",
              "name": "delete_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Custom post endpoint",
          "endpoint": "/api/point",
          "method": "POST"
        },
        {
          "description": "\n        Dynamically create and serve thumbnail.\n\n        If user is logged in, then they can request different sizes.\n        ",
          "endpoint": "/api/point/<int:id>/thumbnail",
          "method": "GET"
        }
      ],
      "hybrid_properties": [
        {
          "args": [],
          "doc": "The in-situ timestamp for when the annotated object was captured/sampled in the media frame.\n        Returns `media.timestamp_start + t` if `t` is set, otherwise it just returns `media.timestamp_start` ",
          "name": "timestamp",
          "type": "property"
        },
        {
          "args": [],
          "doc": "BOOLEAN, whether or not the point has x-y coordinates. If `false`, it is a whole-frame annotation, not a point annotation",
          "name": "has_xy",
          "type": "property"
        },
        {
          "args": [],
          "doc": "BOOLEAN, whether or not the point has a polygon defined",
          "name": "has_polygon",
          "type": "property"
        },
        {
          "args": [
            "x",
            "y"
          ],
          "doc": "FLOAT, euclidean distance to `x` and `y` (which are proportions of the image width and height)",
          "name": "xy_distance",
          "type": "method"
        }
      ],
      "methods": [
        {
          "doc": "Returns bbox size in format [left, top, right, bottom] in relative coordinates, normalized to [0,1]",
          "name": "bbox",
          "type": "method"
        },
        {
          "doc": "**Returns** list of dicts `[{annotation_id:...,label_id:...}, ...]`\n\n        **SETTER** used to set a label based on lookup condition / parameters during batch annotation importing.\n        Parameters are passed by scalar value with query string properties or by setting value as dict.\n        The property value can be `scalar`, `dict`, `list of dicts` or `list of scalars`.\n\n        **Examples**\n        ```\n        # using a query\n        point.annotation_label = {\"filters\":[{\"name\":...,\"op\":...,\"val\":...}],\"comment\":...,\"likelihood\":...,\"needs_review\":...}\n        # using the origin code for the label\n        point.annotation_label = {\"origin_code\":...,\"comment\":...,\"likelihood\":...,\"needs_review\":...}\n        # using the label UUID\n        point.annotation_label = {\"uuid\":...,\"comment\":...,\"likelihood\":...,\"needs_review\":...}\n        # using the label ID (fastest)\n        point.annotation_label = {\"id\":...,\"comment\":...,\"likelihood\":...,\"needs_review\":...}\n        # To set multiple annotation labels per point, formulate dicts as above but combine in a list:\n        point.annotation_label = [{...}, ...]\n        ```\n        where `comment`, `likelihood` and `needs_review` are optional. Label search can be done using `origin_code`,\n        `uuid`, `id` and/or defining `filters`, which is a list of filter objects for the [label](#label) resource.\n        See [Making API search queries](#api_query).\n\n        Coming soon: setting labels using semantic translation (or vocab elements)\n        ",
          "name": "annotation_label",
          "type": "property"
        },
        {
          "doc": "Use to convert between native normalised `x`, `y` and `polygon` to pixel coordinates from top left.\n\n        **Returns** `x`, `y` and `polygon` converted to `col`, `row` and `polygon` values in pixel coordinates from top\n        left of frame using the pixel width and height of the\n        associated [media](#media) object and are set by the model definition as per the `pixel_width`\n        and `pixel_height` properties defined in the [media](#media) object resource, but\n        can be overridden by url parameters: `&pixel_width=<int:width>&pixel_height=<int:height>`.\n\n        **SETTER** convert from pixel coordinates `col`, `row` and `polygon` to to native normalised coords.\n        As above, pixel with and height can be overridden by the url parameters:\n        `&pixel_width=<int:width>&pixel_height=<int:height>`, and in addition, they can be set by dict parameters\n        `width` and `height`. If no `row` or `col` are defined, a centroid point is automatically computed for the `polygon`.\n        See examples below.\n\n        **Examples**\n        ```\n        # Convert x and y pixels to proportions using url params\n        # URL QS params &pixel_width=<int:width>&pixel_height=<int:height>\n        point.pixels = {\"col\":...,\"row\":...}\n        # Convert x and y pixels to proportions using property imports for each row/entry\n        point.pixels = {\"col\":...,\"row\":...,\"width\":...,\"height\":...}\n        # As above, but include a polygon in pixel coordinates that also needs to be converted\n        point.pixels = {..., \"polygon\": [[p1x, p1y],...]}\n        ```\n        where `col` and `row` are the point coordinates in pixels from the top-left of the frame.\n        `polygon` is optional and defines a list of lists containing x-y coordinates of polygon in pixels from top-left\n        of the frame.\n        ",
          "name": "pixels",
          "type": "property"
        },
        {
          "doc": "List of lists containing coordinated of vertices for polygons. Coordinates are in proportions of the image (0-1.0).\n        For point annotations, measurements are relative to point's xy location. For whole-frame annotations, they are absolute.\n        When setting this property, it can be a list of lists or a JSON string which will automatically be converted to a list of lists.",
          "name": "polygon",
          "type": "property"
        },
        {
          "doc": "Get closest linked pose to timestamp",
          "name": "pose",
          "type": "property"
        },
        {
          "doc": "**Returns** `media.key`\n\n        **SETTER** used to link the [media](#media) object to the point annotation during batch annotation importing.\n        If the matched [media](#media) object is not already in the associated [media_collection](#media_collection),\n        it is added. Matching is done on `media.key` and optionally `deployment.key` or `deployment.id`. Matching on\n        `media.key` can be very slow, plus it is not always guaranteed to be unique, so it is highly recommended you\n        include deployment info. If multiple matches are found, it will raise an error.\n        Deployment info can be set as a dict property or as a query string parameter.\n\n        **Examples**\n        ```\n        # Set media key as a scalar and use deployment ID from query string\n        # URL QS params: &deployment_id=407\n        point.set_media = \"PR_20150301_220629_593_LC16\"\n        # Set media key as a scalar and use deployment key from query string\n        # URL QS params: &deployment_key=r20150301_211555_01_TF_ABCDE_South_West_Mew_Stone\n        point.set_media = \"PR_20150301_220629_593_LC16\"\n        # Set media key and deployment key as dict\n        point.set_media = {\"key\":\"PR_20150301_220629_593_LC16\", \"deployment_key\":\"r20150301_211555_01_TF_ABCDE_South_West_Mew_Stone\"}\n        ```\n        ",
          "name": "set_media",
          "type": "property"
        }
      ],
      "relations": [
        {
          "direction": "MANYTOONE",
          "doc": "Related [media](#media) object",
          "key": "media",
          "model": "media"
        },
        {
          "direction": "MANYTOONE",
          "doc": "Parent/origin [annotation_set](#annotation_set) object",
          "key": "annotation_set",
          "model": "annotation_set"
        },
        {
          "direction": "ONETOMANY",
          "doc": "List of [annotation](#annotation) objects",
          "key": "annotations",
          "model": "annotation"
        }
      ]
    },
    {
      "association_proxies": [],
      "collection": "pose",
      "columns": [
        {
          "default": null,
          "doc": "Primary key `id`",
          "foreign_key": null,
          "name": "id",
          "nullable": false,
          "primary_key": true,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "lat",
          "nullable": true,
          "primary_key": false,
          "type": "Float(precision=53)",
          "unique": false
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "lon",
          "nullable": true,
          "primary_key": false,
          "type": "Float(precision=53)",
          "unique": false
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "alt",
          "nullable": true,
          "primary_key": false,
          "type": "Float()",
          "unique": false
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "dep",
          "nullable": true,
          "primary_key": false,
          "type": "Float()",
          "unique": false
        },
        {
          "default": "function",
          "doc": null,
          "foreign_key": null,
          "name": "timestamp",
          "nullable": false,
          "primary_key": false,
          "type": "DateTime()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": "media.id",
          "name": "media_id",
          "nullable": false,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "geom",
          "nullable": true,
          "primary_key": false,
          "type": "Geometry(geometry_type='POINT', srid=4326, from_text='ST_GeomFromEWKT', name='geometry')",
          "unique": null
        }
      ],
      "description": "\n    Pose resource: associates nav / sensor data to a [media](#media) item.\n    ",
      "endpoints": [
        {
          "description": "Create new [pose](#pose) object. Expects JSON. Fields shown in `MODEL COLUMNS` below. ",
          "endpoint": "/api/pose",
          "method": "POST",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict to custodians of the media item's datasource",
              "name": "post_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get list of [pose](#pose) objects matching API query. See [Making API search queries](#api_query) for instructions on making search queries",
          "endpoint": "/api/pose",
          "fields": [
            "id",
            "dep",
            "alt",
            "lat",
            "lon",
            "events",
            "timestamp",
            "media",
            "media.key",
            "media.id",
            "media.timestamp_start",
            "media.path_best_thm",
            "deployment",
            "campaign",
            "platform",
            "color",
            "media.path_best_thm",
            "data"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_many_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get single [pose](#pose) object with pk field matching param `id`",
          "endpoint": "/api/pose/<id>",
          "fields": [
            "id",
            "dep",
            "alt",
            "lat",
            "lon",
            "events",
            "timestamp",
            "media",
            "media.key",
            "media.id",
            "media.timestamp_start",
            "media.path_best_thm",
            "deployment",
            "campaign",
            "platform",
            "color",
            "media.path_best_thm",
            "data"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_single_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Delete single [pose](#pose) object with pk field matching param `id`",
          "endpoint": "/api/pose/<id>",
          "method": "DELETE",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to OWNER only",
              "name": "delete_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get stats for a pose. Accepts `q={}` filter parameters on pose object.\n        Returns a dictionary with the following keys: `dep_min`, `dep_max`, `dep_avg`, `alt_min`, `alt_max`, `alt_avg`, `lat_min`, `lat_max`, `lon_min`, `lon_max`.\n        If qs param `extended=true` is set, it also returns `count`, `ts_min`, `ts_max` and `media_count`.\n        ",
          "endpoint": "/api/pose/stats",
          "method": "GET"
        }
      ],
      "hybrid_properties": [
        {
          "args": [
            "lat",
            "lng"
          ],
          "doc": "FLOAT, distance (in meters) to `lat` and `lon` (which are both in decimal degrees)",
          "name": "distance",
          "type": "method"
        },
        {
          "args": [
            "lat",
            "lon"
          ],
          "doc": null,
          "name": "proximity",
          "type": "method"
        },
        {
          "args": [
            "ts"
          ],
          "doc": "Absolute difference in seconds of the in-situ timestamp and input `ts`, which is datetime string\n        eg: `\"2020-09-25T00:57:11.945009\"` (or in a format that is parsable by `dateutil.parser.parse`)",
          "name": "timestamp_proximity",
          "type": "method"
        }
      ],
      "methods": [
        {
          "doc": null,
          "name": "campaign",
          "type": "property"
        },
        {
          "doc": null,
          "name": "color",
          "type": "property"
        },
        {
          "doc": "Properties for related [pose](#pose) item including any linked [posedata](#posedata) fields",
          "name": "data",
          "type": "property"
        },
        {
          "doc": null,
          "name": "deployment",
          "type": "property"
        },
        {
          "doc": null,
          "name": "platform",
          "type": "property"
        },
        {
          "doc": "LOCAL datetime, converted using `lat`, `lon` and `timestamp`. SETTER converts Local to UTC",
          "name": "timestamp_local",
          "type": "property"
        }
      ],
      "relations": [
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "media",
          "model": "media"
        },
        {
          "direction": "ONETOMANY",
          "doc": null,
          "key": "_data",
          "model": "posedata"
        },
        {
          "direction": "ONETOMANY",
          "doc": null,
          "key": "events",
          "model": "deployment_event"
        }
      ]
    },
    {
      "association_proxies": [],
      "collection": "posedata",
      "columns": [
        {
          "default": null,
          "doc": "Primary key `id`",
          "foreign_key": null,
          "name": "id",
          "nullable": false,
          "primary_key": true,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "name",
          "nullable": false,
          "primary_key": false,
          "type": "String(length=80)",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "value",
          "nullable": true,
          "primary_key": false,
          "type": "Float()",
          "unique": false
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": "pose.id",
          "name": "pose_id",
          "nullable": false,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        }
      ],
      "description": "\n    Pose Data resource: enables linking of name-value data to [pose](#pose) objects. This can be used to attach additional\n    sensor information to each [pose](#pose) object (and by proxy to each [media](#media) object)\n    ",
      "endpoints": [
        {
          "description": "Create new [posedata](#posedata) object. Expects JSON. Fields shown in `MODEL COLUMNS` below. ",
          "endpoint": "/api/posedata",
          "method": "POST",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict to custodians of the pose's datasource",
              "name": "post_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get list of [posedata](#posedata) objects matching API query. See [Making API search queries](#api_query) for instructions on making search queries",
          "endpoint": "/api/posedata",
          "fields": [],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_many_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get single [posedata](#posedata) object with pk field matching param `id`",
          "endpoint": "/api/posedata/<id>",
          "fields": [],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_single_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Delete single [posedata](#posedata) object with pk field matching param `id`",
          "endpoint": "/api/posedata/<id>",
          "method": "DELETE",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to OWNER only",
              "name": "delete_auth_preprocessor"
            }
          ]
        }
      ],
      "hybrid_properties": [],
      "methods": [],
      "relations": [
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "pose",
          "model": "pose"
        }
      ]
    },
    {
      "association_proxies": [],
      "collection": "roles",
      "columns": [
        {
          "default": null,
          "doc": "Primary key `id`",
          "foreign_key": null,
          "name": "id",
          "nullable": false,
          "primary_key": true,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "name",
          "nullable": false,
          "primary_key": false,
          "type": "String(length=80)",
          "unique": true
        }
      ],
      "description": "\n    Not implemented yet. Not in use.\n    ",
      "endpoints": [
        {
          "description": "Create new [roles](#roles) object. Expects JSON. Fields shown in `MODEL COLUMNS` below. ",
          "endpoint": "/api/roles",
          "method": "POST",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to ADMIN user only",
              "name": "assert_current_user_is_admin"
            },
            {
              "doc": "Restrict request to LOGGED IN users only",
              "name": "post_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Update single [roles](#roles) object with pk field matching param `id`. Expects JSON. Fields shown in `MODEL COLUMNS` below.",
          "endpoint": "/api/roles/<id>",
          "method": "PATCH",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to ADMIN user only",
              "name": "assert_current_user_is_admin"
            },
            {
              "doc": "Restrict request to OWNER only",
              "name": "patch_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get list of [roles](#roles) objects matching API query. See [Making API search queries](#api_query) for instructions on making search queries",
          "endpoint": "/api/roles",
          "fields": [],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_many_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get single [roles](#roles) object with pk field matching param `id`",
          "endpoint": "/api/roles/<id>",
          "fields": [],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_single_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Delete single [roles](#roles) object with pk field matching param `id`",
          "endpoint": "/api/roles/<id>",
          "method": "DELETE",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to ADMIN user only",
              "name": "assert_current_user_is_admin"
            },
            {
              "doc": "Restrict request to OWNER only",
              "name": "delete_auth_preprocessor"
            }
          ]
        }
      ],
      "hybrid_properties": [],
      "methods": [],
      "relations": []
    },
    {
      "association_proxies": [
        {
          "model": "label",
          "name": "labels",
          "target_collection": "label_tags"
        }
      ],
      "collection": "tag",
      "columns": [
        {
          "default": null,
          "doc": "Primary key `id`",
          "foreign_key": null,
          "name": "id",
          "nullable": false,
          "primary_key": true,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "name",
          "nullable": false,
          "primary_key": false,
          "type": "String(length=80)",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": "users.id",
          "name": "user_id",
          "nullable": false,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": "tag_type.id",
          "name": "type_id",
          "nullable": true,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "description",
          "nullable": true,
          "primary_key": false,
          "type": "Text()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": "tag.id",
          "name": "synonym_tag_id",
          "nullable": true,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        }
      ],
      "description": "\n    Tag resource. Suggested tags can linked to class labels [label](#label) and tags can be assigned to annotations [annotation](#annotation)\n    ",
      "endpoints": [
        {
          "description": "Create new [tag](#tag) object. Expects JSON. Fields shown in `MODEL COLUMNS` below. ",
          "endpoint": "/api/tag",
          "method": "POST",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": null,
              "name": "post_preprocessor"
            },
            {
              "doc": "Restrict request to LOGGED IN users only",
              "name": "post_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Update single [tag](#tag) object with pk field matching param `id`. Expects JSON. Fields shown in `MODEL COLUMNS` below.",
          "endpoint": "/api/tag/<id>",
          "method": "PATCH",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to OWNER only",
              "name": "patch_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get list of [tag](#tag) objects matching API query. See [Making API search queries](#api_query) for instructions on making search queries",
          "endpoint": "/api/tag",
          "fields": [
            "user_id",
            "name",
            "type_id",
            "synonym_tag_id",
            "type",
            "id",
            "is_synonym",
            "type",
            "synonyms",
            "synonyms.name",
            "synonyms.id",
            "synonyms.user_id"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_many_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get single [tag](#tag) object with pk field matching param `id`",
          "endpoint": "/api/tag/<id>",
          "fields": [
            "user_id",
            "name",
            "type_id",
            "synonym_tag_id",
            "type",
            "id",
            "is_synonym",
            "type",
            "synonyms",
            "synonyms.name",
            "synonyms.id",
            "synonyms.user_id"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_single_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Delete single [tag](#tag) object with pk field matching param `id`",
          "endpoint": "/api/tag/<id>",
          "method": "DELETE",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to OWNER only",
              "name": "delete_auth_preprocessor"
            }
          ]
        }
      ],
      "hybrid_properties": [
        {
          "args": [],
          "doc": null,
          "name": "is_synonym",
          "type": "property"
        }
      ],
      "methods": [],
      "relations": [
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "user",
          "model": "users"
        },
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "type",
          "model": "tag_type"
        },
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "synonym_tag",
          "model": "tag"
        },
        {
          "direction": "ONETOMANY",
          "doc": null,
          "key": "synonyms",
          "model": "tag"
        },
        {
          "direction": "ONETOMANY",
          "doc": null,
          "key": "label_tags",
          "model": "label_tags"
        },
        {
          "direction": "ONETOMANY",
          "doc": "Collection of [annotation_tags](#annotation_tags) associations",
          "key": "annotation_tags",
          "model": "annotation_tags"
        }
      ]
    },
    {
      "association_proxies": [],
      "collection": "tag_type",
      "columns": [
        {
          "default": null,
          "doc": "Primary key `id`",
          "foreign_key": null,
          "name": "id",
          "nullable": false,
          "primary_key": true,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "name",
          "nullable": false,
          "primary_key": false,
          "type": "String(length=80)",
          "unique": true
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "description",
          "nullable": true,
          "primary_key": false,
          "type": "Text()",
          "unique": null
        }
      ],
      "description": "\n    Tag Type resource. A modifier denoting the type for a [tag](#tag) resource.\n    ",
      "endpoints": [
        {
          "description": "Create new [tag_type](#tag_type) object. Expects JSON. Fields shown in `MODEL COLUMNS` below. ",
          "endpoint": "/api/tag_type",
          "method": "POST",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to LOGGED IN users only",
              "name": "post_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Update single [tag_type](#tag_type) object with pk field matching param `id`. Expects JSON. Fields shown in `MODEL COLUMNS` below.",
          "endpoint": "/api/tag_type/<id>",
          "method": "PATCH",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to OWNER only",
              "name": "patch_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get list of [tag_type](#tag_type) objects matching API query. See [Making API search queries](#api_query) for instructions on making search queries",
          "endpoint": "/api/tag_type",
          "fields": [],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_many_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get single [tag_type](#tag_type) object with pk field matching param `id`",
          "endpoint": "/api/tag_type/<id>",
          "fields": [],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_single_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Delete single [tag_type](#tag_type) object with pk field matching param `id`",
          "endpoint": "/api/tag_type/<id>",
          "method": "DELETE",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to OWNER only",
              "name": "delete_auth_preprocessor"
            }
          ]
        }
      ],
      "hybrid_properties": [],
      "methods": [],
      "relations": [
        {
          "direction": "ONETOMANY",
          "doc": null,
          "key": "tags",
          "model": "tag"
        }
      ]
    },
    {
      "association_proxies": [],
      "collection": "usergroups",
      "columns": [
        {
          "default": null,
          "doc": null,
          "foreign_key": "users.id",
          "name": "user_id",
          "nullable": false,
          "primary_key": true,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": "groups.id",
          "name": "group_id",
          "nullable": false,
          "primary_key": true,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": "function",
          "doc": null,
          "foreign_key": null,
          "name": "created_at",
          "nullable": true,
          "primary_key": false,
          "type": "DateTime()",
          "unique": null
        },
        {
          "default": "False",
          "doc": null,
          "foreign_key": null,
          "name": "approved",
          "nullable": true,
          "primary_key": false,
          "type": "Boolean()",
          "unique": null
        },
        {
          "default": "False",
          "doc": null,
          "foreign_key": null,
          "name": "can_edit",
          "nullable": true,
          "primary_key": false,
          "type": "Boolean()",
          "unique": null
        },
        {
          "default": "False",
          "doc": null,
          "foreign_key": null,
          "name": "can_add_members",
          "nullable": true,
          "primary_key": false,
          "type": "Boolean()",
          "unique": null
        },
        {
          "default": "False",
          "doc": null,
          "foreign_key": null,
          "name": "can_share_data",
          "nullable": true,
          "primary_key": false,
          "type": "Boolean()",
          "unique": null
        },
        {
          "default": "False",
          "doc": null,
          "foreign_key": null,
          "name": "has_agreed",
          "nullable": true,
          "primary_key": false,
          "type": "Boolean()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": "users.id",
          "name": "added_by_user_id",
          "nullable": true,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        }
      ],
      "description": "\n    User / Group Association resource.\n    ",
      "endpoints": [
        {
          "description": "Get list of [usergroups](#usergroups) objects matching API query. See [Making API search queries](#api_query) for instructions on making search queries",
          "endpoint": "/api/usergroups",
          "fields": [
            "created_at",
            "approved",
            "can_edit",
            "added_by_user",
            "added_by_user.id",
            "added_by_user.first_name",
            "added_by_user.last_name",
            "user",
            "user.id",
            "user.username",
            "user.created_at",
            "user.last_login",
            "user.first_name",
            "user.last_name",
            "user.active",
            "user.is_admin",
            "group",
            "group.id",
            "group.name",
            "can_add_members",
            "can_share_data",
            "has_agreed",
            "group.is_public",
            "group.is_restricted",
            "group.user_id",
            "group.requires_approval",
            "group.requires_agreement",
            "group.group_type_id",
            "group.groupinfo",
            "group.created_at"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_many_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get single [usergroups](#usergroups) object with pk field matching param `group_id`",
          "endpoint": "/api/usergroups/<group_id>",
          "fields": [
            "created_at",
            "approved",
            "can_edit",
            "added_by_user",
            "added_by_user.id",
            "added_by_user.first_name",
            "added_by_user.last_name",
            "user",
            "user.id",
            "user.username",
            "user.created_at",
            "user.last_login",
            "user.first_name",
            "user.last_name",
            "user.active",
            "user.is_admin",
            "group",
            "group.id",
            "group.name",
            "can_add_members",
            "can_share_data",
            "has_agreed",
            "group.is_public",
            "group.is_restricted",
            "group.user_id",
            "group.requires_approval",
            "group.requires_agreement",
            "group.group_type_id",
            "group.groupinfo",
            "group.created_at"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_single_auth_preprocessor"
            }
          ]
        }
      ],
      "hybrid_properties": [],
      "methods": [],
      "relations": [
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "user",
          "model": "users"
        },
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "added_by_user",
          "model": "users"
        },
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "group",
          "model": "groups"
        }
      ]
    },
    {
      "association_proxies": [
        {
          "model": "group",
          "name": "affiliations",
          "target_collection": "affiliations_usergroups"
        }
      ],
      "collection": "users",
      "columns": [
        {
          "default": null,
          "doc": "Primary key `id`",
          "foreign_key": null,
          "name": "id",
          "nullable": false,
          "primary_key": true,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "username",
          "nullable": false,
          "primary_key": false,
          "type": "String(length=80)",
          "unique": true
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "email",
          "nullable": false,
          "primary_key": false,
          "type": "String(length=80)",
          "unique": true
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "password",
          "nullable": false,
          "primary_key": false,
          "type": "String(length=128)",
          "unique": null
        },
        {
          "default": "function",
          "doc": null,
          "foreign_key": null,
          "name": "created_at",
          "nullable": false,
          "primary_key": false,
          "type": "DateTime()",
          "unique": null
        },
        {
          "default": "now()",
          "doc": null,
          "foreign_key": null,
          "name": "last_login",
          "nullable": true,
          "primary_key": false,
          "type": "DateTime()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "first_name",
          "nullable": false,
          "primary_key": false,
          "type": "String(length=30)",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "last_name",
          "nullable": false,
          "primary_key": false,
          "type": "String(length=30)",
          "unique": null
        },
        {
          "default": "True",
          "doc": null,
          "foreign_key": null,
          "name": "active",
          "nullable": true,
          "primary_key": false,
          "type": "Boolean()",
          "unique": null
        },
        {
          "default": "False",
          "doc": null,
          "foreign_key": null,
          "name": "is_admin",
          "nullable": true,
          "primary_key": false,
          "type": "Boolean()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "info",
          "nullable": true,
          "primary_key": false,
          "type": "Text()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": "roles.id",
          "name": "role_id",
          "nullable": true,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "api_token",
          "nullable": true,
          "primary_key": false,
          "type": "String(length=80)",
          "unique": true
        }
      ],
      "description": "\n    User resource: captures all user information which is linked to most objects and resources.\n    ",
      "endpoints": [
        {
          "description": "Get list of [users](#users) objects matching API query. See [Making API search queries](#api_query) for instructions on making search queries",
          "endpoint": "/api/users",
          "fields": [
            "id",
            "user_created_at",
            "last_login",
            "first_name",
            "last_name",
            "username",
            "active",
            "info",
            "role",
            "affiliations",
            "affiliations.name",
            "affiliations.groupinfo",
            "affiliations.id",
            "affiliations_names"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_many_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get single [users](#users) object with pk field matching param `id`",
          "endpoint": "/api/users/<id>",
          "fields": [
            "id",
            "user_created_at",
            "last_login",
            "first_name",
            "last_name",
            "username",
            "active",
            "info",
            "role",
            "affiliations",
            "affiliations.name",
            "affiliations.groupinfo",
            "affiliations.id",
            "affiliations_names"
          ],
          "method": "GET",
          "postprocessors": [
            {
              "doc": null,
              "name": "get_single_postprocessor"
            }
          ],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_single_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Delete single [users](#users) object with pk field matching param `id`",
          "endpoint": "/api/users/<id>",
          "method": "DELETE",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to ADMIN user only",
              "name": "assert_current_user_is_admin"
            },
            {
              "doc": "Restrict request to OWNER only",
              "name": "delete_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Manage API token",
          "endpoint": "/api/users/api_token",
          "method": "GET"
        },
        {
          "description": "Manage API token",
          "endpoint": "/api/users/api_token",
          "method": "PATCH"
        },
        {
          "description": "Manage API token",
          "endpoint": "/api/users/api_token",
          "method": "DELETE"
        },
        {
          "description": "Manage group membership",
          "endpoint": "/api/users/<int:user_id>/group/<int:group_id>",
          "method": "POST"
        },
        {
          "description": "Manage group membership",
          "endpoint": "/api/users/<int:user_id>/group/<int:group_id>",
          "method": "DELETE"
        },
        {
          "description": "Manage group membership",
          "endpoint": "/api/users/<int:user_id>/group/<int:group_id>",
          "method": "PATCH"
        },
        {
          "description": "\n        Log in. Requires form parameters `username` and `password`.\n        ",
          "endpoint": "/api/users/login",
          "method": "POST"
        },
        {
          "description": "\n        Log out the current session\n        ",
          "endpoint": "/api/users/login",
          "method": "DELETE"
        },
        {
          "description": "Get information about current logged in user",
          "endpoint": "/api/users/login",
          "method": "GET"
        },
        {
          "description": "Update user information",
          "endpoint": "/api/users",
          "method": "POST"
        },
        {
          "description": "Update user information",
          "endpoint": "/api/users/<int:user_id>",
          "method": "PATCH"
        },
        {
          "description": null,
          "endpoint": "/api/users/reset_password",
          "method": "POST"
        },
        {
          "description": null,
          "endpoint": "/api/users/reset_password",
          "method": "GET"
        },
        {
          "description": null,
          "endpoint": "/api/users/reset_password/<token>",
          "method": "POST"
        },
        {
          "description": null,
          "endpoint": "/api/users/reset_password/<token>",
          "method": "GET"
        },
        {
          "description": "\n        Send an email to the user. Requires json post body containing `message` and optionally `subject`. If no\n        `subject`, default subject will be \"User message from PROJECT_NAME\"\n        ",
          "endpoint": "/api/users/<int:user_id>/email",
          "method": "POST"
        }
      ],
      "hybrid_properties": [],
      "methods": [
        {
          "doc": null,
          "name": "affiliations_names",
          "type": "method"
        },
        {
          "doc": null,
          "name": "full_name",
          "type": "method"
        },
        {
          "doc": null,
          "name": "get_id",
          "type": "method"
        },
        {
          "doc": null,
          "name": "is_active",
          "type": "method"
        },
        {
          "doc": null,
          "name": "is_anonymous",
          "type": "method"
        },
        {
          "doc": null,
          "name": "is_authenticated",
          "type": "method"
        }
      ],
      "relations": [
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "role",
          "model": "roles"
        },
        {
          "direction": "ONETOMANY",
          "doc": null,
          "key": "affiliations_usergroups",
          "model": "usergroups"
        },
        {
          "direction": "ONETOMANY",
          "doc": null,
          "key": "usergroups",
          "model": "usergroups"
        },
        {
          "direction": "ONETOMANY",
          "doc": null,
          "key": "datasource_custodianships",
          "model": "datasource_custodian"
        }
      ]
    },
    {
      "association_proxies": [],
      "collection": "vocab_element",
      "columns": [
        {
          "default": null,
          "doc": "Primary key `id`",
          "foreign_key": null,
          "name": "id",
          "nullable": false,
          "primary_key": true,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "name",
          "nullable": false,
          "primary_key": false,
          "type": "String(length=128)",
          "unique": false
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "key",
          "nullable": false,
          "primary_key": false,
          "type": "String(length=96)",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "lineage",
          "nullable": true,
          "primary_key": false,
          "type": "JSON()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "data",
          "nullable": true,
          "primary_key": false,
          "type": "JSON()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "mapped_registries",
          "nullable": true,
          "primary_key": false,
          "type": "JSON()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "description",
          "nullable": true,
          "primary_key": false,
          "type": "Text()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "parent_key",
          "nullable": true,
          "primary_key": false,
          "type": "String(length=96)",
          "unique": null
        },
        {
          "default": null,
          "doc": "The `id` of the `vocab_registry`",
          "foreign_key": "vocab_registry.key",
          "name": "vocab_registry_key",
          "nullable": false,
          "primary_key": false,
          "type": "String(length=96)",
          "unique": null
        },
        {
          "default": null,
          "doc": "The `id` of the user who created and owns this record",
          "foreign_key": "users.id",
          "name": "user_id",
          "nullable": false,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": "function",
          "doc": null,
          "foreign_key": null,
          "name": "created_at",
          "nullable": true,
          "primary_key": false,
          "type": "DateTime()",
          "unique": null
        },
        {
          "default": "function",
          "doc": "Updated time (UTC)",
          "foreign_key": null,
          "name": "updated_at",
          "nullable": true,
          "primary_key": false,
          "type": "TIMESTAMP()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "origin_updated_at",
          "nullable": true,
          "primary_key": false,
          "type": "DateTime()",
          "unique": null
        }
      ],
      "description": "\n    Vocab Element resource: locally cached version of element from [vocab_registry](#vocab_registry)\n    ",
      "endpoints": [
        {
          "description": "Create new [vocab_element](#vocab_element) object. Expects JSON. Fields shown in `MODEL COLUMNS` below. ",
          "endpoint": "/api/vocab_element",
          "method": "POST",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to LOGGED IN users only",
              "name": "post_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Update single [vocab_element](#vocab_element) object with pk field matching param `id`. Expects JSON. Fields shown in `MODEL COLUMNS` below.",
          "endpoint": "/api/vocab_element/<id>",
          "method": "PATCH",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to OWNER only",
              "name": "patch_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get list of [vocab_element](#vocab_element) objects matching API query. See [Making API search queries](#api_query) for instructions on making search queries",
          "endpoint": "/api/vocab_element",
          "fields": [
            "id",
            "name",
            "key",
            "parent_key",
            "vocab_registry",
            "vocab_registry.key",
            "vocab_registry.vocab_element_key_name",
            "vocab_registry.name",
            "vocab_registry.description",
            "created_at",
            "updated_at",
            "user",
            "user.id",
            "lineage",
            "user.first_name",
            "mapped_registries",
            "user.last_name",
            "other_names",
            "other_names.id",
            "other_names.name",
            "origin_updated_at",
            "reference_url",
            "reference_url_parent"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_many_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get single [vocab_element](#vocab_element) object with pk field matching param `id`",
          "endpoint": "/api/vocab_element/<id>",
          "fields": [
            "id",
            "name",
            "key",
            "parent_key",
            "vocab_registry",
            "vocab_registry.key",
            "vocab_registry.vocab_element_key_name",
            "vocab_registry.name",
            "vocab_registry.description",
            "created_at",
            "updated_at",
            "user",
            "user.id",
            "lineage",
            "user.first_name",
            "mapped_registries",
            "user.last_name",
            "other_names",
            "other_names.id",
            "other_names.name",
            "origin_updated_at",
            "reference_url",
            "reference_url_parent",
            "data",
            "description",
            "mapped_labels"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_single_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Delete single [vocab_element](#vocab_element) object with pk field matching param `id`",
          "endpoint": "/api/vocab_element/<id>",
          "method": "DELETE",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to OWNER only",
              "name": "delete_auth_preprocessor"
            }
          ]
        },
        {
          "description": null,
          "endpoint": "/api/vocab_element/<registry_key>/<element_key>",
          "method": "GET"
        },
        {
          "description": null,
          "endpoint": "/api/vocab_element/<registry_key>/<element_key>",
          "method": "POST"
        },
        {
          "description": null,
          "endpoint": "/api/vocab_element/<registry_key>/<element_key>",
          "method": "PATCH"
        },
        {
          "description": null,
          "endpoint": "/api/vocab_element/<registry_key>/<element_key>/label/<label_id>",
          "method": "POST"
        },
        {
          "description": null,
          "endpoint": "/api/vocab_element/<registry_key>/<element_key>/label/<label_id>",
          "method": "DELETE"
        },
        {
          "description": null,
          "endpoint": "/api/vocab_element/nested",
          "method": "GET"
        }
      ],
      "hybrid_properties": [],
      "methods": [
        {
          "doc": null,
          "name": "mapped_labels",
          "type": "method"
        },
        {
          "doc": null,
          "name": "reference_url",
          "type": "method"
        },
        {
          "doc": null,
          "name": "reference_url_parent",
          "type": "method"
        }
      ],
      "relations": [
        {
          "direction": "MANYTOONE",
          "doc": "The `vocab_registry` that contains this `vocab_element`",
          "key": "vocab_registry",
          "model": "vocab_registry"
        },
        {
          "direction": "MANYTOONE",
          "doc": "The user who owns or created and owns this record",
          "key": "user",
          "model": "users"
        },
        {
          "direction": "MANYTOMANY",
          "doc": "A list of `labels` linked to this `vocab_element`",
          "key": "labels",
          "model": "label"
        },
        {
          "direction": "ONETOMANY",
          "doc": null,
          "key": "other_names",
          "model": "vocab_element_names"
        },
        {
          "direction": "ONETOMANY",
          "doc": null,
          "key": "label_vocab_element",
          "model": "label_vocab_element"
        }
      ]
    },
    {
      "association_proxies": [],
      "collection": "vocab_element_names",
      "columns": [
        {
          "default": null,
          "doc": "Primary key `id`",
          "foreign_key": null,
          "name": "id",
          "nullable": false,
          "primary_key": true,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "name",
          "nullable": false,
          "primary_key": false,
          "type": "String(length=128)",
          "unique": false
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": "vocab_element.id",
          "name": "vocab_element_id",
          "nullable": false,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        }
      ],
      "description": "\n    VocabElement Names resource.\n    ",
      "endpoints": [
        {
          "description": "Create new [vocab_element_names](#vocab_element_names) object. Expects JSON. Fields shown in `MODEL COLUMNS` below. ",
          "endpoint": "/api/vocab_element_names",
          "method": "POST",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to LOGGED IN users only",
              "name": "post_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Update single [vocab_element_names](#vocab_element_names) object with pk field matching param `id`. Expects JSON. Fields shown in `MODEL COLUMNS` below.",
          "endpoint": "/api/vocab_element_names/<id>",
          "method": "PATCH",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to OWNER only",
              "name": "patch_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get list of [vocab_element_names](#vocab_element_names) objects matching API query. See [Making API search queries](#api_query) for instructions on making search queries",
          "endpoint": "/api/vocab_element_names",
          "fields": [],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_many_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get single [vocab_element_names](#vocab_element_names) object with pk field matching param `id`",
          "endpoint": "/api/vocab_element_names/<id>",
          "fields": [],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_single_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Delete single [vocab_element_names](#vocab_element_names) object with pk field matching param `id`",
          "endpoint": "/api/vocab_element_names/<id>",
          "method": "DELETE",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to OWNER only",
              "name": "delete_auth_preprocessor"
            }
          ]
        }
      ],
      "hybrid_properties": [],
      "methods": [],
      "relations": [
        {
          "direction": "MANYTOONE",
          "doc": null,
          "key": "vocab_element",
          "model": "vocab_element"
        }
      ]
    },
    {
      "association_proxies": [],
      "collection": "vocab_registry",
      "columns": [
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "key",
          "nullable": false,
          "primary_key": true,
          "type": "String(length=96)",
          "unique": true
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "name",
          "nullable": false,
          "primary_key": false,
          "type": "String(length=128)",
          "unique": true
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "module",
          "nullable": false,
          "primary_key": false,
          "type": "String(length=96)",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "module_kwargs",
          "nullable": true,
          "primary_key": false,
          "type": "JSON()",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "vocab_element_key_name",
          "nullable": true,
          "primary_key": false,
          "type": "String(length=96)",
          "unique": null
        },
        {
          "default": null,
          "doc": null,
          "foreign_key": null,
          "name": "description",
          "nullable": true,
          "primary_key": false,
          "type": "Text()",
          "unique": null
        },
        {
          "default": null,
          "doc": "The `id` of the user who created and owns this record",
          "foreign_key": "users.id",
          "name": "user_id",
          "nullable": false,
          "primary_key": false,
          "type": "Integer()",
          "unique": null
        },
        {
          "default": "function",
          "doc": null,
          "foreign_key": null,
          "name": "created_at",
          "nullable": true,
          "primary_key": false,
          "type": "DateTime()",
          "unique": null
        },
        {
          "default": "function",
          "doc": "Updated time (UTC)",
          "foreign_key": null,
          "name": "updated_at",
          "nullable": true,
          "primary_key": false,
          "type": "TIMESTAMP()",
          "unique": null
        }
      ],
      "description": "\n    Vacab Registry resource: defines a mapping to a vocab registry module and handles interactions with them.\n    ",
      "endpoints": [
        {
          "description": "Create new [vocab_registry](#vocab_registry) object. Expects JSON. Fields shown in `MODEL COLUMNS` below. A simple constructor that allows initialization from kwargs.\n\n    Sets attributes on the constructed instance using the names and\n    values in ``kwargs``.\n\n    Only keys that are present as\n    attributes of the instance's class are allowed. These could be,\n    for example, any mapped columns or relationships.\n    ",
          "endpoint": "/api/vocab_registry",
          "method": "POST",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to ADMIN user only",
              "name": "assert_current_user_is_admin"
            },
            {
              "doc": "Restrict request to LOGGED IN users only",
              "name": "post_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Update single [vocab_registry](#vocab_registry) object with pk field matching param `key`. Expects JSON. Fields shown in `MODEL COLUMNS` below.",
          "endpoint": "/api/vocab_registry/<key>",
          "method": "PATCH",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to ADMIN user only",
              "name": "assert_current_user_is_admin"
            },
            {
              "doc": "Restrict request to OWNER only",
              "name": "patch_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get list of [vocab_registry](#vocab_registry) objects matching API query. See [Making API search queries](#api_query) for instructions on making search queries",
          "endpoint": "/api/vocab_registry",
          "fields": [
            "key",
            "name",
            "description",
            "created_at",
            "updated_at",
            "user",
            "user.id",
            "user.first_name",
            "user.last_name",
            "vocab_element_key_name",
            "module",
            "module_kwargs",
            "registry_urls"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_many_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Get single [vocab_registry](#vocab_registry) object with pk field matching param `key`",
          "endpoint": "/api/vocab_registry/<key>",
          "fields": [
            "key",
            "name",
            "description",
            "created_at",
            "updated_at",
            "user",
            "user.id",
            "user.first_name",
            "user.last_name",
            "vocab_element_key_name",
            "module",
            "module_kwargs",
            "registry_urls"
          ],
          "method": "GET",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Allow all requests",
              "name": "get_single_auth_preprocessor"
            }
          ]
        },
        {
          "description": "Delete single [vocab_registry](#vocab_registry) object with pk field matching param `key`",
          "endpoint": "/api/vocab_registry/<key>",
          "method": "DELETE",
          "postprocessors": [],
          "preprocessors": [
            {
              "doc": "Restrict request to ADMIN user only",
              "name": "assert_current_user_is_admin"
            },
            {
              "doc": "Restrict request to OWNER only",
              "name": "delete_auth_preprocessor"
            }
          ]
        },
        {
          "description": null,
          "endpoint": "/api/vocab_registry/<key>/match",
          "method": "GET"
        },
        {
          "description": null,
          "endpoint": "/api/vocab_registry/<key>/get_element",
          "method": "GET"
        },
        {
          "description": null,
          "endpoint": "/api/vocab_registry/<key>/get_all_elements",
          "method": "GET"
        },
        {
          "description": null,
          "endpoint": "/api/vocab_registry/<key>/get_children",
          "method": "GET"
        }
      ],
      "hybrid_properties": [],
      "methods": [
        {
          "doc": null,
          "name": "registry_urls",
          "type": "method"
        },
        {
          "doc": null,
          "name": "registry_plugin",
          "type": "property"
        }
      ],
      "relations": [
        {
          "direction": "MANYTOONE",
          "doc": "The user who owns or created and owns this record",
          "key": "user",
          "model": "users"
        },
        {
          "direction": "ONETOMANY",
          "doc": null,
          "key": "vocab_elements",
          "model": "vocab_element"
        }
      ]
    }
  ]
}