> For the complete documentation index, see [llms.txt](https://docs.soda.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.soda.io/apis/rest-api/data-products.md).

# Data Products

Soda Cloud API Data Product Endpoints

## List data products

> This endpoint allows you to list the data products in your organization.\
> \
> This GET is a paginated API that uses the following parameters to request specific details:\
> \
> \- \`cursor\`: Omit for the first page. Pass the previous response's \`nextCursor\`, with the same other parameters, to continue after its last item. Cursors are opaque; invalid cursors return 400.\
> \
> \- \`size\`: Number of items per page, from 1 to 1000, default 10. The size may change between pages.\
> \
> \- \`search\`: Optionally, use this parameter to search the data product label and name.\
> \
> \- \`ownerId\`: Optionally, use this parameter to list only the data products owned by one user or one user group. Supply a single id: either a user id or a user group id. A user id also matches the data products owned by a user group that the user belongs to.\
> \
> \- \`datasetId\`: Optionally, use this parameter to list only the data products that have the dataset as an input.\
> \
> \- \`sort\`: Optionally, sort the results by \`label\` (default) or \`name\`.\
> \
> The \`name\` of a data product is the \`key\` of its YAML, and the \`label\` is the YAML \`name\`.\
> \
> The response contains \`content\` and, when more items are available, \`nextCursor\`. An absent \`nextCursor\` marks the end of the results. Page numbers and totals are not returned.\
> \
> Inputs are not part of the data product. Use \`/api/v1/dataProducts/{dataProductName}/inputs\`, which is paged.\
> \
> \## Authentication\
> \
> User authentication required: \`true\`\
> \
> This endpoint accepts authentication via API keys in the \`Basic\` authentication header, or a pre-authenticated token in HTTP cookie \`token\`. Cookie sessions extend automatically on each request.\
> \
> \## Tags\
> \
> \`Data Products\`\
> \
> \## Rate limiting\
> \
> 60 requests/60 seconds

```json
{"openapi":"3.1.0","info":{"title":"Soda Cloud API v4","version":"v1"},"tags":[{"description":"Soda Cloud API Data Product Endpoints","name":"Data Products"}],"servers":[{"description":"Cloud EU","url":"https://cloud.soda.io"},{"description":"Cloud US","url":"https://cloud.us.soda.io"}],"security":[{"basicAuthApiKey":[]},{"cookieToken":[]}],"components":{"securitySchemes":{"basicAuthApiKey":{"scheme":"basic","type":"http"},"cookieToken":{"in":"cookie","name":"token","type":"apiKey"}},"schemas":{"DataProductSortFieldDTO":{"type":"string","enum":["label","name"]},"PublicApiListDataProductsResponse":{"type":"object","properties":{"content":{"type":"array","items":{"type":"object","$ref":"#/components/schemas/DataProductContentDTO"}},"nextCursor":{"type":"string"}},"required":["content"]},"DataProductContentDTO":{"type":"object","properties":{"attributes":{"type":"object","$ref":"#/components/schemas/MapOfStringTo_object"},"cloudUrl":{"type":"string"},"contents":{"type":"string"},"created":{"type":"string","format":"date-time"},"description":{"type":"string"},"health":{"type":"object","$ref":"#/components/schemas/DataProductHealthContentDTO"},"id":{"type":"string"},"label":{"type":"string","description":"The `name` of the data product YAML."},"lastUpdated":{"type":"string","format":"date-time"},"name":{"type":"string","description":"The `key` of the data product YAML. It is unique in the organization and cannot change. Use it as `dataProductName` in the paths."},"owner":{"type":"object","$ref":"#/components/schemas/DataProductOwnerContentDTO"},"url":{"type":"string"}},"required":["attributes","cloudUrl","contents","created","health","id","label","lastUpdated","name","owner"]},"MapOfStringTo_object":{"type":"object","additionalProperties":true},"DataProductHealthContentDTO":{"type":"object","properties":{"evidenceCoverage":{"type":"integer","format":"int32","description":"Percentage, 0 to 100, of the inputs that are not notVerified. Absent when the product has no inputs."},"inputs":{"type":"object","$ref":"#/components/schemas/DataProductHealthInputCountsContentDTO"},"lastEvaluated":{"type":"string","format":"date-time"},"state":{"type":"object","$ref":"#/components/schemas/DataProductHealthStateContentDTO"}},"required":["inputs","state"]},"DataProductHealthInputCountsContentDTO":{"type":"object","properties":{"atRisk":{"type":"integer","format":"int32"},"healthy":{"type":"integer","format":"int32"},"noAccess":{"type":"integer","format":"int32","description":"Inputs whose dataset the caller cannot view, counted for the caller only. They are also counted in healthy, atRisk, unhealthy or notVerified, so other callers see the same state counts but can see a different number here."},"notFound":{"type":"integer","format":"int32","description":"Inputs whose dataset does not exist. Also counted in notVerified: healthy + atRisk + unhealthy + notVerified equals the number of inputs."},"notVerified":{"type":"integer","format":"int32"},"unhealthy":{"type":"integer","format":"int32"}},"required":["atRisk","healthy","noAccess","notFound","notVerified","unhealthy"]},"DataProductHealthStateContentDTO":{"type":"string","enum":["healthy","atRisk","unhealthy","notVerified","incomplete"]},"DataProductOwnerContentDTO":{"type":"object","properties":{"email":{"type":"string"},"state":{"type":"object","$ref":"#/components/schemas/DataProductOwnerStateContentDTO"},"type":{"type":"object","$ref":"#/components/schemas/DataProductOwnerTypeContentDTO"},"user":{"type":"object","$ref":"#/components/schemas/UserContentDTO"},"userGroup":{"type":"object","$ref":"#/components/schemas/UserGroupContentBasicDTO"},"userGroupId":{"type":"string"}},"required":["state","type"]},"DataProductOwnerStateContentDTO":{"type":"string","enum":["linked","notFound"]},"DataProductOwnerTypeContentDTO":{"type":"string","enum":["user","userGroup"]},"UserContentDTO":{"type":"object","properties":{"email":{"type":"string"},"firstName":{"type":"string"},"fullName":{"type":"string"},"lastName":{"type":"string"},"userId":{"type":"string"}},"required":["email","userId"]},"UserGroupContentBasicDTO":{"type":"object","properties":{"label":{"type":"string","description":"Display name of the user group. Equals `name` unless the user group has been given a label."},"name":{"type":"string"},"userGroupId":{"type":"string"}},"required":["label","name","userGroupId"]},"ErrorResponse":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}},"paths":{"/api/v1/dataProducts":{"get":{"description":"This endpoint allows you to list the data products in your organization.\n\nThis GET is a paginated API that uses the following parameters to request specific details:\n\n- `cursor`: Omit for the first page. Pass the previous response's `nextCursor`, with the same other parameters, to continue after its last item. Cursors are opaque; invalid cursors return 400.\n\n- `size`: Number of items per page, from 1 to 1000, default 10. The size may change between pages.\n\n- `search`: Optionally, use this parameter to search the data product label and name.\n\n- `ownerId`: Optionally, use this parameter to list only the data products owned by one user or one user group. Supply a single id: either a user id or a user group id. A user id also matches the data products owned by a user group that the user belongs to.\n\n- `datasetId`: Optionally, use this parameter to list only the data products that have the dataset as an input.\n\n- `sort`: Optionally, sort the results by `label` (default) or `name`.\n\nThe `name` of a data product is the `key` of its YAML, and the `label` is the YAML `name`.\n\nThe response contains `content` and, when more items are available, `nextCursor`. An absent `nextCursor` marks the end of the results. Page numbers and totals are not returned.\n\nInputs are not part of the data product. Use `/api/v1/dataProducts/{dataProductName}/inputs`, which is paged.\n\n## Authentication\n\nUser authentication required: `true`\n\nThis endpoint accepts authentication via API keys in the `Basic` authentication header, or a pre-authenticated token in HTTP cookie `token`. Cookie sessions extend automatically on each request.\n\n## Tags\n\n`Data Products`\n\n## Rate limiting\n\n60 requests/60 seconds","operationId":"GET/api/v1/dataProducts","parameters":[{"in":"query","name":"cursor","schema":{"type":"string"}},{"in":"query","name":"datasetId","schema":{"type":"string"}},{"in":"query","name":"ownerId","schema":{"type":"string"}},{"in":"query","name":"search","schema":{"type":"string"}},{"in":"query","name":"size","schema":{"type":"integer","format":"int32"}},{"in":"query","name":"sort","schema":{"type":"object","$ref":"#/components/schemas/DataProductSortFieldDTO"}}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","$ref":"#/components/schemas/PublicApiListDataProductsResponse"}}},"description":"Successful response"},"400":{"content":{"application/json":{"schema":{"type":"object","$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"type":"object","$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"object","$ref":"#/components/schemas/ErrorResponse"}}},"description":"Forbidden"},"429":{"content":{"application/json":{"schema":{"type":"object","$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too many requests"},"500":{"content":{"application/json":{"schema":{"type":"object","$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal server error"}},"summary":"List data products","tags":["Data Products"]}}}}
```

## Create a data product

> This endpoint allows you to create a data product from its YAML definition.\
> \
> The body has one field, \`contents\`, which holds the data product YAML. The YAML can have at most 3145728 characters. Example:\
> \
> \`\`\`yaml\
> kind: data-product\
> key: monthly\_revenue\_report\
> name: Monthly Revenue Report\
> description: >\
> &#x20; Month-end revenue in USD by region and segment, built from closed-won\
> &#x20; opportunities. Feeds the board pack and the revenue dashboard.\
> url: <https://looker.company.com/dashboards/monthly-revenue\\>
> owner:\
> &#x20; type: soda\_user\_group\
> &#x20; id: 7c4b91e2-6d38-4a05-9f12-83b0e6d7a249\
> attributes:\
> &#x20; department: Finance\
> &#x20; business\_function: Revenue reporting\
> &#x20; documentation\_url: <https://docs.company.com/data-products/monthly-revenue\\>
> &#x20; tags:\
> &#x20;   \- board-reporting\
> &#x20;   \- business-critical\
> inputs:\
> &#x20; \- type: dataset\
> &#x20;   dqn: pg/sales\_data/crm/opportunities\
> &#x20; \- type: dataset\
> &#x20;   dqn: pg/sales\_data/crm/accounts\
> &#x20; \- type: dataset\
> &#x20;   dqn: pg/sales\_data/reference/fx\_rates\
> \`\`\`\
> \
> The \`key\` of the YAML becomes the \`name\` of the data product. If another data product uses this \`key\`, the request is rejected with a 400 error and the code \`data\_product\_name\_already\_exists\`.\
> \
> If the YAML does not parse or does not match the schema, the request is rejected with a 400 error and the code \`invalid\_request\`. If it breaks a data product rule (key, owner, attributes, inputs), the code is \`invalid\_data\_product\`. The message lists each problem on its own line.\
> \
> Problems that do not stop the publish are returned in \`warnings\`, one sentence each.\
> \
> \## Authorization\
> \
> Only users with \*\*Manage data products\*\* permission can create data products.\
> \
> \## Authentication\
> \
> User authentication required: \`true\`\
> \
> This endpoint accepts authentication via API keys in the \`Basic\` authentication header, or a pre-authenticated token in HTTP cookie \`token\`. Cookie sessions extend automatically on each request.\
> \
> \## Auditable\
> \
> This API is marked as \*\*audited\*\* on execution.\
> \
> \## Tags\
> \
> \`Data Products\`\
> \
> \## Rate limiting\
> \
> 100 requests/60 seconds

````json
{"openapi":"3.1.0","info":{"title":"Soda Cloud API v4","version":"v1"},"tags":[{"description":"Soda Cloud API Data Product Endpoints","name":"Data Products"}],"servers":[{"description":"Cloud EU","url":"https://cloud.soda.io"},{"description":"Cloud US","url":"https://cloud.us.soda.io"}],"security":[{"basicAuthApiKey":[]},{"cookieToken":[]}],"components":{"securitySchemes":{"basicAuthApiKey":{"scheme":"basic","type":"http"},"cookieToken":{"in":"cookie","name":"token","type":"apiKey"}},"schemas":{"PublicApiDataProductRequestDTO":{"type":"object","properties":{"contents":{"type":"string"}},"required":["contents"]},"PublicApiCreateDataProductResponse":{"type":"object","properties":{"dataProduct":{"type":"object","$ref":"#/components/schemas/DataProductContentDTO"},"warnings":{"type":"array","items":{"type":"string"}}},"required":["dataProduct","warnings"]},"DataProductContentDTO":{"type":"object","properties":{"attributes":{"type":"object","$ref":"#/components/schemas/MapOfStringTo_object"},"cloudUrl":{"type":"string"},"contents":{"type":"string"},"created":{"type":"string","format":"date-time"},"description":{"type":"string"},"health":{"type":"object","$ref":"#/components/schemas/DataProductHealthContentDTO"},"id":{"type":"string"},"label":{"type":"string","description":"The `name` of the data product YAML."},"lastUpdated":{"type":"string","format":"date-time"},"name":{"type":"string","description":"The `key` of the data product YAML. It is unique in the organization and cannot change. Use it as `dataProductName` in the paths."},"owner":{"type":"object","$ref":"#/components/schemas/DataProductOwnerContentDTO"},"url":{"type":"string"}},"required":["attributes","cloudUrl","contents","created","health","id","label","lastUpdated","name","owner"]},"MapOfStringTo_object":{"type":"object","additionalProperties":true},"DataProductHealthContentDTO":{"type":"object","properties":{"evidenceCoverage":{"type":"integer","format":"int32","description":"Percentage, 0 to 100, of the inputs that are not notVerified. Absent when the product has no inputs."},"inputs":{"type":"object","$ref":"#/components/schemas/DataProductHealthInputCountsContentDTO"},"lastEvaluated":{"type":"string","format":"date-time"},"state":{"type":"object","$ref":"#/components/schemas/DataProductHealthStateContentDTO"}},"required":["inputs","state"]},"DataProductHealthInputCountsContentDTO":{"type":"object","properties":{"atRisk":{"type":"integer","format":"int32"},"healthy":{"type":"integer","format":"int32"},"noAccess":{"type":"integer","format":"int32","description":"Inputs whose dataset the caller cannot view, counted for the caller only. They are also counted in healthy, atRisk, unhealthy or notVerified, so other callers see the same state counts but can see a different number here."},"notFound":{"type":"integer","format":"int32","description":"Inputs whose dataset does not exist. Also counted in notVerified: healthy + atRisk + unhealthy + notVerified equals the number of inputs."},"notVerified":{"type":"integer","format":"int32"},"unhealthy":{"type":"integer","format":"int32"}},"required":["atRisk","healthy","noAccess","notFound","notVerified","unhealthy"]},"DataProductHealthStateContentDTO":{"type":"string","enum":["healthy","atRisk","unhealthy","notVerified","incomplete"]},"DataProductOwnerContentDTO":{"type":"object","properties":{"email":{"type":"string"},"state":{"type":"object","$ref":"#/components/schemas/DataProductOwnerStateContentDTO"},"type":{"type":"object","$ref":"#/components/schemas/DataProductOwnerTypeContentDTO"},"user":{"type":"object","$ref":"#/components/schemas/UserContentDTO"},"userGroup":{"type":"object","$ref":"#/components/schemas/UserGroupContentBasicDTO"},"userGroupId":{"type":"string"}},"required":["state","type"]},"DataProductOwnerStateContentDTO":{"type":"string","enum":["linked","notFound"]},"DataProductOwnerTypeContentDTO":{"type":"string","enum":["user","userGroup"]},"UserContentDTO":{"type":"object","properties":{"email":{"type":"string"},"firstName":{"type":"string"},"fullName":{"type":"string"},"lastName":{"type":"string"},"userId":{"type":"string"}},"required":["email","userId"]},"UserGroupContentBasicDTO":{"type":"object","properties":{"label":{"type":"string","description":"Display name of the user group. Equals `name` unless the user group has been given a label."},"name":{"type":"string"},"userGroupId":{"type":"string"}},"required":["label","name","userGroupId"]},"ErrorResponse":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}},"paths":{"/api/v1/dataProducts":{"post":{"description":"This endpoint allows you to create a data product from its YAML definition.\n\nThe body has one field, `contents`, which holds the data product YAML. The YAML can have at most 3145728 characters. Example:\n\n```yaml\nkind: data-product\nkey: monthly_revenue_report\nname: Monthly Revenue Report\ndescription: >\n  Month-end revenue in USD by region and segment, built from closed-won\n  opportunities. Feeds the board pack and the revenue dashboard.\nurl: https://looker.company.com/dashboards/monthly-revenue\nowner:\n  type: soda_user_group\n  id: 7c4b91e2-6d38-4a05-9f12-83b0e6d7a249\nattributes:\n  department: Finance\n  business_function: Revenue reporting\n  documentation_url: https://docs.company.com/data-products/monthly-revenue\n  tags:\n    - board-reporting\n    - business-critical\ninputs:\n  - type: dataset\n    dqn: pg/sales_data/crm/opportunities\n  - type: dataset\n    dqn: pg/sales_data/crm/accounts\n  - type: dataset\n    dqn: pg/sales_data/reference/fx_rates\n```\n\nThe `key` of the YAML becomes the `name` of the data product. If another data product uses this `key`, the request is rejected with a 400 error and the code `data_product_name_already_exists`.\n\nIf the YAML does not parse or does not match the schema, the request is rejected with a 400 error and the code `invalid_request`. If it breaks a data product rule (key, owner, attributes, inputs), the code is `invalid_data_product`. The message lists each problem on its own line.\n\nProblems that do not stop the publish are returned in `warnings`, one sentence each.\n\n## Authorization\n\nOnly users with **Manage data products** permission can create data products.\n\n## Authentication\n\nUser authentication required: `true`\n\nThis endpoint accepts authentication via API keys in the `Basic` authentication header, or a pre-authenticated token in HTTP cookie `token`. Cookie sessions extend automatically on each request.\n\n## Auditable\n\nThis API is marked as **audited** on execution.\n\n## Tags\n\n`Data Products`\n\n## Rate limiting\n\n100 requests/60 seconds","operationId":"POST/api/v1/dataProducts","requestBody":{"content":{"application/json":{"schema":{"type":"object","$ref":"#/components/schemas/PublicApiDataProductRequestDTO"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","$ref":"#/components/schemas/PublicApiCreateDataProductResponse"}}},"description":"Successful response"},"400":{"content":{"application/json":{"schema":{"type":"object","$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"type":"object","$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"object","$ref":"#/components/schemas/ErrorResponse"}}},"description":"Forbidden"},"429":{"content":{"application/json":{"schema":{"type":"object","$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too many requests"},"500":{"content":{"application/json":{"schema":{"type":"object","$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal server error"}},"summary":"Create a data product","tags":["Data Products"]}}}}
````

## Get a data product

> This endpoint allows you to retrieve a specific data product, including its YAML contents and its health.\
> \
> \`dataProductName\` is the \`key\` of the data product YAML. The YAML \`name\` is returned as \`label\`.\
> \
> The YAML file is in \`contents\`, and the health of the data product is in \`health\`.\
> \
> Inputs are not part of the data product. Use \`/api/v1/dataProducts/{dataProductName}/inputs\`, which is paged.\
> \
> \## Authentication\
> \
> User authentication required: \`true\`\
> \
> This endpoint accepts authentication via API keys in the \`Basic\` authentication header, or a pre-authenticated token in HTTP cookie \`token\`. Cookie sessions extend automatically on each request.\
> \
> \## Tags\
> \
> \`Data Products\`\
> \
> \## Rate limiting\
> \
> 1000 requests/60 seconds

```json
{"openapi":"3.1.0","info":{"title":"Soda Cloud API v4","version":"v1"},"tags":[{"description":"Soda Cloud API Data Product Endpoints","name":"Data Products"}],"servers":[{"description":"Cloud EU","url":"https://cloud.soda.io"},{"description":"Cloud US","url":"https://cloud.us.soda.io"}],"security":[{"basicAuthApiKey":[]},{"cookieToken":[]}],"components":{"securitySchemes":{"basicAuthApiKey":{"scheme":"basic","type":"http"},"cookieToken":{"in":"cookie","name":"token","type":"apiKey"}},"schemas":{"PublicApiGetDataProductResponse":{"type":"object","properties":{"dataProduct":{"type":"object","$ref":"#/components/schemas/DataProductContentDTO"}},"required":["dataProduct"]},"DataProductContentDTO":{"type":"object","properties":{"attributes":{"type":"object","$ref":"#/components/schemas/MapOfStringTo_object"},"cloudUrl":{"type":"string"},"contents":{"type":"string"},"created":{"type":"string","format":"date-time"},"description":{"type":"string"},"health":{"type":"object","$ref":"#/components/schemas/DataProductHealthContentDTO"},"id":{"type":"string"},"label":{"type":"string","description":"The `name` of the data product YAML."},"lastUpdated":{"type":"string","format":"date-time"},"name":{"type":"string","description":"The `key` of the data product YAML. It is unique in the organization and cannot change. Use it as `dataProductName` in the paths."},"owner":{"type":"object","$ref":"#/components/schemas/DataProductOwnerContentDTO"},"url":{"type":"string"}},"required":["attributes","cloudUrl","contents","created","health","id","label","lastUpdated","name","owner"]},"MapOfStringTo_object":{"type":"object","additionalProperties":true},"DataProductHealthContentDTO":{"type":"object","properties":{"evidenceCoverage":{"type":"integer","format":"int32","description":"Percentage, 0 to 100, of the inputs that are not notVerified. Absent when the product has no inputs."},"inputs":{"type":"object","$ref":"#/components/schemas/DataProductHealthInputCountsContentDTO"},"lastEvaluated":{"type":"string","format":"date-time"},"state":{"type":"object","$ref":"#/components/schemas/DataProductHealthStateContentDTO"}},"required":["inputs","state"]},"DataProductHealthInputCountsContentDTO":{"type":"object","properties":{"atRisk":{"type":"integer","format":"int32"},"healthy":{"type":"integer","format":"int32"},"noAccess":{"type":"integer","format":"int32","description":"Inputs whose dataset the caller cannot view, counted for the caller only. They are also counted in healthy, atRisk, unhealthy or notVerified, so other callers see the same state counts but can see a different number here."},"notFound":{"type":"integer","format":"int32","description":"Inputs whose dataset does not exist. Also counted in notVerified: healthy + atRisk + unhealthy + notVerified equals the number of inputs."},"notVerified":{"type":"integer","format":"int32"},"unhealthy":{"type":"integer","format":"int32"}},"required":["atRisk","healthy","noAccess","notFound","notVerified","unhealthy"]},"DataProductHealthStateContentDTO":{"type":"string","enum":["healthy","atRisk","unhealthy","notVerified","incomplete"]},"DataProductOwnerContentDTO":{"type":"object","properties":{"email":{"type":"string"},"state":{"type":"object","$ref":"#/components/schemas/DataProductOwnerStateContentDTO"},"type":{"type":"object","$ref":"#/components/schemas/DataProductOwnerTypeContentDTO"},"user":{"type":"object","$ref":"#/components/schemas/UserContentDTO"},"userGroup":{"type":"object","$ref":"#/components/schemas/UserGroupContentBasicDTO"},"userGroupId":{"type":"string"}},"required":["state","type"]},"DataProductOwnerStateContentDTO":{"type":"string","enum":["linked","notFound"]},"DataProductOwnerTypeContentDTO":{"type":"string","enum":["user","userGroup"]},"UserContentDTO":{"type":"object","properties":{"email":{"type":"string"},"firstName":{"type":"string"},"fullName":{"type":"string"},"lastName":{"type":"string"},"userId":{"type":"string"}},"required":["email","userId"]},"UserGroupContentBasicDTO":{"type":"object","properties":{"label":{"type":"string","description":"Display name of the user group. Equals `name` unless the user group has been given a label."},"name":{"type":"string"},"userGroupId":{"type":"string"}},"required":["label","name","userGroupId"]},"ErrorResponse":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}},"paths":{"/api/v1/dataProducts/{dataProductName}":{"get":{"description":"This endpoint allows you to retrieve a specific data product, including its YAML contents and its health.\n\n`dataProductName` is the `key` of the data product YAML. The YAML `name` is returned as `label`.\n\nThe YAML file is in `contents`, and the health of the data product is in `health`.\n\nInputs are not part of the data product. Use `/api/v1/dataProducts/{dataProductName}/inputs`, which is paged.\n\n## Authentication\n\nUser authentication required: `true`\n\nThis endpoint accepts authentication via API keys in the `Basic` authentication header, or a pre-authenticated token in HTTP cookie `token`. Cookie sessions extend automatically on each request.\n\n## Tags\n\n`Data Products`\n\n## Rate limiting\n\n1000 requests/60 seconds","operationId":"GET/api/v1/dataProducts/{dataProductName}","parameters":[{"in":"path","name":"dataProductName","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","$ref":"#/components/schemas/PublicApiGetDataProductResponse"}}},"description":"Successful response"},"400":{"content":{"application/json":{"schema":{"type":"object","$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"type":"object","$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"object","$ref":"#/components/schemas/ErrorResponse"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"type":"object","$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not found"},"429":{"content":{"application/json":{"schema":{"type":"object","$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too many requests"},"500":{"content":{"application/json":{"schema":{"type":"object","$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal server error"}},"summary":"Get a data product","tags":["Data Products"]}}}}
```

## Update a data product

> This endpoint allows you to replace the YAML definition of a data product.\
> \
> The body is the same as for the create endpoint: one field, \`contents\`, which holds the complete data product YAML.\
> \
> The \`key\` of the YAML must be equal to \`dataProductName\`. You cannot change the \`key\` of a data product. If the two are different, the request is rejected with a 400 error and the code \`data\_product\_name\_immutable\`.\
> \
> If the YAML does not parse or does not match the schema, the request is rejected with a 400 error and the code \`invalid\_request\`. If it breaks a data product rule (key, owner, attributes, inputs), the code is \`invalid\_data\_product\`. The message lists each problem on its own line.\
> \
> Problems that do not stop the publish are returned in \`warnings\`, one sentence each.\
> \
> \## Authorization\
> \
> Only users with \*\*Manage data products\*\* permission can update data products.\
> \
> \## Authentication\
> \
> User authentication required: \`true\`\
> \
> This endpoint accepts authentication via API keys in the \`Basic\` authentication header, or a pre-authenticated token in HTTP cookie \`token\`. Cookie sessions extend automatically on each request.\
> \
> \## Auditable\
> \
> This API is marked as \*\*audited\*\* on execution.\
> \
> \## Tags\
> \
> \`Data Products\`\
> \
> \## Rate limiting\
> \
> 100 requests/60 seconds

```json
{"openapi":"3.1.0","info":{"title":"Soda Cloud API v4","version":"v1"},"tags":[{"description":"Soda Cloud API Data Product Endpoints","name":"Data Products"}],"servers":[{"description":"Cloud EU","url":"https://cloud.soda.io"},{"description":"Cloud US","url":"https://cloud.us.soda.io"}],"security":[{"basicAuthApiKey":[]},{"cookieToken":[]}],"components":{"securitySchemes":{"basicAuthApiKey":{"scheme":"basic","type":"http"},"cookieToken":{"in":"cookie","name":"token","type":"apiKey"}},"schemas":{"PublicApiDataProductRequestDTO":{"type":"object","properties":{"contents":{"type":"string"}},"required":["contents"]},"PublicApiUpdateDataProductResponse":{"type":"object","properties":{"dataProduct":{"type":"object","$ref":"#/components/schemas/DataProductContentDTO"},"warnings":{"type":"array","items":{"type":"string"}}},"required":["dataProduct","warnings"]},"DataProductContentDTO":{"type":"object","properties":{"attributes":{"type":"object","$ref":"#/components/schemas/MapOfStringTo_object"},"cloudUrl":{"type":"string"},"contents":{"type":"string"},"created":{"type":"string","format":"date-time"},"description":{"type":"string"},"health":{"type":"object","$ref":"#/components/schemas/DataProductHealthContentDTO"},"id":{"type":"string"},"label":{"type":"string","description":"The `name` of the data product YAML."},"lastUpdated":{"type":"string","format":"date-time"},"name":{"type":"string","description":"The `key` of the data product YAML. It is unique in the organization and cannot change. Use it as `dataProductName` in the paths."},"owner":{"type":"object","$ref":"#/components/schemas/DataProductOwnerContentDTO"},"url":{"type":"string"}},"required":["attributes","cloudUrl","contents","created","health","id","label","lastUpdated","name","owner"]},"MapOfStringTo_object":{"type":"object","additionalProperties":true},"DataProductHealthContentDTO":{"type":"object","properties":{"evidenceCoverage":{"type":"integer","format":"int32","description":"Percentage, 0 to 100, of the inputs that are not notVerified. Absent when the product has no inputs."},"inputs":{"type":"object","$ref":"#/components/schemas/DataProductHealthInputCountsContentDTO"},"lastEvaluated":{"type":"string","format":"date-time"},"state":{"type":"object","$ref":"#/components/schemas/DataProductHealthStateContentDTO"}},"required":["inputs","state"]},"DataProductHealthInputCountsContentDTO":{"type":"object","properties":{"atRisk":{"type":"integer","format":"int32"},"healthy":{"type":"integer","format":"int32"},"noAccess":{"type":"integer","format":"int32","description":"Inputs whose dataset the caller cannot view, counted for the caller only. They are also counted in healthy, atRisk, unhealthy or notVerified, so other callers see the same state counts but can see a different number here."},"notFound":{"type":"integer","format":"int32","description":"Inputs whose dataset does not exist. Also counted in notVerified: healthy + atRisk + unhealthy + notVerified equals the number of inputs."},"notVerified":{"type":"integer","format":"int32"},"unhealthy":{"type":"integer","format":"int32"}},"required":["atRisk","healthy","noAccess","notFound","notVerified","unhealthy"]},"DataProductHealthStateContentDTO":{"type":"string","enum":["healthy","atRisk","unhealthy","notVerified","incomplete"]},"DataProductOwnerContentDTO":{"type":"object","properties":{"email":{"type":"string"},"state":{"type":"object","$ref":"#/components/schemas/DataProductOwnerStateContentDTO"},"type":{"type":"object","$ref":"#/components/schemas/DataProductOwnerTypeContentDTO"},"user":{"type":"object","$ref":"#/components/schemas/UserContentDTO"},"userGroup":{"type":"object","$ref":"#/components/schemas/UserGroupContentBasicDTO"},"userGroupId":{"type":"string"}},"required":["state","type"]},"DataProductOwnerStateContentDTO":{"type":"string","enum":["linked","notFound"]},"DataProductOwnerTypeContentDTO":{"type":"string","enum":["user","userGroup"]},"UserContentDTO":{"type":"object","properties":{"email":{"type":"string"},"firstName":{"type":"string"},"fullName":{"type":"string"},"lastName":{"type":"string"},"userId":{"type":"string"}},"required":["email","userId"]},"UserGroupContentBasicDTO":{"type":"object","properties":{"label":{"type":"string","description":"Display name of the user group. Equals `name` unless the user group has been given a label."},"name":{"type":"string"},"userGroupId":{"type":"string"}},"required":["label","name","userGroupId"]},"ErrorResponse":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}},"paths":{"/api/v1/dataProducts/{dataProductName}":{"post":{"description":"This endpoint allows you to replace the YAML definition of a data product.\n\nThe body is the same as for the create endpoint: one field, `contents`, which holds the complete data product YAML.\n\nThe `key` of the YAML must be equal to `dataProductName`. You cannot change the `key` of a data product. If the two are different, the request is rejected with a 400 error and the code `data_product_name_immutable`.\n\nIf the YAML does not parse or does not match the schema, the request is rejected with a 400 error and the code `invalid_request`. If it breaks a data product rule (key, owner, attributes, inputs), the code is `invalid_data_product`. The message lists each problem on its own line.\n\nProblems that do not stop the publish are returned in `warnings`, one sentence each.\n\n## Authorization\n\nOnly users with **Manage data products** permission can update data products.\n\n## Authentication\n\nUser authentication required: `true`\n\nThis endpoint accepts authentication via API keys in the `Basic` authentication header, or a pre-authenticated token in HTTP cookie `token`. Cookie sessions extend automatically on each request.\n\n## Auditable\n\nThis API is marked as **audited** on execution.\n\n## Tags\n\n`Data Products`\n\n## Rate limiting\n\n100 requests/60 seconds","operationId":"POST/api/v1/dataProducts/{dataProductName}","parameters":[{"in":"path","name":"dataProductName","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","$ref":"#/components/schemas/PublicApiDataProductRequestDTO"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","$ref":"#/components/schemas/PublicApiUpdateDataProductResponse"}}},"description":"Successful response"},"400":{"content":{"application/json":{"schema":{"type":"object","$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"type":"object","$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"object","$ref":"#/components/schemas/ErrorResponse"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"type":"object","$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not found"},"429":{"content":{"application/json":{"schema":{"type":"object","$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too many requests"},"500":{"content":{"application/json":{"schema":{"type":"object","$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal server error"}},"summary":"Update a data product","tags":["Data Products"]}}}}
```

## Delete a data product

> This endpoint deletes a data product. The deletion is complete when the response is returned.\
> \
> The input datasets and the other data products stay as they are.\
> \
> \## Authorization\
> \
> Only users with \*\*Manage data products\*\* permission can delete data products.\
> \
> \## Authentication\
> \
> User authentication required: \`true\`\
> \
> This endpoint accepts authentication via API keys in the \`Basic\` authentication header, or a pre-authenticated token in HTTP cookie \`token\`. Cookie sessions extend automatically on each request.\
> \
> \## Auditable\
> \
> This API is marked as \*\*audited\*\* on execution.\
> \
> \## Tags\
> \
> \`Data Products\`\
> \
> \## Rate limiting\
> \
> 100 requests/60 seconds

```json
{"openapi":"3.1.0","info":{"title":"Soda Cloud API v4","version":"v1"},"tags":[{"description":"Soda Cloud API Data Product Endpoints","name":"Data Products"}],"servers":[{"description":"Cloud EU","url":"https://cloud.soda.io"},{"description":"Cloud US","url":"https://cloud.us.soda.io"}],"security":[{"basicAuthApiKey":[]},{"cookieToken":[]}],"components":{"securitySchemes":{"basicAuthApiKey":{"scheme":"basic","type":"http"},"cookieToken":{"in":"cookie","name":"token","type":"apiKey"}},"schemas":{"PublicApiDeleteDataProductResponse":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]},"ErrorResponse":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}},"paths":{"/api/v1/dataProducts/{dataProductName}":{"delete":{"description":"This endpoint deletes a data product. The deletion is complete when the response is returned.\n\nThe input datasets and the other data products stay as they are.\n\n## Authorization\n\nOnly users with **Manage data products** permission can delete data products.\n\n## Authentication\n\nUser authentication required: `true`\n\nThis endpoint accepts authentication via API keys in the `Basic` authentication header, or a pre-authenticated token in HTTP cookie `token`. Cookie sessions extend automatically on each request.\n\n## Auditable\n\nThis API is marked as **audited** on execution.\n\n## Tags\n\n`Data Products`\n\n## Rate limiting\n\n100 requests/60 seconds","operationId":"DELETE/api/v1/dataProducts/{dataProductName}","parameters":[{"in":"path","name":"dataProductName","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","$ref":"#/components/schemas/PublicApiDeleteDataProductResponse"}}},"description":"Successful response"},"400":{"content":{"application/json":{"schema":{"type":"object","$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"type":"object","$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"object","$ref":"#/components/schemas/ErrorResponse"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"type":"object","$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not found"},"429":{"content":{"application/json":{"schema":{"type":"object","$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too many requests"},"500":{"content":{"application/json":{"schema":{"type":"object","$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal server error"}},"summary":"Delete a data product","tags":["Data Products"]}}}}
```

## List data product inputs

> This endpoint allows you to list the inputs of a data product, with the health of each input.\
> \
> This GET is a paginated API that uses the following parameters to request specific details:\
> \
> \- \`cursor\`: Omit for the first page. Pass the previous response's \`nextCursor\`, with the same other parameters, to continue after its last item. Cursors are opaque; invalid cursors return 400.\
> \
> \- \`size\`: Number of items per page, from 1 to 1000, default 10. The size may change between pages.\
> \
> The response contains \`content\` and, when more items are available, \`nextCursor\`. An absent \`nextCursor\` marks the end of the results. Page numbers and totals are not returned.\
> \
> Inputs whose dataset you cannot view are left out of this list and counted in the product's \`health.inputs.noAccess\`; their DQNs still appear in the product's \`contents\`.\
> \
> \## Authentication\
> \
> User authentication required: \`true\`\
> \
> This endpoint accepts authentication via API keys in the \`Basic\` authentication header, or a pre-authenticated token in HTTP cookie \`token\`. Cookie sessions extend automatically on each request.\
> \
> \## Tags\
> \
> \`Data Products\`\
> \
> \## Rate limiting\
> \
> 60 requests/60 seconds

```json
{"openapi":"3.1.0","info":{"title":"Soda Cloud API v4","version":"v1"},"tags":[{"description":"Soda Cloud API Data Product Endpoints","name":"Data Products"}],"servers":[{"description":"Cloud EU","url":"https://cloud.soda.io"},{"description":"Cloud US","url":"https://cloud.us.soda.io"}],"security":[{"basicAuthApiKey":[]},{"cookieToken":[]}],"components":{"securitySchemes":{"basicAuthApiKey":{"scheme":"basic","type":"http"},"cookieToken":{"in":"cookie","name":"token","type":"apiKey"}},"schemas":{"PublicApiListDataProductInputsResponse":{"type":"object","properties":{"content":{"type":"array","items":{"type":"object","$ref":"#/components/schemas/DataProductInputContentDTO"}},"nextCursor":{"type":"string"}},"required":["content"]},"DataProductInputContentDTO":{"type":"object","properties":{"checkResults":{"type":"object","$ref":"#/components/schemas/DataProductCheckResultsContentDTO"},"datasetId":{"type":"string"},"dqn":{"type":"string"},"health":{"type":"object","$ref":"#/components/schemas/DataProductInputHealthContentDTO"},"id":{"type":"string"},"state":{"type":"object","$ref":"#/components/schemas/DataProductInputStateContentDTO"},"type":{"type":"object","$ref":"#/components/schemas/DataProductInputTypeContentDTO"}},"required":["id","state","type"]},"DataProductCheckResultsContentDTO":{"type":"object","properties":{"criticalFailingCount":{"type":"integer","format":"int32","description":"A subset of failingCount: the failing checks whose `severity` check attribute is `critical`."},"failingCount":{"type":"integer","format":"int32"},"notEvaluatedCount":{"type":"integer","format":"int32"},"passingCount":{"type":"integer","format":"int32"},"warningCount":{"type":"integer","format":"int32"}},"required":["criticalFailingCount","failingCount","notEvaluatedCount","passingCount","warningCount"]},"DataProductInputHealthContentDTO":{"type":"object","properties":{"lastEvaluated":{"type":"string","format":"date-time"},"state":{"type":"object","$ref":"#/components/schemas/DataProductHealthStateContentDTO"}},"required":["state"]},"DataProductHealthStateContentDTO":{"type":"string","enum":["healthy","atRisk","unhealthy","notVerified","incomplete"]},"DataProductInputStateContentDTO":{"type":"string","enum":["linked","notFound"]},"DataProductInputTypeContentDTO":{"type":"string","enum":["dataset"]},"ErrorResponse":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}},"paths":{"/api/v1/dataProducts/{dataProductName}/inputs":{"get":{"description":"This endpoint allows you to list the inputs of a data product, with the health of each input.\n\nThis GET is a paginated API that uses the following parameters to request specific details:\n\n- `cursor`: Omit for the first page. Pass the previous response's `nextCursor`, with the same other parameters, to continue after its last item. Cursors are opaque; invalid cursors return 400.\n\n- `size`: Number of items per page, from 1 to 1000, default 10. The size may change between pages.\n\nThe response contains `content` and, when more items are available, `nextCursor`. An absent `nextCursor` marks the end of the results. Page numbers and totals are not returned.\n\nInputs whose dataset you cannot view are left out of this list and counted in the product's `health.inputs.noAccess`; their DQNs still appear in the product's `contents`.\n\n## Authentication\n\nUser authentication required: `true`\n\nThis endpoint accepts authentication via API keys in the `Basic` authentication header, or a pre-authenticated token in HTTP cookie `token`. Cookie sessions extend automatically on each request.\n\n## Tags\n\n`Data Products`\n\n## Rate limiting\n\n60 requests/60 seconds","operationId":"GET/api/v1/dataProducts/{dataProductName}/inputs","parameters":[{"in":"path","name":"dataProductName","required":true,"schema":{"type":"string"}},{"in":"query","name":"cursor","schema":{"type":"string"}},{"in":"query","name":"size","schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","$ref":"#/components/schemas/PublicApiListDataProductInputsResponse"}}},"description":"Successful response"},"400":{"content":{"application/json":{"schema":{"type":"object","$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"type":"object","$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"object","$ref":"#/components/schemas/ErrorResponse"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"type":"object","$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not found"},"429":{"content":{"application/json":{"schema":{"type":"object","$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too many requests"},"500":{"content":{"application/json":{"schema":{"type":"object","$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal server error"}},"summary":"List data product inputs","tags":["Data Products"]}}}}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.soda.io/apis/rest-api/data-products.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
