{"openrpc":"1.3.2","info":{"title":"Darwin public API","version":"v1","description":"Read the analytics of your Darwin projects.\n\nThe API is **experimental**: a method, a field or a limit can change or go without notice.\n\nEvery call needs an API key. Create one on the key management page at `/`, then send it as\n`Authorization: Bearer <key>`. A key reads the organizations you chose when you created it, as\nlong as you can still read them.\n"},"servers":[{"name":"json-rpc","url":"https://developer.darwindata.ai/public/v1/json-rpc"},{"name":"websocket","url":"wss://developer.darwindata.ai/public/v1/ws"}],"methods":[{"name":"projects/list","summary":"The projects your key may read, in all its organizations.","description":"Answers the projects of every organization your key reads, from the oldest to the newest.\n\nPage with `page.limit` and the `nextCursor` of the previous page. The last page has no\n`nextCursor`. A project created after your first page comes on the last page.\n\nThe analytics methods read a project only when its `state` is `computed`: an assessment of the\nproject completed. While a new assessment runs, the project stays `computed`, and the analytics\nmethods read the previous assessment until the snapshot of the new one is sealed.\n","tags":[{"name":"projects"}],"paramStructure":"by-name","params":[{"name":"page","required":false,"schema":{"type":"object","properties":{"limit":{"type":"integer","format":"uint32","minimum":1,"maximum":500,"default":100,"description":"How many items to return."},"cursor":{"anyOf":[{"$ref":"#/components/schemas/Cursor"},{"type":"null"}],"description":"The `nextCursor` of the previous page. Omit it for the first page."}},"description":"Which page to return. Omit it for the first page, at the default size.","default":{"limit":100}},"description":"Which page to return. Omit it for the first page, at the default size."}],"result":{"name":"result","schema":{"$ref":"#/components/schemas/ProjectSummaryList"}},"errors":[{"code":-32700,"message":"PARSE_ERROR"},{"code":-32600,"message":"INVALID_REQUEST"},{"code":-32601,"message":"METHOD_NOT_FOUND"},{"code":-32602,"message":"INVALID_PARAMS"},{"code":-32603,"message":"INTERNAL"},{"code":1401,"message":"UNAUTHENTICATED"},{"code":1403,"message":"FORBIDDEN"},{"code":1429,"message":"RATE_LIMITED"},{"code":1503,"message":"UNAVAILABLE"}],"examples":[{"name":"The first page","params":[]},{"name":"Two projects per page","params":[{"name":"page","value":{"limit":2}}]}],"deprecated":false,"x-darwin-stability":"experimental","x-darwin-access":{"kind":"caller"}},{"name":"projects/describe","summary":"The relations projects/query can read, and the columns of one.","description":"Answers what `projects/query` can read in a project: every relation, what one row of it is, and\nworked queries.\n\nName a relation in `relation` to get its columns and their SQL types, read from the snapshot of\nthe project. The relations whose `kind` is `fold` are computed from the snapshot for the point of\nview of the query, most of them aggregations: read them rather than rebuild a total from the\ntables.\n\nThe catalogue is the same for every project. The columns need a sealed snapshot of the project:\nbefore the first one, the answer is `NOT_READY`. They are built within 60 seconds; past it, the\nanswer is `UNAVAILABLE`: retry later.\n","tags":[{"name":"projects"}],"paramStructure":"by-name","params":[{"name":"projectId","required":true,"schema":{"description":"The id of the project, a UUID. `projects/list` gives the ids your key may read.","allOf":[{"$ref":"#/components/schemas/ProjectId"}]},"description":"The id of the project, a UUID. `projects/list` gives the ids your key may read."},{"name":"relation","required":false,"schema":{"type":["string","null"],"description":"A relation of the catalogue, e.g. `fold_risks`. Give it to get its columns and their types.","default":null},"description":"A relation of the catalogue, e.g. `fold_risks`. Give it to get its columns and their types."}],"result":{"name":"result","schema":{"$ref":"#/components/schemas/ProjectDescription"}},"errors":[{"code":-32700,"message":"PARSE_ERROR"},{"code":-32600,"message":"INVALID_REQUEST"},{"code":-32601,"message":"METHOD_NOT_FOUND"},{"code":-32602,"message":"INVALID_PARAMS"},{"code":-32603,"message":"INTERNAL"},{"code":1401,"message":"UNAUTHENTICATED"},{"code":1403,"message":"FORBIDDEN"},{"code":1429,"message":"RATE_LIMITED"},{"code":1503,"message":"UNAVAILABLE"},{"code":1409,"message":"NOT_READY"}],"examples":[{"name":"The catalogue","params":[{"name":"projectId","value":"$projectId"}]},{"name":"The columns of the risks","params":[{"name":"projectId","value":"$projectId"},{"name":"relation","value":"fold_risks"}]}],"deprecated":false,"x-darwin-stability":"experimental","x-darwin-access":{"kind":"scoped","scope":"projectAnalytics"}},{"name":"projects/query","summary":"One read-only SQL query over the analytics of a project.","description":"Runs one read-only SQL query over the analytics of a project, and answers its rows as JSON\nobjects, one page at a time.\n\n- `sql` is one `SELECT` over the relations of `projects/describe`, or a `UNION`, `EXCEPT` or\n  `INTERSECT` of them, with an optional `WITH`. A statement that writes, a second statement, and\n  a read of a file outside the project's own analytics are refused with `INVALID_QUERY`. So is a\n  query that fails on its own text, and a single row larger than 4 MiB as JSON.\n- The query reads the point of view of `entityId` and its subtree, or of the whole project when\n  `entityId` is absent, with `net` or `gross` ownership.\n- It reads the latest sealed snapshot of the project, which can belong to an assessment that still\n  runs. Before the first one, the answer is `NOT_READY`.\n\nThe numbers are the ones the screens compute, with three differences:\n\n- The risks a user excluded are not in `fold_risks` and `risk_rows`. The screens keep them in\n  their totals, so a total here can be lower.\n- An entity with no dependency data of its own has no row in `fold_dependencies`. The screens\n  show a sector estimate for it.\n- The relations carry no sourcing risk: the screens add it to the commodities.\n\nLimits:\n\n- The relations the query names are built first, within 60 seconds. Past it, the answer is\n  `UNAVAILABLE`: retry later.\n- The query then has 30 seconds. Past it, the answer is `QUERY_TIMEOUT`. A query that runs out of\n  memory answers `QUERY_TOO_LARGE`. Narrow the query in both cases, because a retry fails the same\n  way.\n- A call waits 5 seconds at most for a free connection, then answers `UNAVAILABLE`.\n\nPage with `page.limit` and the `nextCursor` of the previous page. Send the same `sql`, `entityId`\nand `ownershipView` with it. The last page has no `nextCursor`. The cursor counts rows: order the\nrows on a unique key, or a row can move between two pages. A page stops early when its rows hold\nmore than 4 MiB as JSON: follow its `nextCursor`. When a new assessment replaces the snapshot\nbetween two pages, the cursor answers `INVALID_PARAMS`: start again from the first page.\n","tags":[{"name":"projects"}],"paramStructure":"by-name","params":[{"name":"projectId","required":true,"schema":{"description":"The id of the project, a UUID. `projects/list` gives the ids your key may read.","allOf":[{"$ref":"#/components/schemas/ProjectId"}]},"description":"The id of the project, a UUID. `projects/list` gives the ids your key may read."},{"name":"entityId","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/EntityId"},{"type":"null"}],"description":"The entity whose subtree the query reads, a UUID. Omit it for the whole project.","default":null},"description":"The entity whose subtree the query reads, a UUID. Omit it for the whole project."},{"name":"ownershipView","required":false,"schema":{"default":"net","description":"`net` (the default) or `gross`.","allOf":[{"$ref":"#/components/schemas/OwnershipView"}]},"description":"`net` (the default) or `gross`."},{"name":"sql","required":true,"schema":{"type":"string","description":"One `SELECT` over the relations of `projects/describe`, or a `UNION`, `EXCEPT` or\n`INTERSECT` of them, with an optional `WITH`. Anything else is refused. Order the rows on a\nunique key to page them."},"description":"One `SELECT` over the relations of `projects/describe`, or a `UNION`, `EXCEPT` or\n`INTERSECT` of them, with an optional `WITH`. Anything else is refused. Order the rows on a\nunique key to page them."},{"name":"page","required":false,"schema":{"type":"object","properties":{"limit":{"type":"integer","format":"uint32","minimum":1,"maximum":500,"default":100,"description":"How many items to return."},"cursor":{"anyOf":[{"$ref":"#/components/schemas/Cursor"},{"type":"null"}],"description":"The `nextCursor` of the previous page. Omit it for the first page."}},"description":"Which page of rows to return. Omit it for the first page, at the default size. Send the\nsame `sql`, `entityId` and `ownershipView` with a `cursor`.","default":{"limit":100}},"description":"Which page of rows to return. Omit it for the first page, at the default size. Send the\nsame `sql`, `entityId` and `ownershipView` with a `cursor`."}],"result":{"name":"result","schema":{"$ref":"#/components/schemas/RowList"}},"errors":[{"code":-32700,"message":"PARSE_ERROR"},{"code":-32600,"message":"INVALID_REQUEST"},{"code":-32601,"message":"METHOD_NOT_FOUND"},{"code":-32602,"message":"INVALID_PARAMS"},{"code":-32603,"message":"INTERNAL"},{"code":1401,"message":"UNAUTHENTICATED"},{"code":1403,"message":"FORBIDDEN"},{"code":1429,"message":"RATE_LIMITED"},{"code":1503,"message":"UNAVAILABLE"},{"code":1404,"message":"NOT_FOUND"},{"code":1409,"message":"NOT_READY"},{"code":1422,"message":"INVALID_QUERY"},{"code":1408,"message":"QUERY_TIMEOUT"},{"code":1413,"message":"QUERY_TOO_LARGE"}],"examples":[{"name":"The impact by IPBES pressure","params":[{"name":"projectId","value":"$projectId"},{"name":"sql","value":"SELECT ipbes_pressure, value FROM dash_ipbes ORDER BY value DESC"}]},{"name":"The ten largest pressures, gross","params":[{"name":"projectId","value":"$projectId"},{"name":"ownershipView","value":"gross"},{"name":"sql","value":"SELECT pressure_indicator, unit, biome, scope, net FROM fold_pressures ORDER BY abs(net) DESC, pressure_indicator, biome, scope"},{"name":"page","value":{"limit":10}}]}],"deprecated":false,"x-darwin-stability":"experimental","x-darwin-access":{"kind":"scoped","scope":"projectAnalytics"}},{"name":"projects/export","summary":"One read-only SQL query over the analytics of a project, as a parquet file.","description":"Runs one read-only SQL query over the analytics of a project, writes all its rows to one parquet\nfile, and answers a URL to download it. Use it for a relation too large to page with\n`projects/query`.\n\n- `sql`, `entityId` and `ownershipView` are those of `projects/query`, with the same rules and the\n  same three differences from the screens. There is no page and no 4 MiB limit on a row: the file\n  holds every row.\n- The answer is `url`, `expiresAt`, `rows` and `bytes`. Download the file with a plain `GET` on\n  `url`, with no header: the URL carries its own signature. It stops working at `expiresAt`, 15\n  minutes after the call. Call again for a new URL.\n- Each call writes a new file. The storage removes it about one day later.\n\nLimits:\n\n- The relations the query names are built first, within 60 seconds. Past it, the answer is\n  `UNAVAILABLE`: retry later.\n- The query then has 120 seconds. Past it, the answer is `QUERY_TIMEOUT`. A query that runs out of\n  memory answers `QUERY_TOO_LARGE`. So does a file that grows past 1 GiB: the query stops there.\n  Narrow the query in both cases, because a retry fails the same way.\n- A call waits 5 seconds at most for a free connection, then answers `UNAVAILABLE`.\n","tags":[{"name":"projects"}],"paramStructure":"by-name","params":[{"name":"projectId","required":true,"schema":{"description":"The id of the project, a UUID. `projects/list` gives the ids your key may read.","allOf":[{"$ref":"#/components/schemas/ProjectId"}]},"description":"The id of the project, a UUID. `projects/list` gives the ids your key may read."},{"name":"entityId","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/EntityId"},{"type":"null"}],"description":"The entity whose subtree the query reads, a UUID. Omit it for the whole project.","default":null},"description":"The entity whose subtree the query reads, a UUID. Omit it for the whole project."},{"name":"ownershipView","required":false,"schema":{"default":"net","description":"`net` (the default) or `gross`.","allOf":[{"$ref":"#/components/schemas/OwnershipView"}]},"description":"`net` (the default) or `gross`."},{"name":"sql","required":true,"schema":{"type":"string","description":"One `SELECT` over the relations of `projects/describe`, or a `UNION`, `EXCEPT` or\n`INTERSECT` of them, with an optional `WITH`. Anything else is refused."},"description":"One `SELECT` over the relations of `projects/describe`, or a `UNION`, `EXCEPT` or\n`INTERSECT` of them, with an optional `WITH`. Anything else is refused."}],"result":{"name":"result","schema":{"$ref":"#/components/schemas/ProjectExport"}},"errors":[{"code":-32700,"message":"PARSE_ERROR"},{"code":-32600,"message":"INVALID_REQUEST"},{"code":-32601,"message":"METHOD_NOT_FOUND"},{"code":-32602,"message":"INVALID_PARAMS"},{"code":-32603,"message":"INTERNAL"},{"code":1401,"message":"UNAUTHENTICATED"},{"code":1403,"message":"FORBIDDEN"},{"code":1429,"message":"RATE_LIMITED"},{"code":1503,"message":"UNAVAILABLE"},{"code":1404,"message":"NOT_FOUND"},{"code":1409,"message":"NOT_READY"},{"code":1422,"message":"INVALID_QUERY"},{"code":1408,"message":"QUERY_TIMEOUT"},{"code":1413,"message":"QUERY_TOO_LARGE"}],"examples":[{"name":"Every dependency row of the project","params":[{"name":"projectId","value":"$projectId"},{"name":"sql","value":"SELECT * FROM dependency_rows"}]}],"deprecated":false,"x-darwin-stability":"experimental","x-darwin-access":{"kind":"scoped","scope":"projectAnalytics"}}],"components":{"schemas":{"ProjectsListInput":{"type":"object","properties":{"page":{"type":"object","properties":{"limit":{"type":"integer","format":"uint32","minimum":1,"maximum":500,"default":100,"description":"How many items to return."},"cursor":{"anyOf":[{"$ref":"#/components/schemas/Cursor"},{"type":"null"}],"description":"The `nextCursor` of the previous page. Omit it for the first page."}},"description":"Which page to return. Omit it for the first page, at the default size.","default":{"limit":100}}},"description":"The projects that the key may read, one page at a time."},"Cursor":{"type":"string","description":"A position in a list, as the previous page returned it. The caller never builds one."},"ProjectSummaryList":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/ProjectSummary"},"description":"The items of this page. Empty when the list is empty."},"nextCursor":{"anyOf":[{"$ref":"#/components/schemas/Cursor"},{"type":"null"}],"description":"Absent on the last page."}},"required":["items"],"description":"One page of a list."},"ProjectSummary":{"type":"object","properties":{"projectId":{"description":"The id of the project, a UUID.","allOf":[{"$ref":"#/components/schemas/ProjectId"}]},"name":{"type":"string","description":"The name of the project, as Darwin shows it."},"organization":{"description":"The key of the organization that owns the project.","allOf":[{"$ref":"#/components/schemas/OrganizationKey"}]},"state":{"description":"Whether the analytics methods can read the project now.","allOf":[{"$ref":"#/components/schemas/ProjectState"}]}},"required":["projectId","name","organization","state"],"description":"One project the key may read."},"ProjectId":{"type":"string","format":"uuid"},"OrganizationKey":{"type":"string","description":"The key of an organization, such as `darwin`."},"ProjectState":{"oneOf":[{"type":"string","const":"computed","description":"An assessment completed: the analytics methods can read the project. While a new\nassessment runs, they read the previous one until the snapshot of the new one is sealed."},{"type":"string","const":"computing","description":"The first assessment runs: nothing can be read yet."},{"type":"string","const":"notComputed","description":"No assessment completed, and none runs: nothing can be read."}],"description":"Whether the analytics methods can read the project. They read the snapshot of the last\ncompleted assessment."},"ProjectsDescribeInput":{"type":"object","properties":{"projectId":{"description":"The id of the project, a UUID. `projects/list` gives the ids your key may read.","allOf":[{"$ref":"#/components/schemas/ProjectId"}]},"relation":{"type":["string","null"],"description":"A relation of the catalogue, e.g. `fold_risks`. Give it to get its columns and their types.","default":null}},"required":["projectId"],"description":"The project to describe, and optionally one of its relations."},"ProjectDescription":{"type":"object","properties":{"relations":{"type":"array","items":{"$ref":"#/components/schemas/RelationSummary"},"description":"Every relation a query may read, the computed ones first."},"examples":{"type":"array","items":{"$ref":"#/components/schemas/QueryExample"},"description":"Worked queries, each with the question it answers."},"columns":{"type":["array","null"],"items":{"$ref":"#/components/schemas/Column"},"description":"The columns of the relation of the input, in order. Absent when the input names none."}},"required":["relations","examples"],"description":"The catalogue of the relations, and the columns of one relation when the input names one."},"RelationSummary":{"type":"object","properties":{"name":{"type":"string","description":"The name to write in `FROM`."},"kind":{"$ref":"#/components/schemas/RelationKind"},"about":{"type":["string","null"],"description":"What one row is. Absent for a table, whose columns say it."}},"required":["name","kind"],"description":"One relation a query may name in `FROM`."},"RelationKind":{"oneOf":[{"type":"string","const":"fold","description":"A relation Darwin computes from the snapshot for the point of view of the query, most of\nthem aggregations. Read one rather than rebuild a total from the tables."},{"type":"string","const":"table","description":"A table of the assessment, as Darwin stored it."}]},"QueryExample":{"type":"object","properties":{"question":{"type":"string","description":"The question the query answers."},"sql":{"type":"string","description":"The `sql` to send to `projects/query`."}},"required":["question","sql"],"description":"A worked query."},"Column":{"type":"object","properties":{"name":{"type":"string","description":"The name to write in a query."},"type":{"type":"string","description":"The SQL type of the column, e.g. `VARCHAR`, `DOUBLE`, `UUID`."}},"required":["name","type"],"description":"One column of a relation."},"ProjectsQueryInput":{"type":"object","properties":{"projectId":{"description":"The id of the project, a UUID. `projects/list` gives the ids your key may read.","allOf":[{"$ref":"#/components/schemas/ProjectId"}]},"entityId":{"anyOf":[{"$ref":"#/components/schemas/EntityId"},{"type":"null"}],"description":"The entity whose subtree the query reads, a UUID. Omit it for the whole project.","default":null},"ownershipView":{"default":"net","description":"`net` (the default) or `gross`.","allOf":[{"$ref":"#/components/schemas/OwnershipView"}]},"sql":{"type":"string","description":"One `SELECT` over the relations of `projects/describe`, or a `UNION`, `EXCEPT` or\n`INTERSECT` of them, with an optional `WITH`. Anything else is refused. Order the rows on a\nunique key to page them."},"page":{"type":"object","properties":{"limit":{"type":"integer","format":"uint32","minimum":1,"maximum":500,"default":100,"description":"How many items to return."},"cursor":{"anyOf":[{"$ref":"#/components/schemas/Cursor"},{"type":"null"}],"description":"The `nextCursor` of the previous page. Omit it for the first page."}},"description":"Which page of rows to return. Omit it for the first page, at the default size. Send the\nsame `sql`, `entityId` and `ownershipView` with a `cursor`.","default":{"limit":100}}},"required":["projectId","sql"],"description":"One read-only SQL query over the analytics of a project."},"EntityId":{"type":"string","format":"uuid"},"OwnershipView":{"oneOf":[{"type":"string","const":"net","description":"Each entity counts at the ownership share along the path. The screens' default."},{"type":"string","const":"gross","description":"Each entity counts at 100%, whatever the ownership."}],"description":"Net or gross ownership."},"RowList":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Row"},"description":"The items of this page. Empty when the list is empty."},"nextCursor":{"anyOf":[{"$ref":"#/components/schemas/Cursor"},{"type":"null"}],"description":"Absent on the last page."}},"required":["items"],"description":"One page of a list."},"Row":{"type":"object","additionalProperties":true,"description":"One row of the result: each column name, with its value."},"ProjectsExportInput":{"type":"object","properties":{"projectId":{"description":"The id of the project, a UUID. `projects/list` gives the ids your key may read.","allOf":[{"$ref":"#/components/schemas/ProjectId"}]},"entityId":{"anyOf":[{"$ref":"#/components/schemas/EntityId"},{"type":"null"}],"description":"The entity whose subtree the query reads, a UUID. Omit it for the whole project.","default":null},"ownershipView":{"default":"net","description":"`net` (the default) or `gross`.","allOf":[{"$ref":"#/components/schemas/OwnershipView"}]},"sql":{"type":"string","description":"One `SELECT` over the relations of `projects/describe`, or a `UNION`, `EXCEPT` or\n`INTERSECT` of them, with an optional `WITH`. Anything else is refused."}},"required":["projectId","sql"],"description":"One read-only SQL query over the analytics of a project, written whole to one parquet file."},"ProjectExport":{"type":"object","properties":{"url":{"type":"string","description":"The URL of the parquet file. Send no header with it: the URL carries its own signature."},"expiresAt":{"type":"string","description":"When the URL stops working, in RFC 3339.","format":"date-time"},"rows":{"type":"integer","format":"uint64","minimum":0,"description":"The rows of the file."},"bytes":{"type":"integer","format":"uint64","minimum":0,"description":"The size of the file, in bytes."}},"required":["url","expiresAt","rows","bytes"],"description":"Where to download the file, until when, and what it holds."}}}}