> For the complete documentation index, see [llms.txt](https://docs.bipeye.com/product-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.bipeye.com/product-docs/overview/openapi/bi.p.eye-api.md).

# BI.P.EYE API

## Generate a signed embed URL

> Creates a signed URL that embeds a dashboard inside your product.\
> \
> Pass the returned \`url\` directly to an \`\<iframe src="...">\` in your frontend.\
> If \`expiresInDays\` is omitted, the link expires after 360 days.\
> \
> Use \`restrictDatasetsData\` to filter each dataset's rows per link (row-level security).\
> Datasets the dashboard starts using after the link was created are not shown by the link\
> until you list them with \`PATCH /embed/apiKey\`.\
> \
> Use \`security\` to protect this link on its own: a password viewers enter before the dashboard opens,\
> the IPs it opens from, and the sites allowed to frame it. These apply in addition to the dashboard's\
> own IP and domain restrictions set in the BI.P.EYE app.\
> \
> \*\*Short-lived links.\*\* For a link per viewer session, set a short \`expiresInDays\` (minimum 1).\
> Only unexpired links count toward your plan's API key limit.

````json
{"openapi":"3.0.0","info":{"title":"BI.P.EYE API","version":"1.0.0"},"servers":[{"url":"https://api.bipeye.com/v1","description":"Production"}],"security":[{"organizationApiKey":[]}],"components":{"securitySchemes":{"organizationApiKey":{"type":"apiKey","in":"header","name":"X-API-Key","description":"Your organization API key (the master key), never a dashboard API key"}},"schemas":{"Filter":{"type":"object","properties":{"jsonPath":{"type":"string","minLength":1,"description":"JSON path to the field being filtered"},"type":{"$ref":"#/components/schemas/FiltersTypes"},"value":{"nullable":true}},"required":["jsonPath","type"]},"FiltersTypes":{"type":"string","enum":["is greater than","is less than","is greater than or equal to","is less than or equal to","is","is not","date range","multi select","days back","is exists","is not exists","includes","not includes"]},"EmbedLinkSecurity":{"type":"object","properties":{"password":{"type":"string","minLength":8,"description":"Viewers enter this password before the dashboard opens. 8 to 72 characters. Stored hashed; it is never returned."},"allowedIps":{"type":"array","items":{"type":"string"},"maxItems":100,"description":"Visitor IPs the link opens from, at most 100. Single addresses and CIDR ranges, IPv4 and IPv6. Checked on the embed page and on every data request the dashboard makes. An empty list means no IP restriction."},"allowedDomains":{"type":"array","items":{"type":"string"},"maxItems":50,"description":"Sites allowed to show the link in an iframe, at most 50. A domain (`app.example.com`, which also covers its subdomains), a wildcard (`*.example.com`), or an origin with a scheme and port (`http://localhost:3000`). Enforced by the browser (Content-Security-Policy `frame-ancestors`), and opening the link outside an iframe is refused. An empty list means no domain restriction."}},"additionalProperties":false,"description":"Access rules for this link only. They apply in addition to the dashboard's own IP and domain restrictions set in the BI.P.EYE app: a viewer must pass both."},"EmbedLinkSecuritySummary":{"type":"object","properties":{"hasPassword":{"type":"boolean"},"allowedIps":{"type":"array","items":{"type":"string"}},"allowedDomains":{"type":"array","items":{"type":"string"}}},"required":["hasPassword","allowedIps","allowedDomains"],"description":"The link's access rules as stored. The password itself is never returned."}}},"paths":{"/embed/link":{"post":{"summary":"Generate a signed embed URL","description":"Creates a signed URL that embeds a dashboard inside your product.\n\nPass the returned `url` directly to an `<iframe src=\"...\">` in your frontend.\nIf `expiresInDays` is omitted, the link expires after 360 days.\n\nUse `restrictDatasetsData` to filter each dataset's rows per link (row-level security).\nDatasets the dashboard starts using after the link was created are not shown by the link\nuntil you list them with `PATCH /embed/apiKey`.\n\nUse `security` to protect this link on its own: a password viewers enter before the dashboard opens,\nthe IPs it opens from, and the sites allowed to frame it. These apply in addition to the dashboard's\nown IP and domain restrictions set in the BI.P.EYE app.\n\n**Short-lived links.** For a link per viewer session, set a short `expiresInDays` (minimum 1).\nOnly unexpired links count toward your plan's API key limit.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"organizationId":{"type":"string","format":"uuid","description":"The organization ID to embed"},"dashboardId":{"type":"string","format":"uuid","description":"The dashboard ID to embed"},"apiKeyName":{"type":"string","description":"An optional name for the generated API key, for easier identification in the BI.P.EYE dashboard"},"expiresInDays":{"type":"integer","minimum":0,"exclusiveMinimum":true,"description":"How long the link is valid in days. Defaults to 360 days if omitted, or to the API key's maximum link lifetime when it has a shorter one. At most the API key's maximum link lifetime, when it has one."},"overrideCurrency":{"type":"string","enum":["USD","EUR","GBP","ILS","JPY","AUD","DKK","CAD","$","€","£","₪","¥","A$","KR","C$"],"description":"Override the currency symbol displayed across all charts in the dashboard.\nAccepts either the ISO currency code (`USD`) or the symbol (`$`) — both resolve to the same currency.\n"},"restrictDatasetsData":{"type":"object","additionalProperties":{"type":"object","properties":{"filters":{"type":"array","items":{"$ref":"#/components/schemas/Filter"}}},"required":["filters"],"description":"**Key** = dataset UUID (e.g. `c3dcb641-72fe-458b-9fe5-1594ba69aff4`).\nEach dataset can have its own independent filter rules.\n\n```json\n{\n  \"restrictDatasetsData\": {\n    \"c3dcb641-72fe-458b-9fe5-1594ba69aff4\": {\n      \"filters\": [\n        {\n          \"jsonPath\": \"$.accountId\",\n          \"type\": \"is\",\n          \"value\": \"ac_123\"\n        }\n      ]\n    }\n  }\n}\n```"},"description":"Per-dataset row-level security. Use dataset UUIDs as keys - each key maps to the filters applied to that dataset's rows before rendering.\n\n- **Listed with filters**: the link shows only the rows that match.\n- **Listed with `\"filters\": []`**: the link shows all the dataset's rows.\n- **Not listed**: a dataset the dashboard used when the link was created shows all its rows.\n  A dataset the dashboard starts using **later** is not shown by this link (its charts show\n  \"Not available for this link\") until you list it, with filters or with `\"filters\": []`.\n\nEvery dataset listed must be one this organization API key can access (its models, its datasets,\nor the datasets of a dashboard granted to it); otherwise the request is refused with 403.\n\nEvery filter must be complete. A filter that cannot be applied, for example `\"type\": \"is\"` with an\nempty value, is refused with 400 and the response names it."},"enableDashboardChat":{"type":"boolean","description":"Turns the dashboard chat on (true) or off (false) for this link: people who open it can ask questions\nabout the data in plain language. Answers use only the datasets this link shows, filtered by its\n`restrictDatasetsData` (row-level security). Off unless set.\n\nRequires an organization API key that is allowed to enable chat; otherwise the request is refused with 403."},"security":{"$ref":"#/components/schemas/EmbedLinkSecurity"}},"required":["organizationId","dashboardId"]}}}},"responses":{"200":{"description":"Signed embed URL","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"expiresAt":{"type":"string","format":"date-time"},"apiKey":{"type":"string","format":"uuid","description":"The embed API key. Pass this to the PATCH /embed/apiKey endpoint to update the key later."},"security":{"$ref":"#/components/schemas/EmbedLinkSecuritySummary"}},"required":["url","expiresAt","apiKey","security"]}}}},"400":{"description":"Validation error — check your request body"},"401":{"description":"Invalid or missing API key"},"403":{"description":"This API key has no access to this dashboard, or to a dataset in `restrictDatasetsData`, or may not enable the dashboard chat: grant the dashboard, or the models or datasets it reads, to the key"},"404":{"description":"Dashboard not found or does not belong to your organization"}}}}}}
````

## List datasets for a dashboard

> Returns the datasets used by the given dashboard that this API key can access, along with their fields and inferred types.\
> A key created before API key permissions, or a key granted the dashboard itself, gets every dataset of the dashboard.\
> \
> Use this to discover which \`jsonPath\` values and field types are available\
> when building \`restrictDatasetsData\` filters for the embed link endpoint.

```json
{"openapi":"3.0.0","info":{"title":"BI.P.EYE API","version":"1.0.0"},"servers":[{"url":"https://api.bipeye.com/v1","description":"Production"}],"security":[{"organizationApiKey":[]}],"components":{"securitySchemes":{"organizationApiKey":{"type":"apiKey","in":"header","name":"X-API-Key","description":"Your organization API key (the master key), never a dashboard API key"}},"schemas":{"DashboardDatasetsResponse":{"type":"object","properties":{"datasets":{"type":"array","items":{"$ref":"#/components/schemas/Dataset"}}},"required":["datasets"]},"Dataset":{"type":"object","properties":{"datasetId":{"type":"string","format":"uuid","description":"The UUID of the dataset"},"fields":{"type":"array","items":{"$ref":"#/components/schemas/DatasetField"}}},"required":["datasetId","fields"]},"DatasetField":{"type":"object","properties":{"jsonPath":{"type":"string","description":"JSONPath of the field within the dataset"},"type":{"$ref":"#/components/schemas/FieldType"}},"required":["jsonPath","type"]},"FieldType":{"type":"string","enum":["string","boolean","number","bigint"]}}},"paths":{"/dashboards/datasets":{"post":{"summary":"List datasets for a dashboard","description":"Returns the datasets used by the given dashboard that this API key can access, along with their fields and inferred types.\nA key created before API key permissions, or a key granted the dashboard itself, gets every dataset of the dashboard.\n\nUse this to discover which `jsonPath` values and field types are available\nwhen building `restrictDatasetsData` filters for the embed link endpoint.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"organizationId":{"type":"string","format":"uuid","description":"The organization ID"},"dashboardId":{"type":"string","format":"uuid","description":"The dashboard ID to fetch datasets for"}},"required":["organizationId","dashboardId"]}}}},"responses":{"200":{"description":"List of datasets with their fields","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DashboardDatasetsResponse"}}}},"400":{"description":"Validation error — check your request body"},"401":{"description":"Invalid or missing API key"},"403":{"description":"This API key can access none of this dashboard's datasets: grant the dashboard, or the models or datasets it reads, to the key"},"404":{"description":"Dashboard not found or does not belong to your organization"}}}}}}
```

## Delete an embed API key

> Permanently deletes an embed API key.\
> \
> Once deleted, any iframe using this key will immediately lose access to the dashboard.\
> This action cannot be undone.

```json
{"openapi":"3.0.0","info":{"title":"BI.P.EYE API","version":"1.0.0"},"servers":[{"url":"https://api.bipeye.com/v1","description":"Production"}],"security":[{"organizationApiKey":[]}],"components":{"securitySchemes":{"organizationApiKey":{"type":"apiKey","in":"header","name":"X-API-Key","description":"Your organization API key (the master key), never a dashboard API key"}},"schemas":{"DeleteApiKeyResponse":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}},"paths":{"/embed/apiKey":{"delete":{"summary":"Delete an embed API key","description":"Permanently deletes an embed API key.\n\nOnce deleted, any iframe using this key will immediately lose access to the dashboard.\nThis action cannot be undone.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"organizationId":{"type":"string","format":"uuid","description":"The organization ID that owns the API key"},"dashboardId":{"type":"string","format":"uuid","description":"The dashboard ID that the API key belongs to"},"apiKey":{"type":"string","format":"uuid","description":"The embed API key to delete"}},"required":["organizationId","dashboardId","apiKey"]}}}},"responses":{"200":{"description":"API key deleted successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteApiKeyResponse"}}}},"400":{"description":"Validation error — check your request body"},"401":{"description":"Invalid or missing API key"},"403":{"description":"This API key has no access to this dashboard: grant the dashboard, or the models or datasets it reads, to the key"},"404":{"description":"API key not found or does not belong to your organization"}}}}}}
```

## Edit an existing embed API key

> Updates the configuration of an existing embed API key.\
> \
> You can update the expiry duration and/or the per-dataset row-level filters.\
> Only the fields you provide will be changed — omitted fields are left as-is.\
> \
> \`restrictDatasetsData\` replaces the link's filters. List a dataset with filters to show only matching rows,\
> or with \`"filters": \[]\` to show all its rows. This is also how a dataset the dashboard started using after\
> the link was created becomes visible on the link. A dataset that was hidden from the link in the BI.P.EYE\
> app stays hidden.\
> If \`expiresInDays\` is omitted, expiry is reset to the default of 360 days from now.\
> \
> \`security\` changes the link's access rules field by field: \`password\` (a new one, or \`null\` to remove it),\
> \`allowedIps\` and \`allowedDomains\` (a list replaces the current one, \`\[]\` removes it). Fields you omit are kept.

````json
{"openapi":"3.0.0","info":{"title":"BI.P.EYE API","version":"1.0.0"},"servers":[{"url":"https://api.bipeye.com/v1","description":"Production"}],"security":[{"organizationApiKey":[]}],"components":{"securitySchemes":{"organizationApiKey":{"type":"apiKey","in":"header","name":"X-API-Key","description":"Your organization API key (the master key), never a dashboard API key"}},"schemas":{"Filter":{"type":"object","properties":{"jsonPath":{"type":"string","minLength":1,"description":"JSON path to the field being filtered"},"type":{"$ref":"#/components/schemas/FiltersTypes"},"value":{"nullable":true}},"required":["jsonPath","type"]},"FiltersTypes":{"type":"string","enum":["is greater than","is less than","is greater than or equal to","is less than or equal to","is","is not","date range","multi select","days back","is exists","is not exists","includes","not includes"]},"EmbedLinkSecurityEdit":{"type":"object","properties":{"password":{"anyOf":[{"type":"string","minLength":8},{"type":"string","enum":[""]},{"nullable":true}],"description":"A new password. `null` or `\"\"` removes the password. Omit to keep the current one."},"allowedIps":{"type":"array","items":{"type":"string"},"maxItems":100,"description":"Replaces the IP list. `[]` removes it. Omit to keep the current one."},"allowedDomains":{"type":"array","items":{"type":"string"},"maxItems":50,"description":"Replaces the domain list. `[]` removes it. Omit to keep the current one."}},"additionalProperties":false,"description":"Changes the link's access rules field by field: a field you send replaces, a field you omit is kept."},"EditApiKeyResponse":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}},"paths":{"/embed/apiKey":{"patch":{"summary":"Edit an existing embed API key","description":"Updates the configuration of an existing embed API key.\n\nYou can update the expiry duration and/or the per-dataset row-level filters.\nOnly the fields you provide will be changed — omitted fields are left as-is.\n\n`restrictDatasetsData` replaces the link's filters. List a dataset with filters to show only matching rows,\nor with `\"filters\": []` to show all its rows. This is also how a dataset the dashboard started using after\nthe link was created becomes visible on the link. A dataset that was hidden from the link in the BI.P.EYE\napp stays hidden.\nIf `expiresInDays` is omitted, expiry is reset to the default of 360 days from now.\n\n`security` changes the link's access rules field by field: `password` (a new one, or `null` to remove it),\n`allowedIps` and `allowedDomains` (a list replaces the current one, `[]` removes it). Fields you omit are kept.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"organizationId":{"type":"string","format":"uuid","description":"The organization ID that owns the API key"},"dashboardId":{"type":"string","format":"uuid","description":"The dashboard ID that the API key belongs to"},"apiKeyName":{"type":"string","description":"An optional name for the generated API key, for easier identification in the BI.P.EYE dashboard"},"apiKey":{"type":"string","format":"uuid","description":"The embed API key to edit"},"expiresInDays":{"type":"integer","minimum":0,"exclusiveMinimum":true,"description":"New expiry duration in days from now. Defaults to 360 days if omitted, or to the API key's maximum link lifetime when it has a shorter one. At most that maximum."},"restrictDatasetsData":{"type":"object","additionalProperties":{"type":"object","properties":{"filters":{"type":"array","items":{"$ref":"#/components/schemas/Filter"}}},"required":["filters"],"description":"**Key** = dataset UUID (e.g. `c3dcb641-72fe-458b-9fe5-1594ba69aff4`).\nEach dataset can have its own independent filter rules.\n\n```json\n{\n  \"restrictDatasetsData\": {\n    \"c3dcb641-72fe-458b-9fe5-1594ba69aff4\": {\n      \"filters\": [\n        {\n          \"jsonPath\": \"$.accountId\",\n          \"type\": \"is\",\n          \"value\": \"ac_123\"\n        }\n      ]\n    }\n  }\n}\n```"},"description":"Per-dataset row-level security. Use dataset UUIDs as keys - each key maps to the filters applied to that dataset's rows before rendering.\n\n- **Listed with filters**: the link shows only the rows that match.\n- **Listed with `\"filters\": []`**: the link shows all the dataset's rows.\n- **Not listed**: a dataset the dashboard used when the link was created shows all its rows.\n  A dataset the dashboard starts using **later** is not shown by this link (its charts show\n  \"Not available for this link\") until you list it, with filters or with `\"filters\": []`.\n\nEvery dataset listed must be one this organization API key can access (its models, its datasets,\nor the datasets of a dashboard granted to it); otherwise the request is refused with 403.\n\nEvery filter must be complete. A filter that cannot be applied, for example `\"type\": \"is\"` with an\nempty value, is refused with 400 and the response names it."},"enableDashboardChat":{"type":"boolean","description":"Turns the dashboard chat on (true) or off (false) for this link: people who open it can ask questions\nabout the data in plain language. Answers use only the datasets this link shows, filtered by its\n`restrictDatasetsData` (row-level security). Off unless set.\n\nRequires an organization API key that is allowed to enable chat; otherwise the request is refused with 403."},"security":{"$ref":"#/components/schemas/EmbedLinkSecurityEdit"}},"required":["organizationId","dashboardId","apiKey"]}}}},"responses":{"200":{"description":"API key updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EditApiKeyResponse"}}}},"400":{"description":"Validation error — check your request body"},"401":{"description":"Invalid or missing API key"},"403":{"description":"This API key has no access to this dashboard, or to a dataset in `restrictDatasetsData`, or may not enable the dashboard chat: grant the dashboard, or the models or datasets it reads, to the key"},"404":{"description":"API key not found or does not belong to your organization"}}}}}}
````
