openapi: 3.0.2 info: title: Holistics API version: '2.0' description: > # Introduction Using these APIs, you are able to programmatically work with Holistics. For example: - You can programmatically retrieve CSV, XLSX, etc. data from any Holistics report. - You can use our API to trigger execution of an data schedule, transform or data import. etc... This is useful especially if you need to pass live data to your other applications. For example, you may want to feed a live CSV endpoint of your user segmentation list into your email marketing application so that you can always get fresh data upon retrieving them. **NOTE**: Please note that Holistics **API version** does not correlate with Holistics **feature version**. For example, Holistics API v2 can support operations on all Holistics 2.0, 2.7 and 3.0. # Data center regions API data is limited to specific regions. For example, if your want to access data from the US region, you need to use the subdomain https://us.holistics.io. Below is the API subdomain corresponding with data center's region. |Region | URL | |----------------------|------------------------------------| |Asia-Pacific (APAC) | https://secure.holistics.io/api/v2 | |Europe (EU) | https://eu.holistics.io/api/v2 | |United States (US) | https://us.holistics.io/api/v2 | If you do not know which data center your Holistics' account is currently on, check out this [docs](https://docs.holistics.io/docs/data-centers#how-do-i-know-which-data-center-im-on). # Authentication

Allow user API access

In order for a user to use API key, they must be allowed to use API access in User Management. Edit the User and tick the checkbox Allow API access:

API Key

The allowed user can then visit User Settings and generate a new API key. ![Retrieve API key](https://cdn.holistics.io/docs-images/new_api_key.png) Then, they can set the API key in the request header when calling Holistics APIs. ### API Request Authorization Set the HTTP header `X-Holistics-Key` to your API key. Example: ```bash curl -X POST \ -H "Accept:application/json" \ -H "Content-Type:application/json" \ -H "X-Holistics-Key:$your_api_key" \ https://secure.holistics.io/api/v2/users/me ``` contact: name: Holistics Support email: support@holistics.io servers: - url: https://secure.holistics.io/api/v2 security: - ApiKeyAuthentication: [] components: securitySchemes: ApiKeyAuthentication: type: apiKey in: header name: X-Holistics-Key schemas: _BaseError: $ref: '#/components/schemas/BaseError' _RecordError: $ref: '#/components/schemas/RecordError' _DataModelingCondition: $ref: '#/components/schemas/Condition' Schedule: type: object properties: repeat: type: string description: > Crontab expression. Example: `0 4 * * *` will start a job at 4:00 AM everyday. You can check your crontab expression by using https://crontab.guru. We recommend that you should change the `repeat` time to prevent anti-spam filter from your email provider. For example `0 4 * * *` (job start at 4:00 AM) could be `1 4 * * *` (job start at 4:01 AM) or `5 4 * * *`(job start at 4:05 AM). This will also help your database does not get overload when there are many email schedules that execute at the same time. paused: type: boolean description: Pause execution temporarily. required: - repeat - paused ConditionValue: anyOf: - type: string - type: boolean - type: number Condition: title: DataModelingCondition type: object description: >- Condition that can be applied on the Data Modeling layer to filter your data. [Examples](#section/DataModelingCondition) properties: modifier: type: string nullable: true operator: type: string values: type: array items: $ref: '#/components/schemas/ConditionValue' discriminator: propertyName: operator mapping: is: '#/components/schemas/Is' is_not: '#/components/schemas/IsNot' is_null: '#/components/schemas/IsNull' not_null: '#/components/schemas/NotNull' greater_than: '#/components/schemas/GreaterThan' less_than: '#/components/schemas/LessThan' between: '#/components/schemas/Between' matches_user_attribute: '#/components/schemas/MatchesUserAttribute' contains: '#/components/schemas/Contains' does_not_contain: '#/components/schemas/DoesNotContain' starts_with: '#/components/schemas/StartsWith' ends_with: '#/components/schemas/EndsWith' is_true: '#/components/schemas/IsTrue' is_false: '#/components/schemas/IsFalse' last: '#/components/schemas/Last' next: '#/components/schemas/Next' before: '#/components/schemas/Before' after: '#/components/schemas/After' matches: '#/components/schemas/Matches' transform_pop_relative: '#/components/schemas/TransformPopRelative' transform_pop_absolute: '#/components/schemas/TransformPopAbsolute' transform_pop_none: '#/components/schemas/TransformPopNone' transform_date_drill: '#/components/schemas/TransformDateDrill' none: '#/components/schemas/None' required: - operator - values Is: type: object allOf: - type: object properties: values: type: array items: $ref: '#/components/schemas/ConditionValue' example: operator: is values: - Alice - Bob - $ref: '#/components/schemas/Condition' IsNot: type: object allOf: - type: object properties: values: type: array items: $ref: '#/components/schemas/ConditionValue' example: operator: is_not values: - Alice - Bob - $ref: '#/components/schemas/Condition' IsNull: type: object allOf: - type: object properties: values: type: array items: $ref: '#/components/schemas/ConditionValue' minItems: 0 maxItems: 0 example: operator: is_null values: [] - $ref: '#/components/schemas/Condition' NotNull: type: object allOf: - type: object properties: values: type: array items: $ref: '#/components/schemas/ConditionValue' minItems: 0 maxItems: 0 example: operator: not_null values: [] - $ref: '#/components/schemas/Condition' GreaterThan: type: object allOf: - type: object properties: values: type: array items: $ref: '#/components/schemas/ConditionValue' minItems: 1 maxItems: 1 example: operator: greater_than values: - 3 - $ref: '#/components/schemas/Condition' LessThan: type: object allOf: - type: object properties: values: type: array items: $ref: '#/components/schemas/ConditionValue' minItems: 1 maxItems: 1 example: operator: less_than values: - 3 - $ref: '#/components/schemas/Condition' Between: type: object allOf: - type: object properties: values: type: array items: $ref: '#/components/schemas/ConditionValue' minItems: 2 maxItems: 2 example: operator: between values: - 3 - 5 - $ref: '#/components/schemas/Condition' MatchesUserAttribute: type: object allOf: - type: object properties: values: type: array items: $ref: '#/components/schemas/ConditionValue' minItems: 1 example: operator: matches_user_attribute values: - h_email - $ref: '#/components/schemas/Condition' Contains: type: object allOf: - type: object properties: values: type: array items: $ref: '#/components/schemas/ConditionValue' minItems: 1 example: operator: contains values: - a - b - $ref: '#/components/schemas/Condition' DoesNotContain: type: object allOf: - type: object properties: values: type: array items: $ref: '#/components/schemas/ConditionValue' minItems: 1 example: operator: does_not_contain values: - a - b - $ref: '#/components/schemas/Condition' StartsWith: type: object allOf: - type: object properties: values: type: array items: $ref: '#/components/schemas/ConditionValue' minItems: 1 example: operator: starts_with values: - a - b - $ref: '#/components/schemas/Condition' EndsWith: type: object allOf: - type: object properties: values: type: array items: $ref: '#/components/schemas/ConditionValue' minItems: 1 example: operator: ends_with values: - a - b - $ref: '#/components/schemas/Condition' IsTrue: type: object allOf: - type: object properties: values: type: array items: $ref: '#/components/schemas/ConditionValue' minItems: 0 maxItems: 0 example: operator: is_true values: [] - $ref: '#/components/schemas/Condition' IsFalse: type: object allOf: - type: object properties: values: type: array items: $ref: '#/components/schemas/ConditionValue' minItems: 0 maxItems: 0 example: operator: is_false values: [] - $ref: '#/components/schemas/Condition' DateTime: type: string enum: - year - quarter - month - week - day - hour - minute Last: type: object allOf: - type: object properties: values: type: array items: $ref: '#/components/schemas/ConditionValue' minItems: 1 maxItems: 1 modifier: $ref: '#/components/schemas/DateTime' example: operator: last values: - 2 modifier: day - $ref: '#/components/schemas/Condition' Next: type: object allOf: - type: object properties: values: type: array items: $ref: '#/components/schemas/ConditionValue' minItems: 1 maxItems: 1 modifier: $ref: '#/components/schemas/DateTime' example: operator: next values: - 2 modifier: day - $ref: '#/components/schemas/Condition' Before: type: object allOf: - type: object properties: values: type: array items: $ref: '#/components/schemas/ConditionValue' minItems: 1 maxItems: 1 example: operator: before values: - '2020-03-21' - $ref: '#/components/schemas/Condition' After: type: object allOf: - type: object properties: values: type: array items: $ref: '#/components/schemas/ConditionValue' minItems: 1 maxItems: 1 example: operator: after values: - '2020-03-21' - $ref: '#/components/schemas/Condition' Matches: type: object allOf: - type: object properties: values: type: array items: $ref: '#/components/schemas/ConditionValue' minItems: 1 maxItems: 1 example: operator: matches values: - last 3 days - $ref: '#/components/schemas/Condition' TransformPopRelative: type: object allOf: - type: object properties: values: type: array items: $ref: '#/components/schemas/ConditionValue' minItems: 1 maxItems: 1 modifier: $ref: '#/components/schemas/DateTime' example: operator: transform_pop_relative values: - 1 modifier: year - $ref: '#/components/schemas/Condition' TransformPopAbsolute: type: object allOf: - type: object properties: values: type: array items: $ref: '#/components/schemas/ConditionValue' minItems: 2 maxItems: 2 example: operator: transform_pop_absolute values: - '2020-07-05' - '2021-02-19' modifier: year - $ref: '#/components/schemas/Condition' TransformPopNone: type: object allOf: - type: object properties: values: type: array items: $ref: '#/components/schemas/ConditionValue' minItems: 0 maxItems: 0 example: operator: transform_pop_none values: null - $ref: '#/components/schemas/Condition' TransformDateDrill: type: object allOf: - type: object properties: values: type: array items: $ref: '#/components/schemas/ConditionValue' minItems: 1 maxItems: 1 example: operator: transform_date_drill values: - datetrunc month - $ref: '#/components/schemas/Condition' None: type: object allOf: - type: object properties: values: type: array items: $ref: '#/components/schemas/ConditionValue' minItems: 0 maxItems: 0 example: operator: none values: [] - type: object properties: operator: type: string description: >- None condition applied. This Condition will be skipped and have no effect on the exploration. - $ref: '#/components/schemas/Condition' DynamicFilterPreset: type: object properties: id: type: integer dynamic_filter_id: anyOf: - type: string - type: integer preset_condition: $ref: '#/components/schemas/Condition' public_hidden: type: boolean default: false description: >- (Only available in Shareable Links) Whether the associated filter should be hidden to public users. Note: This is an UI-only setting and should not be used for permission control. nullable: true required: - dynamic_filter_id - preset_condition DataScheduleEmailDest: type: object allOf: - type: object properties: title: type: string description: >- Email subject. In default, source title will be used if title is not available. Dynamic title: https://docs.holistics.io/docs/delivery/email-schedules/#dynamic-variables. recipients: type: array items: type: string format: email options: type: object properties: preview: type: boolean description: Include preview inside email content. include_header: type: boolean description: Include column headers in Excel, CSV attachments. include_report_link: type: boolean description: Include link to report / dashboard. include_filters: type: boolean description: Include filters info in email content. dont_send_when_empty: type: boolean description: Only send the email when at least one widget has data. body_text: type: string nullable: true description: Text content inside email body. attachment_formats: type: array items: $ref: '#/components/schemas/DataScheduleAttachmentFormat' - $ref: '#/components/schemas/DataScheduleDest' required: - recipients DataScheduleSftpDest: type: object allOf: - type: object properties: dashboard_widget_id: anyOf: - $ref: '#/components/schemas/NullableString' - $ref: '#/components/schemas/NullableNumber' description: >- The widget whose data will be exported to the SFTP destination. Only available for dashboard data schedules. data_source_id: type: integer file_path: type: string format: $ref: '#/components/schemas/DataScheduleDataAttachmentFormat' include_header: type: boolean description: Include column headers in the attachment. separator: type: string description: CSV separator. nullable: true enum: - ',' - '|' - "\t" - ^ - ; - $ref: '#/components/schemas/DataScheduleDest' required: - data_source_id - file_path DataScheduleSlackDest: type: object allOf: - type: object properties: hide_filters: type: boolean message: type: string nullable: true slack_channels: type: array items: type: object title: type: string nullable: true - $ref: '#/components/schemas/DataScheduleDest' required: - slack_channels DataScheduleGoogleSheetDest: type: object allOf: - type: object properties: sheet_url: type: string sheet_title: type: string - $ref: '#/components/schemas/DataScheduleDest' required: - sheet_url - sheet_title DataScheduleAttachmentFormat: description: Attachment format. type: string enum: - csv - xlsx - excel - pdf - png - excel_dashboard - csv_formatted_data DataScheduleDest: type: object properties: type: type: string enum: - EmailDest - SlackDest - SftpDest - GsheetDest required: - type NullableString: type: string nullable: true NullableNumber: type: integer nullable: true DataScheduleDataAttachmentFormat: description: Attachment format. type: string enum: - csv - xlsx DataSchedule: type: object properties: id: type: integer description: Unique Data Schedule identifier. source_type: type: string enum: - Dashboard - QueryReport source_id: type: integer schedule: $ref: '#/components/schemas/Schedule' dynamic_filter_presets: type: array items: $ref: '#/components/schemas/DynamicFilterPreset' dest: type: object oneOf: - $ref: '#/components/schemas/DataScheduleEmailDest' - $ref: '#/components/schemas/DataScheduleSftpDest' - $ref: '#/components/schemas/DataScheduleSlackDest' - $ref: '#/components/schemas/DataScheduleGoogleSheetDest' discriminator: propertyName: type mapping: EmailDest: '#/components/schemas/DataScheduleEmailDest' SftpDest: '#/components/schemas/DataScheduleSftpDest' SlackDest: '#/components/schemas/DataScheduleSlackDest' GsheetDest: '#/components/schemas/DataScheduleGoogleSheetDest' required: - source_type - source_id - dest - schedule PaginationCursor: type: object properties: cursors: type: object properties: previous: type: string nullable: true description: >- Put this value in the `before` parameter to go to previous page. Current page is the first page if this value is null. next: type: string nullable: true description: >- Put this value in the `after` parameter to go to next page. Current page is the last page if this value is null. required: - cursors BaseError: type: object properties: type: type: string enum: - BaseError - RecordError - InvalidParameterError - AuthError - MaintenanceError - SubscriptionError - PermissionDeniedError - InternalHolisticsError - RateLimitExceedError - InvalidOperationError - InvalidEmailsInvitationError message: type: string details: type: object description: Details about this error. properties: description: type: string docs: type: string required: - type - message Message: type: object properties: message: type: string required: - message JobStatus: type: object properties: status: type: string enum: - created - queued - running - success - failure - cancelled - cancelling - already_existed - flow_pending AsyncResult: type: object properties: job: type: object allOf: - type: object properties: id: type: integer - $ref: '#/components/schemas/JobStatus' required: - job FilterSource: type: object properties: source_type: type: string enum: - ManualFilterSource - DmFieldFilterSource required: - source_type ManualFilterSource: type: object allOf: - type: object properties: manual_options: type: array items: type: object properties: value: oneOf: - type: string - type: integer - $ref: '#/components/schemas/FilterSource' FieldPath: anyOf: - type: object properties: field_name: type: string model_id: type: integer nullable: true data_set_id: type: integer nullable: true is_metric: type: boolean nullable: true - type: object properties: field_name: type: string model_id: type: string nullable: true data_set_id: type: integer nullable: true is_metric: type: boolean nullable: true DmFieldFilterSource: type: object allOf: - type: object properties: data_set_id: type: integer field_path: $ref: '#/components/schemas/FieldPath' - $ref: '#/components/schemas/FilterSource' DynamicFilterDefinition: type: object properties: id: type: integer nullable: true label: type: string default_condition: $ref: '#/components/schemas/Condition' filter_type: type: string enum: - number - string - date - boolean - pop - date_drill input_type: type: string nullable: true enum: - single_select - multi_operator - single_select_with_empty_value - null is_sharable: type: boolean filter_source: type: object oneOf: - $ref: '#/components/schemas/ManualFilterSource' - $ref: '#/components/schemas/DmFieldFilterSource' discriminator: propertyName: source_type constraints: type: object nullable: true DynamicFilterMapping: type: object properties: id: type: integer viz_conditionable_id: type: integer description: The id of DashboardWidget that this filter will apply to. viz_conditionable_type: type: string enum: - DashboardWidget field_path: $ref: '#/components/schemas/FieldPath' aggregation: type: string nullable: true permissions: type: object properties: crud: type: boolean DynamicFilter: type: object properties: id: anyOf: - type: integer - type: string order: type: integer uname: type: string permissions: type: object properties: read: type: boolean crud: type: boolean use: type: boolean definition: $ref: '#/components/schemas/DynamicFilterDefinition' drillthrough_enabled: type: boolean mappings: type: array items: $ref: '#/components/schemas/DynamicFilterMapping' Dashboard: type: object properties: id: type: integer owner_id: type: integer title: type: string category_id: type: integer version: type: integer enum: - 1 - 3 - 4 dynamic_filters: type: array items: $ref: '#/components/schemas/DynamicFilter' widgets: type: array items: $ref: '#/components/schemas/DashboardWidget' url: type: string embed_info: $ref: '#/components/schemas/DashboardEmbedInfo' VizType: type: string enum: - data_table - area_chart - line_chart - bar_chart - column_chart - pie_chart - scatter_chart - pyramid_chart - funnel_chart - bubble_chart - retention_heatmap - pivot_table - geo_heatmap - conversion_funnel - combination_chart - metric_kpi - radar_chart - wordcloud - solid_gauge - filled_map - point_map - metric_sheet - new_conversion_funnel - heatmap VizSetting: type: object properties: viz_type: $ref: '#/components/schemas/VizType' source_id: type: integer adhoc_fields: type: array nullable: true items: type: object fields: type: object settings: type: object format: type: object filters: type: array nullable: true items: type: object hashid: type: string custom_chart_id: type: integer nullable: true PersonalItem: type: object nullable: true properties: id: type: integer owner_id: type: integer category_id: type: integer QueryReport: type: object properties: id: type: integer title: type: string data_set_id: type: integer viz_setting: $ref: '#/components/schemas/VizSetting' data_source_id: type: integer owner_id: type: integer category_id: type: integer is_adhoc: type: boolean personal_item: $ref: '#/components/schemas/PersonalItem' x-holistics-internal: true DashboardWidget: type: object properties: id: anyOf: - type: string - type: integer source_id: anyOf: - type: string - type: integer source_type: type: string enum: - QueryReport - QueryMetric - Text - VizBlock source_title: type: string permissions: type: object properties: can_explore: type: boolean description: Current User can explore the Widget's Data Set. can_export: type: boolean description: Current User can use the Export Feature on this Widget. can_export_data: type: boolean description: >- Current User can export data as csv, xlsx. This is a sub-permission of the `export` permission. required: - can_explore - can_export - can_export_data url: type: string dashboard: $ref: '#/components/schemas/Dashboard' query_report: $ref: '#/components/schemas/QueryReport' required: - id - source_id - source_type - permissions Viz: type: object properties: dataset_id: type: number viz_setting: $ref: '#/components/schemas/VizSetting' required: - dataset_id - viz_setting VizBlock: type: object properties: type: type: string enum: - VizBlock uname: type: string label: nullable: true type: string description: nullable: true type: string viz: $ref: '#/components/schemas/Viz' label: type: string filter_type: type: string enum: - number - string - date - boolean - pop - date_drill input_type: type: string nullable: true enum: - single_select - multi_operator - single_select_with_empty_value - null filter_source: type: object oneOf: - $ref: '#/components/schemas/ManualFilterSource' - $ref: '#/components/schemas/DmFieldFilterSource' discriminator: propertyName: source_type constraints: type: object nullable: true AsCodeDynamicFilterDefinition: type: object properties: label: nullable: true $ref: '#/components/schemas/label' default_condition: type: object nullable: true filter_type: $ref: '#/components/schemas/filter_type' input_type: nullable: true $ref: '#/components/schemas/input_type' is_sharable: type: boolean filter_source: type: object nullable: true allOf: - $ref: '#/components/schemas/filter_source' constraints: $ref: '#/components/schemas/constraints' FilterBlock: type: object properties: type: type: string enum: - FilterBlock uname: type: string label: nullable: true type: string filter: $ref: '#/components/schemas/AsCodeDynamicFilterDefinition' TextBlock: type: object properties: type: type: string enum: - TextBlock uname: type: string content: type: string PopBlock: type: object properties: type: type: string enum: - PopBlock uname: type: string label: nullable: true type: string settings: nullable: true type: object description: nullable: true type: string pop: $ref: '#/components/schemas/AsCodeDynamicFilterDefinition' DateDrillBlock: type: object properties: type: type: string enum: - DateDrillBlock uname: type: string label: nullable: true type: string date_drill: $ref: '#/components/schemas/AsCodeDynamicFilterDefinition' Position: type: object properties: x: type: number 'y': type: number w: type: number h: type: number BlockPosition: type: object properties: position: $ref: '#/components/schemas/Position' layer: type: number CanvasLayout: type: object properties: type: type: string enum: - CanvasLayout uname: type: string label: nullable: true type: string width: nullable: true type: number height: nullable: true type: number margin: nullable: true type: number blocks: type: object additionalProperties: $ref: '#/components/schemas/BlockPosition' LinearLayout: type: object properties: type: type: string enum: - LinearLayout uname: type: string label: nullable: true type: string FilterInteraction: type: object properties: type: type: string enum: - FilterInteraction - DateDrillInteraction from: type: string to: type: string field_path: $ref: '#/components/schemas/FieldPath' CrossFilterInteraction: type: object properties: type: type: string enum: - CrossFilterInteraction from: type: string to: type: string DashboardDefinition: type: object x-holistics-internal: true nullable: true properties: title: type: string description: type: string owner: type: string blocks: type: array items: anyOf: - $ref: '#/components/schemas/VizBlock' - $ref: '#/components/schemas/FilterBlock' - $ref: '#/components/schemas/TextBlock' - $ref: '#/components/schemas/PopBlock' - $ref: '#/components/schemas/DateDrillBlock' views: type: array items: oneOf: - $ref: '#/components/schemas/CanvasLayout' - $ref: '#/components/schemas/LinearLayout' interactions: type: array items: oneOf: - $ref: '#/components/schemas/FilterInteraction' - $ref: '#/components/schemas/CrossFilterInteraction' DashboardEmbedInfo: type: object nullable: true description: >- Embed info of the Dashboard. Can be null if Dashboard has not generated Embed Link. properties: hash_code: type: string secret_key: type: string UserRole: description: User role. type: string enum: - user - explorer - analyst - admin - growth_admin - it_admin User: type: object properties: id: type: integer email: type: string name: type: string nullable: true initials: type: string role: $ref: '#/components/schemas/UserRole' is_deleted: type: boolean is_activated: type: boolean has_authentication_token: type: boolean allow_authentication_token: type: boolean enable_export_data: type: boolean current_sign_in_at: type: string format: date-time nullable: true last_sign_in_at: type: string format: date-time nullable: true created_at: type: string format: date-time title: type: string nullable: true job_title: type: string nullable: true required: - id - email - initials - role - is_deleted - is_activated - has_authentication_token - allow_authentication_token - enable_export_data - created_at DashboardStats: type: object x-holistics-internal: true properties: id: type: integer description: type: string created_at: type: string created_user: $ref: '#/components/schemas/User' last_edited_at: type: string nullable: true last_edited_user: anyOf: - type: object nullable: true - $ref: '#/components/schemas/User' frequent_viewers: type: array items: $ref: '#/components/schemas/User' favourites_count: type: integer description: The total favourities of dashboard. views_count: type: integer description: The total views of dashboard. DynamicFilterCondition: type: object description: Selected Condition on a DynamicFilter. properties: dynamic_filter_id: anyOf: - type: integer - type: string condition: $ref: '#/components/schemas/Condition' required: - dynamic_filter_id - condition Job: type: object allOf: - type: object properties: id: type: integer user_id: type: integer start_time: type: string nullable: true end_time: type: string nullable: true cancellable: type: boolean last_error_log: description: The last ERROR-level log of the Job. type: string nullable: true - $ref: '#/components/schemas/JobStatus' JobLog: type: object properties: level: type: string enum: - INFO - ERROR message: type: string timestamp: type: string format: date-time x-faker: date.recent WithData: type: object properties: status: type: string enum: - success error: type: 'null' result: type: object discriminator: propertyName: type mapping: SubmitPublishJobResult: '#/components/schemas/SubmitDeployResult' SubmitValidateJobResult: '#/components/schemas/SubmitValidateResult' oneOf: - $ref: '#/components/schemas/SubmitDeployResult' - $ref: '#/components/schemas/SubmitValidateResult' EmptyData: type: object properties: status: type: string enum: - created - queued - running - failure - cancelled - cancelling - already_existed error: type: string nullable: true result: type: 'null' SuccessDeploy: type: object properties: status: type: string enum: - success preparing_production_job: type: object allOf: - type: object properties: job_id: type: integer - $ref: '#/components/schemas/JobStatus' objects_status: type: object properties: id: type: integer description: id of object in Reporting type: type: string enum: - Dataset - Dashboard uname: type: string description: uname of object in Modeling title: type: string status: type: string enum: - created - updated target_commit: type: string description: target commit of the deployment FailedDeploy: type: object properties: status: type: string enum: - error error_type: type: string enum: - syntax_error - dataset_mapping - dashboard_mapping - dashboard_deployment - aml_server_error error_details: oneOf: - $ref: '#/components/schemas/SyntaxError' - $ref: '#/components/schemas/DatasetMapping' - $ref: '#/components/schemas/DashboardMapping' - $ref: '#/components/schemas/DashboardDeployment' - $ref: '#/components/schemas/AmlServerError' target_commit: type: string description: target commit of the deployment SyntaxError: type: object properties: diagnostics: type: array items: type: object properties: category: type: string enum: - Error code: type: integer message: type: string file_path: type: string start: type: integer description: start offset end: type: integer description: end offset DatasetMapping: type: object properties: message: type: string is_orphaned: type: boolean orphaned_dataset: type: array items: type: object deploying_dataset: type: array items: type: object DashboardMapping: type: array items: type: object properties: type: type: string enum: - Dataset - Dashboard id: type: integer uname: type: string title: type: string dependencies: type: array items: type: object properties: type: type: string enum: - EmbedLink - ShareableLink id: type: integer DashboardDeployment: type: string description: Error message AmlServerError: type: object properties: message: type: string description: error message SubmitDeployResult: type: object properties: type: type: string enum: - SubmitPublishJobResult data: type: object discriminator: propertyName: status mapping: success: '#/components/schemas/SuccessDeploy' error: '#/components/schemas/FailedDeploy' oneOf: - $ref: '#/components/schemas/FailedDeploy' - $ref: '#/components/schemas/SuccessDeploy' SuccessValidate: type: object properties: status: type: string enum: - success FailedValidate: type: object properties: status: type: string enum: - error errors: description: List of errors type: array items: type: object SubmitValidateResult: type: object properties: type: type: string enum: - SubmitPublishJobResult data: type: object discriminator: propertyName: status mapping: success: '#/components/schemas/SuccessValidate' error: '#/components/schemas/FailedValidate' oneOf: - $ref: '#/components/schemas/FailedValidate' - $ref: '#/components/schemas/SuccessValidate' JobResult: type: object discriminator: propertyName: status mapping: success: '#/components/schemas/WithData' created: '#/components/schemas/EmptyData' queued: '#/components/schemas/EmptyData' running: '#/components/schemas/EmptyData' failure: '#/components/schemas/EmptyData' cancelled: '#/components/schemas/EmptyData' cancelling: '#/components/schemas/EmptyData' already_existed: '#/components/schemas/EmptyData' oneOf: - $ref: '#/components/schemas/WithData' - $ref: '#/components/schemas/EmptyData' DataAlertDest: type: object properties: type: type: string enum: - EmailDest - SlackDest - WebhookDest required: - type DataAlertEmailDest: type: object allOf: - type: object properties: title: type: string description: >- Email subject. In default, source title will be used if title is not available. Dynamic title: https://docs.holistics.io/docs/delivery/email-schedules/#dynamic-variables. recipients: type: array items: type: string format: email options: type: object properties: body_text: type: string nullable: true description: Text content inside email body. - $ref: '#/components/schemas/DataAlertDest' required: - recipients DataAlertSlackDest: type: object allOf: - type: object properties: title: type: string description: Slack message title. message: type: string slack_channels: description: Destination Slack channels where the Data Alert will be sent to. type: array items: type: object properties: id: type: string name: type: string - $ref: '#/components/schemas/DataAlertDest' required: - slack_channels DataAlertWebhookDest: type: object allOf: - type: object properties: endpoint: type: string description: Webhook endpoint. - $ref: '#/components/schemas/DataAlertDest' required: - endpoint VizCondition: type: object properties: id: type: integer description: Unique viz condition identifier. field_path: $ref: '#/components/schemas/FieldPath' aggregation: description: >- The aggregation that will be applied on the field when processing the condition. type: string nullable: true enum: - sum - avg - max - min - running sum - running avg - running max - running min - count - count distinct - median - stdev - stdevp - var - varp - custom transformation: description: >- The transformation that will be applied on the field when processing the condition. type: string nullable: true enum: - datetrunc year - datetrunc quarter - datetrunc month - datetrunc week - datetrunc day - datetrunc hour - datetrunc minute condition: $ref: '#/components/schemas/Condition' required: - field_path - condition DataAlert: type: object properties: id: type: integer description: Unique Data Schedule identifier. title: type: string source_id: anyOf: - type: integer - type: string source_type: type: string enum: - DashboardWidget - VizBlock dest: type: string oneOf: - $ref: '#/components/schemas/DataAlertEmailDest' - $ref: '#/components/schemas/DataAlertSlackDest' - $ref: '#/components/schemas/DataAlertWebhookDest' discriminator: propertyName: type mapping: EmailDest: '#/components/schemas/DataAlertEmailDest' SlackDest: '#/components/schemas/DataAlertSlackDest' WebhookDest: '#/components/schemas/DataAlertWebhookDest' dynamic_filter_presets: type: array items: $ref: '#/components/schemas/DynamicFilterPreset' viz_conditions: description: Alert conditions for Data Alert. nullable: true type: array items: $ref: '#/components/schemas/VizCondition' schedule: $ref: '#/components/schemas/Schedule' required: - source_type - source_id - dest - schedule - dynamic_filter_presets DataSource: type: object properties: id: type: integer name: type: string dbtype: type: string settings: type: object properties: require_ssl: type: boolean query_timeout: type: integer nullable: true enable_schema_info: type: boolean use_connection_str: type: boolean timezone: type: string description: Timezone name from the IANA database. is_sample: type: boolean is_default: type: boolean name: type: string settings: type: object properties: require_ssl: type: boolean query_timeout: type: integer nullable: true enable_schema_info: type: boolean use_connection_str: type: boolean timezone: type: string description: Timezone name from the IANA database. dbconfig: type: object properties: database: type: string nullable: true host: type: string nullable: true port: type: string nullable: true username: type: string nullable: true password: type: string nullable: true DbtManifestLog: type: object x-holistics-internal: true properties: id: type: integer description: Unique dbt log identifier. filename: type: string uploader: type: string data_source_name: type: string data_source_type: type: string uploaded_at: type: string required: - filename - source_id DbtIntegration: type: object x-holistics-internal: true properties: id: type: integer description: Unique dbt integration identifier. uploader: type: string upload_method: type: string data_source_name: type: string data_source_type: type: string updated_date: type: string Join: type: object description: Join data. properties: id: type: integer nullable: true name: type: string nullable: true link_type: type: string nullable: true join_on: type: string nullable: true data_source_id: type: integer source_model_id: type: integer nullable: true dest_model_id: type: integer nullable: true source_model: type: object nullable: true properties: id: type: integer nullable: true name: type: string dest_model: type: object nullable: true properties: id: type: integer nullable: true name: type: string missing_source_fields: description: Fields that is in join but not available in the source model. type: array nullable: true items: type: string missing_dest_fields: description: Fields that is in join but not available in the dest model. type: array nullable: true items: type: string JoinConfig: type: object properties: id: type: integer nullable: true data_set_id: type: integer nullable: true join_id: type: integer nullable: true active: type: boolean direction: type: string join: type: object nullable: true properties: name: type: string nullable: true source_model: type: string dest_model: type: string link_type: type: string join_on: type: string nullable: true AggregationType: type: string enum: - avg - sum - count - min - max - count distinct - median - stdev - stdevp - var - varp - custom - not_supported nullable: true TransformType: type: string enum: - datetrunc year - datetrunc quarter - datetrunc month - datetrunc week - datetrunc day - datetrunc hour - datetrunc minute nullable: true FieldType: type: string enum: - date - datetime - number - text - truefalse - duration - time - composite - binary - unknown SyntaxType: type: string enum: - sql - aml - aql - '' DataModelField: type: object properties: aggregation_type: $ref: '#/components/schemas/AggregationType' custom_label: type: string nullable: true field_format: type: string nullable: true description: type: string nullable: true is_custom: type: boolean nullable: true is_custom_measure: type: boolean nullable: true label: type: string model: type: object nullable: true properties: id: oneOf: - type: string - type: integer name: type: string name: type: string sql: type: string transform_type: $ref: '#/components/schemas/TransformType' type: $ref: '#/components/schemas/FieldType' syntax: $ref: '#/components/schemas/SyntaxType' DataModel: type: object properties: id: oneOf: - type: integer - type: string nullable: true data_source_id: type: integer name: type: string label: type: string fields: type: array items: $ref: '#/components/schemas/DataModelField' dimensions: type: array items: $ref: '#/components/schemas/DataModelField' measures: type: array items: $ref: '#/components/schemas/DataModelField' params: type: array items: $ref: '#/components/schemas/DataModelField' category_id: type: integer nullable: true metadata: type: object description: AML metadata from dbt. sql: type: string nullable: true table_name: type: string nullable: true DataSet: type: object properties: id: type: integer name: type: string label: type: string nullable: true description: type: string nullable: true owner_id: type: integer nullable: true owner: type: string nullable: true tenant_id: type: integer data_source_id: type: integer category_id: type: integer nullable: true related_joins: type: array description: List of join data. items: $ref: '#/components/schemas/Join' join_configs: type: array items: type: object $ref: '#/components/schemas/JoinConfig' data_models: type: array items: $ref: '#/components/schemas/DataModel' permission: type: object properties: can_crud: type: boolean can_read: type: boolean uname: type: string from_aml: type: boolean project_id: type: integer nullable: true AMLDataSet: type: object allOf: - type: object properties: version: type: string version_timestamp: type: string is_frontend_cached: type: boolean data_models: type: array items: $ref: '#/components/schemas/DataModel' nullable: true - $ref: '#/components/schemas/DataSet' UsersCounters: type: object properties: total: description: Total number of (filtered) users. type: integer by_role: description: An object containing the user counters for each user role. type: object additionalProperties: type: integer example: viewer: 0 explorer: 0 analyst: 0 admin: 0 growth_admin: 0 required: - total - by_role Group: type: object properties: id: type: integer name: type: string user_ids: type: array items: type: integer InvalidEmailsInvitationError: description: Some emails are invalid when inviting users. type: object allOf: - type: object properties: data: description: A list of emails with their invalid reasons. type: array items: type: object properties: email: type: string reason: type: string - $ref: '#/components/schemas/BaseError' required: - data UserAttribute: type: object properties: id: type: number name: type: string nullable: false attribute_type: type: string nullable: false label: type: string nullable: false description: type: string is_system_attribute: type: boolean example: false required: - name - attribute_type - label UserAttributeInput: type: object properties: name: type: string nullable: false attribute_type: type: string nullable: false label: type: string nullable: false description: type: string required: - name - attribute_type - label RecordError: type: object description: Error when saving a record. allOf: - type: object properties: type: type: string enum: - RecordError - type: object properties: record: description: Detailed errors of the record being created/updated. type: object properties: base: description: >- Overall errors of the whole record (not specific to a single field). type: array items: type: string additionalProperties: description: Errors of a specific field. type: array items: type: string - $ref: '#/components/schemas/BaseError' UserAttributeEntryOutput: type: object properties: user_attribute_id: type: number input_type: type: string enum: - manual - inherit - all subject_type: type: string enum: - User - Group subject_id: type: number required: - user_attribute_id - input_type - subject_type - subject_id UserAttributeEntryInput: type: object properties: user_attribute_entries: type: array description: >- The number of entries that can be processed at once is limited to 100. items: type: object allOf: - properties: input_type: type: string enum: - manual - inherit - all values: type: array items: type: string subject_type: type: string enum: - User - Group subject_id: type: number - anyOf: - title: with User Attribute name properties: user_attribute_id: type: integer - title: with User Attribute ID properties: user_attribute_name: type: string required: - user_attribute_id - user_attribute_name - subject_type - subject_id required: - user_attribute_entries RowBasedPermissionRule: type: object properties: condition: type: object $ref: '#/components/schemas/Condition' field_path: type: object $ref: '#/components/schemas/FieldPath' ShareableLink: type: object properties: resource_type: type: string enum: - Dashboard resource_id: type: number title: type: string nullable: true password_enabled: type: boolean nullable: false password: nullable: true expired_at: type: string nullable: true dynamic_filter_presets: type: array items: $ref: '#/components/schemas/DynamicFilterPreset' permission_rules: type: object properties: row_based: type: array items: $ref: '#/components/schemas/RowBasedPermissionRule' required: - resource_type - resource_id JobQueue: type: object properties: id: type: integer queue: type: string total_workers: type: integer busy_workers: type: integer required: - id - queue - total_workers - busy_workers SectionItem: type: object description: Homepage section item, currently only support Dashboard type properties: id: type: integer type: type: string enum: - Dashboard title: type: string slug: type: string icon: type: string enum: - dashboard - canvas data: type: object parameters: Before: name: before in: query description: Only get records before this cursor. schema: type: string After: name: after in: query description: Only get records after this cursor. schema: type: string Limit: name: limit in: query description: Limit number of records per page. schema: type: integer default: 20 minimum: 1 maximum: 100 IntResourceId: name: id in: path description: Resource id with type integer required: true schema: type: integer ResourceId: name: id in: path description: Resource id. required: true schema: anyOf: - type: string - type: integer SearchTerm: name: search_term in: query description: Search records by its name, title... schema: type: string EmailAttribute: name: email in: query description: Query parameter for email attribute. schema: type: string responses: UnauthorizedError: description: Unauthorized access or invalid credential was used. content: application/json: schema: $ref: '#/components/schemas/BaseError' PermissionDeniedError: description: Access forbidden. content: application/json: schema: $ref: '#/components/schemas/BaseError' InvalidParametersError: description: Invalid parameters were sent. content: application/json: schema: $ref: '#/components/schemas/BaseError' NotFoundError: description: Resource was not found. content: application/json: schema: $ref: '#/components/schemas/BaseError' AsyncResult: description: >- Async result. The operation will be executed asynchronously in a Job. You can check Job status using [Jobs APIs](#tag/Jobs). content: application/json: schema: $ref: '#/components/schemas/AsyncResult' InvalidOperationError: description: Invalid Operation. content: application/json: schema: $ref: '#/components/schemas/BaseError' JobResult: description: Job result. content: application/json: schema: $ref: '#/components/schemas/JobResult' ExportJobNotReady: description: Job is not successful or not ready to be downloaded yet. content: application/json: schema: $ref: '#/components/schemas/BaseError' BaseError: description: Base error. content: application/json: schema: $ref: '#/components/schemas/BaseError' RateLimitExceedError: description: Rate Limit Exceed. content: application/json: schema: $ref: '#/components/schemas/BaseError' MessageOrAsyncResult: description: >- Will return result message of action immediately, else create job to do the action and return job's status. content: application/json: schema: type: object oneOf: - $ref: '#/components/schemas/AsyncResult' - $ref: '#/components/schemas/Message' InvalidEmailsInvitationError: description: Some emails are invalid when inviting users. content: application/json: schema: $ref: '#/components/schemas/InvalidEmailsInvitationError' RecordError: description: Record was not valid. content: application/json: schema: $ref: '#/components/schemas/RecordError' examples: DataScheduleEmailDest: value: data_schedule: id: 1 source_type: Dashboard source_id: 1 schedule: repeat: '* * * * *' paused: false dynamic_filter_presets: - id: 1 dynamic_filter_id: 1 public_hidden: true preset_condition: modifier: null operator: is values: - alice dest: type: EmailDest title: Sale report for {{$today}} recipients: - support@holistics.io - hello@holistics.io options: preview: true include_header: true include_report_link: true include_filters: false dont_send_when_empty: true body_text: Report attachment_formats: - pdf - csv DataScheduleSftpDest: value: data_schedule: id: 1 source_type: Dashboard source_id: 1 schedule: repeat: '* * * * *' paused: false dynamic_filter_presets: - id: 1 dynamic_filter_id: 1 public_hidden: true preset_condition: modifier: null operator: is values: - alice dest: type: SftpDest dashboard_widget_id: 1 data_source_id: 1 file_path: /report format: csv include_header: true separator: ',' paths: /data_schedules: post: operationId: DataSchedules_Create summary: Create a Data Schedule tags: - Data Schedules requestBody: content: application/json: schema: type: object properties: data_schedule: $ref: '#/components/schemas/DataSchedule' required: - data_schedule examples: EmailSchedule: $ref: '#/components/examples/DataScheduleEmailDest' SftpSchedule: $ref: '#/components/examples/DataScheduleSftpDest' responses: '201': description: Data Schedule was created successfully. content: application/json: schema: type: object properties: data_schedule: $ref: '#/components/schemas/DataSchedule' required: - data_schedule '403': $ref: '#/components/responses/PermissionDeniedError' '422': $ref: '#/components/responses/InvalidParametersError' get: operationId: DataSchedules_List summary: List Data Schedules tags: - Data Schedules parameters: - $ref: '#/components/parameters/Before' - $ref: '#/components/parameters/After' - $ref: '#/components/parameters/Limit' - name: dest_type in: query description: Filter by destination type. schema: type: string enum: - EmailDest - SlackDest - Adls2Dest - SftpDest - name: source_type in: query description: Filter by source type. schema: type: string enum: - QueryReport - Dashboard - name: source_id in: query description: Filter by source id. schema: type: integer responses: '200': description: List of Data Schedules. content: application/json: schema: type: object allOf: - type: object properties: data_schedules: type: array items: $ref: '#/components/schemas/DataSchedule' required: - data_schedules - $ref: '#/components/schemas/PaginationCursor' '401': $ref: '#/components/responses/UnauthorizedError' /data_schedules/{id}: parameters: - $ref: '#/components/parameters/IntResourceId' get: operationId: DataSchedules_Get summary: Get a Data Schedule tags: - Data Schedules responses: '200': description: A Data Schedule. content: application/json: schema: type: object properties: data_schedule: $ref: '#/components/schemas/DataSchedule' required: - data_schedule '403': $ref: '#/components/responses/PermissionDeniedError' '404': $ref: '#/components/responses/NotFoundError' put: operationId: DataSchedules_Update summary: Update a Data Schedule tags: - Data Schedules requestBody: content: application/json: schema: type: object properties: data_schedule: $ref: '#/components/schemas/DataSchedule' required: - data_schedule responses: '200': description: Data Schedule was updated successfully. content: application/json: schema: type: object properties: data_schedule: $ref: '#/components/schemas/DataSchedule' required: - data_schedule delete: operationId: DataSchedules_Delete summary: Delete a Data Schedule tags: - Data Schedules responses: '200': description: Data schedule was deleted successfully. content: application/json: schema: $ref: '#/components/schemas/Message' /data_schedules/submit_execute: post: operationId: DataSchedules_SubmitExecute summary: Execute a Data Schedule tags: - Data Schedules responses: '200': $ref: '#/components/responses/AsyncResult' /data_schedules/{id}/submit_execute: parameters: - $ref: '#/components/parameters/IntResourceId' post: operationId: DataSchedules_SubmitExecute summary: Execute a Data Schedule tags: - Data Schedules responses: '200': $ref: '#/components/responses/AsyncResult' /dashboards: get: operationId: Dashboards_List summary: List Dashboards tags: - Dashboards parameters: - $ref: '#/components/parameters/Before' - $ref: '#/components/parameters/After' - $ref: '#/components/parameters/Limit' - name: sort in: query description: | Sort dashboards according to the specified sort order. schema: type: string enum: - natural - id_asc - id_desc default: natural - name: include_embed_info in: query description: Decide whether embed info is included or not. schema: type: boolean responses: '200': description: List of Dashboards. content: application/json: schema: type: object allOf: - type: object properties: dashboards: type: array items: $ref: '#/components/schemas/Dashboard' required: - dashboards - $ref: '#/components/schemas/PaginationCursor' '403': $ref: '#/components/responses/PermissionDeniedError' /dashboards/{id}: parameters: - $ref: '#/components/parameters/IntResourceId' get: operationId: Dashboards_Get summary: Get a Dashboard tags: - Dashboards parameters: [] responses: '200': description: A Dashboard. content: application/json: schema: type: object properties: dashboard: $ref: '#/components/schemas/Dashboard' required: - dashboard '403': $ref: '#/components/responses/PermissionDeniedError' delete: operationId: Dashboards_Delete summary: Delete a Dashboard tags: - Dashboards responses: '200': description: Dashboard was deleted successfully. content: application/json: schema: $ref: '#/components/schemas/Message' '403': $ref: '#/components/responses/PermissionDeniedError' '404': $ref: '#/components/responses/NotFoundError' '422': $ref: '#/components/responses/InvalidOperationError' /dashboards/{id}/build_url: post: operationId: Dashboards_BuildUrl summary: Build a Dashboard URL with preset filter states tags: - Dashboards requestBody: content: application/json: schema: type: object properties: filter_states: type: array items: $ref: '#/components/schemas/DynamicFilterCondition' responses: '200': description: A Dashboard URL. content: application/json: schema: type: object properties: dashboard_url: description: >- The full Dashboard URL with preset filter states. This URL already includes the fstate_hash. type: string fstate_hash: description: >- The hash key representing the filter states data. Note: It is null when there are no submitted filter_states. type: string nullable: true '403': $ref: '#/components/responses/PermissionDeniedError' '404': $ref: '#/components/responses/NotFoundError' '422': $ref: '#/components/responses/InvalidOperationError' parameters: - $ref: '#/components/parameters/IntResourceId' /dashboards/{id}/submit_preload: parameters: - $ref: '#/components/parameters/IntResourceId' post: operationId: Dashboards_SubmitPreload summary: Preload a Dashboard description: >- Preload a Dashboard by executing its widgets (using the submitted filter conditions, or default filter conditions if not submitted) and storing the widgets' results into Holistics cache.
Read more about Data Caching at https://docs.holistics.io/docs/data-caching. tags: - Dashboards requestBody: content: application/json: schema: type: object properties: dashboard_filter_conditions: type: array items: $ref: '#/components/schemas/DynamicFilterCondition' bust_cache: type: boolean description: >- If set to True, ignore existing cache and always execute the widgets. Otherwise, do not execute the widgets that are already cached. default: false examples: Use all default filter conditions: value: {} Specify some filters and use default conditions for the rest: value: dashboard_filter_conditions: - dynamic_filter_id: 101 condition: operator: matches values: - last week - dynamic_filter_id: 201 condition: operator: is values: - alice - bob Skipping specific default filters: value: dashboard_filter_conditions: - dynamic_filter_id: 301 condition: operator: none values: [] responses: '200': $ref: '#/components/responses/AsyncResult' '403': $ref: '#/components/responses/PermissionDeniedError' '404': $ref: '#/components/responses/NotFoundError' /dashboard_widgets/{id}: parameters: - $ref: '#/components/parameters/IntResourceId' get: operationId: DashboardWidgets_Get summary: Get a Dashboard Widget tags: - Dashboard Widgets parameters: - name: include_dashboard in: query description: Decide whether dashboard is included or not. schema: type: boolean - name: include_report in: query description: Decide whether report is included or not. schema: type: boolean - name: include_url in: query description: Decide whether dashboard url, widget url is included or not. schema: type: boolean responses: '200': description: A Dashboard Widget. content: application/json: schema: type: object properties: dashboard_widget: $ref: '#/components/schemas/DashboardWidget' required: - dashboard_widget '403': $ref: '#/components/responses/PermissionDeniedError' '404': $ref: '#/components/responses/NotFoundError' delete: operationId: DashboardWidgets_Delete summary: Delete a Dashboard Widget tags: - Dashboard Widgets responses: '200': description: Dashboard Widget was deleted successfully. content: application/json: schema: $ref: '#/components/schemas/Message' '403': $ref: '#/components/responses/PermissionDeniedError' '404': $ref: '#/components/responses/NotFoundError' /dashboard_widgets/{id}/submit_export: parameters: - $ref: '#/components/parameters/ResourceId' post: operationId: DashboardWidgets_SubmitExport summary: Export a Dashboard Widget description: >- See more details on how to export a widget at [Get Data](#section/Get-Reporting-Data-via-API). When the Job is finished, you can download the exported file using the [download export API](#tag/Exports/operation/Exports_Download). tags: - Dashboard Widgets requestBody: content: application/json: schema: type: object properties: output: type: string description: Output file type. enum: - csv - xlsx - pdf dashboard_filter_conditions: type: array items: $ref: '#/components/schemas/DynamicFilterCondition' required: - output responses: '200': $ref: '#/components/responses/AsyncResult' /jobs/{id}: parameters: - $ref: '#/components/parameters/IntResourceId' get: operationId: Jobs_Get summary: Get a Job tags: - Jobs responses: '200': description: A Job. content: application/json: schema: type: object properties: job: $ref: '#/components/schemas/Job' required: - job /jobs/{id}/logs: parameters: - $ref: '#/components/parameters/IntResourceId' get: operationId: Jobs_GetLogs summary: Get Job's logs tags: - Jobs responses: '200': description: Job's logs. content: application/json: schema: type: object properties: job_logs: type: array items: $ref: '#/components/schemas/JobLog' required: - job_logs /jobs/{id}/result: parameters: - $ref: '#/components/parameters/IntResourceId' get: operationId: Jobs_GetResult summary: Get Job result x-holistics-internal: false tags: - Jobs responses: '200': $ref: '#/components/responses/JobResult' '422': $ref: '#/components/responses/InvalidOperationError' /exports/download: get: operationId: Exports_Download summary: Download an exported file tags: - Exports parameters: - name: job_id in: query description: ID of the Job that has done the exporting. schema: type: integer required: true responses: '302': description: >2- Successful Response. You will be redirected to the exported file's secured URL on Amazon S3. Note that the response content type depends on your exported file. `text/csv` below is just an example. content: text/csv: schema: type: string format: binary '422': $ref: '#/components/responses/ExportJobNotReady' /data_alerts: post: operationId: DataAlerts_Create summary: Create a Data Alert tags: - Data Alerts requestBody: content: application/json: schema: type: object properties: data_alert: $ref: '#/components/schemas/DataAlert' required: - data_alert responses: '201': description: Data Alert was created successfully. content: application/json: schema: type: object properties: data_alert: $ref: '#/components/schemas/DataAlert' required: - data_alert '400': $ref: '#/components/responses/InvalidParametersError' '403': $ref: '#/components/responses/PermissionDeniedError' '422': $ref: '#/components/responses/InvalidOperationError' get: operationId: DataAlerts_List summary: List Data Alerts tags: - Data Alerts parameters: - $ref: '#/components/parameters/Before' - $ref: '#/components/parameters/After' - $ref: '#/components/parameters/Limit' - $ref: '#/components/parameters/SearchTerm' - name: dest_type in: query description: Filter by destination type. schema: type: string enum: - EmailDest - SlackDest - name: source_id in: query description: Filter by source id. schema: anyOf: - type: integer - type: string - name: source_type in: query description: Filter by source type. schema: type: string enum: - DashboardWidget - VizBlock responses: '200': description: List of Data Alerts. content: application/json: schema: type: object allOf: - type: object properties: data_alerts: type: array items: $ref: '#/components/schemas/DataAlert' - $ref: '#/components/schemas/PaginationCursor' required: - data_alerts '401': $ref: '#/components/responses/UnauthorizedError' /data_alerts/{id}: parameters: - $ref: '#/components/parameters/IntResourceId' get: operationId: DataAlerts_Get summary: Get a Data Alert tags: - Data Alerts responses: '200': description: A Data Alert. content: application/json: schema: type: object properties: data_alert: $ref: '#/components/schemas/DataAlert' required: - data_alert '403': $ref: '#/components/responses/PermissionDeniedError' '404': $ref: '#/components/responses/NotFoundError' put: operationId: DataAlerts_Update summary: Update a Data Alert tags: - Data Alerts requestBody: content: application/json: schema: type: object properties: data_alert: $ref: '#/components/schemas/DataAlert' required: - data_alert responses: '200': description: Data Alert was updated successfully. content: application/json: schema: type: object properties: data_alert: $ref: '#/components/schemas/DataAlert' required: - data_alert '422': $ref: '#/components/responses/InvalidOperationError' delete: operationId: DataAlerts_Delete summary: Delete a Data Alert tags: - Data Alerts responses: '200': description: Data Alert was deleted successfully. content: application/json: schema: $ref: '#/components/schemas/Message' /data_alerts/submit_execute: post: operationId: DataAlerts_SubmitExecuteTest summary: Execute a Test Data Alert tags: - Data Alerts requestBody: content: application/json: schema: type: object properties: test_data_alert: $ref: '#/components/schemas/DataAlert' required: - test_data_alert responses: '200': $ref: '#/components/responses/AsyncResult' description: Submit execute response. /data_alerts/{id}/submit_execute: parameters: - $ref: '#/components/parameters/IntResourceId' post: operationId: DataAlerts_SubmitExecute summary: Execute a Data Alert tags: - Data Alerts responses: '200': $ref: '#/components/responses/AsyncResult' description: Submit execute response. '403': $ref: '#/components/responses/PermissionDeniedError' /data_sources/{id}: parameters: - $ref: '#/components/parameters/IntResourceId' get: operationId: DataSources_Get summary: Get a Data Source tags: - Data Sources responses: '200': description: A Data Source. content: application/json: schema: type: object properties: data_source: $ref: '#/components/schemas/DataSource' required: - data_source '403': $ref: '#/components/responses/PermissionDeniedError' '404': $ref: '#/components/responses/NotFoundError' put: operationId: DataSources_Update summary: Update a Data Source tags: - Data Sources requestBody: content: application/json: schema: type: object properties: data_source: type: object properties: name: $ref: '#/components/schemas/name' nullable: true settings: $ref: '#/components/schemas/settings' nullable: true dbconfig: $ref: '#/components/schemas/dbconfig' nullable: true required: - data_source responses: '200': description: A Data Source. content: application/json: schema: type: object properties: data_source: $ref: '#/components/schemas/DataSource' required: - data_source '403': $ref: '#/components/responses/PermissionDeniedError' '404': $ref: '#/components/responses/NotFoundError' delete: operationId: DataSources_Delete summary: Delete a Data Source tags: - Data Sources responses: '200': description: Data Source was deleted successfully. content: application/json: schema: $ref: '#/components/schemas/Message' '422': $ref: '#/components/responses/InvalidOperationError' /data_sources/{id}/bust_exploration_cache: parameters: - $ref: '#/components/parameters/IntResourceId' post: operationId: DataSources_BustExplorationCache summary: Bust Exploration Cache (Beta) description: >- This feature is currently in Beta.

Bust (invalidate) all exploration/report cache of the specified Data Source. After a successful busting, all explorations/reports running on the specified Data Source will return fresh data.

Please note that this does not bust or trigger the Data Source's Model Storages. Hence, even after calling this API, the explorations/reports can only be as fresh as the data persisted in the Model Storages. tags: - Data Sources responses: '200': $ref: '#/components/responses/AsyncResult' '403': $ref: '#/components/responses/PermissionDeniedError' '404': $ref: '#/components/responses/NotFoundError' /data_sources/upload_dbt_manifest: {} /data_sets/{id}: parameters: - $ref: '#/components/parameters/IntResourceId' get: operationId: DataSets_Get summary: Get a Data Set tags: - Data Sets parameters: - name: include_models in: query description: Decide whether data models are included or not. schema: type: boolean - name: include_reports in: query description: Decide whether query reports are included or not. schema: type: boolean responses: '200': description: A Data Set. content: application/json: schema: type: object properties: data_set: allOf: - type: object properties: data_models: type: array items: type: object $ref: '#/components/schemas/DataModel' reports: type: array items: type: object $ref: '#/components/schemas/QueryReport' nullable: true - $ref: '#/components/schemas/DataSet' required: - data_set '403': $ref: '#/components/responses/PermissionDeniedError' '404': $ref: '#/components/responses/NotFoundError' '429': $ref: '#/components/responses/RateLimitExceedError' delete: operationId: DataSets_Delete summary: Delete a Data Set. description: >- We do not support deleting data set created from AML yet, try deleting it from AML Studio. Send your request to support@holistics.io if you have any concern. tags: - Data Sets responses: '200': description: Data Set was deleted successfully. content: application/json: schema: $ref: '#/components/schemas/Message' '403': $ref: '#/components/responses/PermissionDeniedError' '404': $ref: '#/components/responses/NotFoundError' '422': $ref: '#/components/responses/InvalidOperationError' /data_models: get: operationId: DataModels_List summary: List Data Models tags: - Data Models parameters: - in: query name: project_id description: AML Project Id schema: type: integer required: true - name: branch_name in: query description: >- Branch name to get list of models. branch_name param will be ignore if commit_oid is available. schema: type: string required: false - name: commit_oid in: query description: Commit oid to get list of models. schema: type: string required: false responses: '200': description: All Data Models. content: application/json: schema: type: object properties: data_models: type: array items: $ref: '#/components/schemas/DataModel' required: - data_models '403': $ref: '#/components/responses/PermissionDeniedError' '404': $ref: '#/components/responses/NotFoundError' /query_reports/{id}: parameters: - $ref: '#/components/parameters/IntResourceId' get: operationId: QueryReports_Get summary: Get a Query Report tags: - Query Reports parameters: - name: include_data_set in: query description: Decide whether Data Set is included or not. schema: type: boolean responses: '200': description: A Report. content: application/json: schema: type: object properties: query_report: allOf: - type: object properties: data_set: type: object $ref: '#/components/schemas/DataSet' - $ref: '#/components/schemas/QueryReport' required: - query_report '403': $ref: '#/components/responses/PermissionDeniedError' '404': $ref: '#/components/responses/NotFoundError' /users: get: operationId: Users_List summary: List Users tags: - Users parameters: - $ref: '#/components/parameters/Before' - $ref: '#/components/parameters/After' - $ref: '#/components/parameters/Limit' - name: search_term in: query description: Search by User `email`, `name`, `initials` or Group names. schema: type: string - name: status in: query description: Filter by User status. schema: type: string enum: - active - deleted - pending - name: role in: query description: Filter by User `role`. schema: $ref: '#/components/schemas/UserRole' - name: has_authentication_token in: query description: > Whether or not to include users who have API key. *Note:* the result also includes users even when their API access has been revoked. schema: type: boolean - name: exclude_deleted in: query description: Whether or not to exclude deleted Users. schema: type: boolean - name: sort in: query description: > Sort the Users according to the specified sort order. If multiple records have the same value, the corresponding order of User `id` will be applied to assure consistent result. schema: type: string enum: - natural - id_asc - id_desc - name_asc - name_desc - initials_asc - initials_desc default: natural responses: '200': description: User listing response. content: application/json: schema: type: object allOf: - type: object properties: counters: $ref: '#/components/schemas/UsersCounters' users: description: >- List of Users. Each `User` object also contains `group_ids` which is the ID list of the Groups that the User belongs to. type: array items: allOf: - type: object properties: group_ids: type: array items: type: integer required: - group_ids - $ref: '#/components/schemas/User' groups: type: object description: > An object containing Group ids as keys with their corressponding Group data as values. > NOTE: this only contains the Groups of the Users above. additionalProperties: type: object $ref: '#/components/schemas/Group' example: '1': id: 1 name: string '2': id: 2 name: string required: - counters - users - groups - $ref: '#/components/schemas/PaginationCursor' /users/{id}: parameters: - $ref: '#/components/parameters/IntResourceId' put: operationId: Users_Update summary: Update a User tags: - Users requestBody: content: application/json: schema: type: object properties: user: type: object properties: password: description: User password. type: string name: description: User name. type: string nullable: true title: description: User title. type: string nullable: true job_title: description: User job title. type: string nullable: true role: allOf: - $ref: '#/components/schemas/UserRole' allow_authentication_token: description: Allow User to have API access. type: boolean enable_export_data: description: >- [(Enterprise feature) Allow/disallow exporting data](https://docs.holistics.io/docs/user-management#enterprise-feature-allowdisallow-exporting-data). type: boolean group_ids: description: List of new Group ids that the User will be assigned to. type: array items: type: integer responses: '200': description: The updated User. content: application/json: schema: $ref: '#/components/schemas/User' '403': $ref: '#/components/responses/PermissionDeniedError' '422': $ref: '#/components/responses/InvalidOperationError' delete: operationId: Users_Delete summary: Delete a User (soft-delete) description: >- Revoke a User from accessing and using Holistics.
Note: The soft-deleted User will still retain ownership of their resources. You can contact support@holistics.io to request for an ownership transfer. tags: - Users responses: '200': description: User was deleted successfully. content: application/json: schema: $ref: '#/components/schemas/Message' '403': description: You don't have permission to delete user. $ref: '#/components/responses/PermissionDeniedError' '404': description: User not found. $ref: '#/components/responses/NotFoundError' '422': description: User not permitted to self-destruction. $ref: '#/components/responses/InvalidParametersError' /users/invite: post: operationId: Users_Invite summary: Invite Users tags: - Users requestBody: content: application/json: schema: type: object properties: emails: description: List of User emails to invite. type: array items: type: string role: description: Role that will be applied to specified Users. allOf: - $ref: '#/components/schemas/UserRole' allow_authentication_token: description: Allow Users to have API access. type: boolean enable_export_data: description: >- [(Enterprise feature) Allow/disallow exporting data](https://docs.holistics.io/docs/user-management#enterprise-feature-allowdisallow-exporting-data). type: boolean group_ids: description: List of Group ids that the Users will be assigned to. type: array items: type: integer message: description: Greeting message that will be sent to all User emails. type: string required: - emails - role responses: '200': $ref: '#/components/responses/AsyncResult' '403': $ref: '#/components/responses/PermissionDeniedError' '422': $ref: '#/components/responses/InvalidEmailsInvitationError' /users/{id}/restore: parameters: - $ref: '#/components/parameters/IntResourceId' post: operationId: Users_Restore summary: Restore a Deleted User tags: - Users responses: '200': description: User was restored successfully. content: application/json: schema: $ref: '#/components/schemas/Message' '403': description: You don't have permission to restore User. $ref: '#/components/responses/PermissionDeniedError' '404': description: User not found. $ref: '#/components/responses/NotFoundError' '422': description: User is not deleted. $ref: '#/components/responses/InvalidOperationError' /users/{id}/resend_invite: parameters: - $ref: '#/components/parameters/IntResourceId' post: operationId: Users_ResendInvite summary: Resend invitation to User tags: - Users responses: '200': $ref: '#/components/responses/AsyncResult' '403': description: You don't have permission to resend invite User. $ref: '#/components/responses/PermissionDeniedError' '404': description: User not found. $ref: '#/components/responses/NotFoundError' '422': description: Unable to locate invitation. $ref: '#/components/responses/InvalidOperationError' /users/{id}/revoke_authentication_token: parameters: - $ref: '#/components/parameters/IntResourceId' post: operationId: Users_RevokeAuthenticationToken summary: Revoke User API key. description: Admin can revoke all users' tokens. Users can revoke their tokens. tags: - Users responses: '200': description: User token was revoked. content: application/json: schema: $ref: '#/components/schemas/Message' '403': description: You don't have permission to revoke this User authentication token. $ref: '#/components/responses/PermissionDeniedError' '404': description: User not found. $ref: '#/components/responses/NotFoundError' /users/check_holistics_user: parameters: - $ref: '#/components/parameters/EmailAttribute' get: operationId: Users_CheckHolisticsUser summary: Check if email address is used description: >- Check if the specified email address is already used for a User in your Holistics workspace. tags: - Users responses: '200': description: Returning a Boolean Variable 'is_already_user'. content: application/json: schema: type: object properties: is_already_user: type: boolean '403': $ref: '#/components/responses/PermissionDeniedError' /users/me: get: operationId: Users_Me summary: Get currently authorized User tags: - Users responses: '200': description: Info of the currently authorized User. content: application/json: schema: type: object properties: user: $ref: '#/components/schemas/User' '401': $ref: '#/components/responses/UnauthorizedError' /user_attributes: post: operationId: UserAttributes_Create summary: Create a User Attribute tags: - User Attributes (Beta) requestBody: content: application/json: schema: type: object properties: user_attribute: $ref: '#/components/schemas/UserAttributeInput' required: - user_attribute responses: '200': description: User Attribute was created successfully. content: application/json: schema: type: object properties: user_attribute: $ref: '#/components/schemas/UserAttribute' status: type: string enum: - created required: - user_attribute '401': $ref: '#/components/responses/UnauthorizedError' '422': $ref: '#/components/responses/InvalidParametersError' get: operationId: UserAttributes_List summary: List User Attributes description: >- List [User Attributes](https://docs.holistics.io/docs/user-attributes) including [System Attributes](https://docs.holistics.io/docs/user-attributes#system-user-attributes) tags: - User Attributes (Beta) parameters: - $ref: '#/components/parameters/Before' - $ref: '#/components/parameters/After' - $ref: '#/components/parameters/Limit' responses: '200': description: List of User Attributes. content: application/json: schema: type: object allOf: - type: object properties: user_attributes: description: List of User Attributes, including System Attributes. type: array items: $ref: '#/components/schemas/UserAttribute' required: - user_attributes - $ref: '#/components/schemas/PaginationCursor' '401': $ref: '#/components/responses/UnauthorizedError' /user_attributes/{id}: parameters: - $ref: '#/components/parameters/IntResourceId' put: operationId: UserAttributes_Update summary: Update a User Attribute tags: - User Attributes (Beta) requestBody: content: application/json: schema: type: object properties: user_attribute: $ref: '#/components/schemas/UserAttributeInput' required: - user_attribute responses: '200': description: User Attribute was updated successfully. content: application/json: schema: type: object properties: user_attribute: $ref: '#/components/schemas/UserAttribute' required: - user_attribute '401': $ref: '#/components/responses/UnauthorizedError' '403': $ref: '#/components/responses/PermissionDeniedError' '422': $ref: '#/components/responses/RecordError' delete: operationId: UserAttributes_Delete summary: Delete a User Attribute tags: - User Attributes (Beta) responses: '200': description: User Attribute was deleted successfully. content: application/json: schema: $ref: '#/components/schemas/Message' '401': $ref: '#/components/responses/UnauthorizedError' '403': description: You don't have permission to delete User Attribute. $ref: '#/components/responses/PermissionDeniedError' '404': description: User Attribute wasn't found. $ref: '#/components/responses/NotFoundError' /user_attribute_entries: get: operationId: UserAttributeEntries_List summary: List User Attribute Entries tags: - User Attributes (Beta) parameters: - name: subject_type in: query description: Subject type. schema: type: string enum: - User - Group required: true - name: subject_id in: query description: Subject Id. schema: type: number required: true responses: '200': description: List of User Attribute Entries. content: application/json: schema: type: object allOf: - type: object properties: user_attribute_entries: type: array items: $ref: '#/components/schemas/UserAttributeEntryOutput' - $ref: '#/components/schemas/PaginationCursor' '401': $ref: '#/components/responses/UnauthorizedError' '403': $ref: '#/components/responses/PermissionDeniedError' /user_attribute_entries/computed_values: get: operationId: UserAttributeEntries_ComputedValues summary: Compute User Attribute Values tags: - User Attributes (Beta) parameters: - name: subject_type in: query description: Subject type. schema: type: string enum: - User - Group required: true - name: subject_id in: query description: Subject Id. schema: type: number required: true responses: '200': description: Computed values of User Attribute. content: application/json: schema: type: object properties: user_attribute_values: type: object additionalProperties: type: array items: type: string example: user_attribute_name_1: - value_1 - value_2 '401': $ref: '#/components/responses/UnauthorizedError' '403': $ref: '#/components/responses/PermissionDeniedError' /user_attribute_entries/upsert: put: operationId: UserAttributeEntries_Upsert summary: Upsert User Attribute Entries tags: - User Attributes (Beta) requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UserAttributeEntryInput' responses: '200': description: Upsert User Attribute Entries successfully. content: application/json: schema: type: object properties: user_attribute_entries: type: array items: $ref: '#/components/schemas/UserAttributeEntryOutput' '400': $ref: '#/components/responses/InvalidParametersError' '401': $ref: '#/components/responses/UnauthorizedError' '403': $ref: '#/components/responses/PermissionDeniedError' '404': $ref: '#/components/responses/BaseError' '422': $ref: '#/components/responses/InvalidOperationError' /dependencies/downstream_dependencies: get: operationId: Dependencies_DownstreamDependencies summary: Get object's downstream dependencies tags: - Dependencies parameters: - in: query name: id description: Object id. required: true schema: type: integer - in: query name: type description: Object type. required: true schema: type: string enum: - DataSource - DataModel - DataSet responses: '200': description: An object's downstream dependencies. content: application/json: schema: type: object properties: dependants: type: object additionalProperties: type: array items: type: integer example: data_model_ids: - 1 - 2 - 3 data_set_ids: - 5 - 6 required: - dependants '403': $ref: '#/components/responses/PermissionDeniedError' '404': $ref: '#/components/responses/NotFoundError' /aml_studio/projects/submit_publish: post: operationId: AmlStudioProjects_SubmitDeploy summary: Publish the AML Project to Production tags: - AML Studio requestBody: content: application/json: schema: type: object properties: object_mapping: type: object description: >- associate an deploying object with an orphan reporting object properties: datasets: type: object description: '{ "\": "\" }' responses: '200': $ref: '#/components/responses/AsyncResult' description: go go go '403': $ref: '#/components/responses/PermissionDeniedError' '404': $ref: '#/components/responses/NotFoundError' '422': $ref: '#/components/responses/InvalidOperationError' /aml_studio/projects/submit_validate: post: operationId: AmlStudioProjects_SubmitValidate summary: Validate AML Project tags: - AML Studio parameters: - name: branch_name in: query description: Branch name to run validation schema: type: string required: true - name: commit_oid in: query description: Commit oid to run validation schema: type: string required: true responses: '200': $ref: '#/components/responses/AsyncResult' '403': $ref: '#/components/responses/PermissionDeniedError' '404': $ref: '#/components/responses/NotFoundError' '422': $ref: '#/components/responses/InvalidOperationError' /shareable_links: post: operationId: ShareableLinks_Create summary: Create a Shareable Link tags: - Shareable Links requestBody: content: application/json: schema: type: object properties: shareable_link: $ref: '#/components/schemas/ShareableLink' required: - shareable_link responses: '201': description: Shareable Link was created successfully. content: application/json: schema: type: object properties: shareable_link: $ref: '#/components/schemas/ShareableLink' required: - shareable_link '403': $ref: '#/components/responses/PermissionDeniedError' '422': $ref: '#/components/responses/InvalidParametersError' get: operationId: ShareableLinks_List summary: List Shareable Links tags: - Shareable Links parameters: - $ref: '#/components/parameters/Before' - $ref: '#/components/parameters/After' - $ref: '#/components/parameters/Limit' - name: sort in: query description: | Sort dashboards according to the specified sort order. schema: type: string enum: - natural - id_asc - id_desc default: natural - name: resource_type in: query description: Filter by resource type. schema: type: string enum: - Dashboard - name: resource_id in: query description: Filter by resource ID. schema: type: integer responses: '200': description: List of Shareable Links. content: application/json: schema: type: object allOf: - type: object properties: shareable_links: type: array items: $ref: '#/components/schemas/ShareableLink' required: - shareable_links - $ref: '#/components/schemas/PaginationCursor' '401': $ref: '#/components/responses/UnauthorizedError' /shareable_links/{id}: parameters: - $ref: '#/components/parameters/IntResourceId' get: operationId: ShareableLinks_Get summary: Get a Shareable Link tags: - Shareable Links responses: '200': description: A Shareable Link. content: application/json: schema: type: object properties: shareable_link: $ref: '#/components/schemas/ShareableLink' required: - shareable_link '403': $ref: '#/components/responses/PermissionDeniedError' '404': $ref: '#/components/responses/NotFoundError' put: operationId: ShareableLinks_Update summary: Update a Shareable Link tags: - Shareable Links requestBody: content: application/json: schema: type: object properties: shareable_link: $ref: '#/components/schemas/ShareableLink' required: - shareable_link responses: '200': description: Shareable Link was updated successfully. content: application/json: schema: type: object properties: shareable_link: $ref: '#/components/schemas/ShareableLink' required: - shareable_link '403': $ref: '#/components/responses/PermissionDeniedError' '422': $ref: '#/components/responses/InvalidParametersError' delete: operationId: ShareableLinks_Delete summary: Delete a Shareable Link tags: - Shareable Links responses: '200': description: Shareable Link was deleted successfully. content: application/json: schema: $ref: '#/components/schemas/Message' '403': description: User doesn't have permission to delete Shareable Link. $ref: '#/components/responses/PermissionDeniedError' /groups: post: operationId: Groups_Create summary: Create a Group tags: - Groups requestBody: content: application/json: schema: type: object properties: group: type: object properties: name: type: string required: - name required: - group responses: '201': description: Group was created successfully. content: application/json: schema: type: object properties: group: $ref: '#/components/schemas/Group' required: - group '403': $ref: '#/components/responses/PermissionDeniedError' '422': $ref: '#/components/responses/InvalidOperationError' get: operationId: Groups_List summary: List Groups tags: - Groups parameters: - $ref: '#/components/parameters/Before' - $ref: '#/components/parameters/After' - $ref: '#/components/parameters/Limit' - name: sort in: query description: | Sort groups according to the specified sort order. schema: type: string enum: - natural - id_asc - id_desc default: natural - name: include_users in: query description: | Include users in the response. schema: type: boolean responses: '200': description: List of Groups. content: application/json: schema: type: object allOf: - type: object properties: groups: type: array items: $ref: '#/components/schemas/Group' example: - id: 1 name: sample_group user_ids: - 1 - 2 users: type: object description: > An object containing user ids as keys with their corresponding user data as values. > NOTE: this only contains the users of the groups above. additionalProperties: type: object $ref: '#/components/schemas/User' example: '1': id: 1 email: admin@domain.com name: admin_user initials: string role: user is_deleted: false is_activated: true has_authentication_token: true allow_authentication_token: true enable_export_data: true current_sign_in_at: '2019-08-24T14:15:22Z' last_sign_in_at: '2019-08-24T14:15:22Z' created_at: '2019-08-24T14:15:22Z' title: admin_user job_title: admin '2': id: 2 email: analyst@domain.com name: analyst_user initials: string role: user is_deleted: false is_activated: true has_authentication_token: true allow_authentication_token: true enable_export_data: true current_sign_in_at: '2019-08-24T14:15:22Z' last_sign_in_at: '2019-08-24T14:15:22Z' created_at: '2019-08-24T14:15:22Z' title: analyst_user job_title: analyst required: - groups - users - $ref: '#/components/schemas/PaginationCursor' '403': $ref: '#/components/responses/PermissionDeniedError' /groups/{id}: parameters: - $ref: '#/components/parameters/IntResourceId' get: operationId: Groups_Get summary: Get a Group tags: - Groups parameters: - in: query name: include_users description: Whether to include Users information. schema: type: boolean responses: '200': description: A Group. content: application/json: schema: type: object properties: group: $ref: '#/components/schemas/Group' required: - group '403': $ref: '#/components/responses/PermissionDeniedError' '404': $ref: '#/components/responses/NotFoundError' put: operationId: Groups_Update summary: Update a Group tags: - Groups requestBody: content: application/json: schema: type: object properties: group: type: object properties: name: type: string required: - group responses: '200': description: Group was updated successfully. content: application/json: schema: type: object properties: group: $ref: '#/components/schemas/Group' required: - group '403': $ref: '#/components/responses/PermissionDeniedError' '404': $ref: '#/components/responses/NotFoundError' '422': $ref: '#/components/responses/InvalidParametersError' delete: operationId: Groups_Delete summary: Delete a Group tags: - Groups responses: '200': description: Group was deleted successfully. content: application/json: schema: $ref: '#/components/schemas/Message' '403': $ref: '#/components/responses/PermissionDeniedError' '404': $ref: '#/components/responses/NotFoundError' /groups/{id}/add_user/{user_id}: parameters: - $ref: '#/components/parameters/IntResourceId' - in: path name: user_id description: User id. required: true schema: type: integer post: operationId: Groups_AddUser summary: Add a User to a Group tags: - Groups responses: '200': description: User was added successfully. content: application/json: schema: $ref: '#/components/schemas/Message' '403': $ref: '#/components/responses/PermissionDeniedError' '404': $ref: '#/components/responses/NotFoundError' '422': $ref: '#/components/responses/InvalidParametersError' /groups/{id}/remove_user/{user_id}: parameters: - $ref: '#/components/parameters/IntResourceId' - in: path name: user_id description: User id. required: true schema: type: integer post: operationId: Groups_RemoveUser summary: Remove a User from a Group tags: - Groups responses: '200': description: Remove User successfully. content: application/json: schema: $ref: '#/components/schemas/Message' '403': $ref: '#/components/responses/PermissionDeniedError' '404': $ref: '#/components/responses/NotFoundError' /job_queues: get: operationId: JobQueues_List summary: List Job's queues tags: - Jobs responses: '200': description: >- List of Job's queues with their number of total workers and number of busy workers. content: application/json: schema: type: object properties: job_queues: type: array items: $ref: '#/components/schemas/JobQueue' required: - job_queues '401': $ref: '#/components/responses/UnauthorizedError' '403': $ref: '#/components/responses/PermissionDeniedError' /data_model_persistences/validate_ddl: post: operationId: DataModelPersistences_ValidateDDL summary: Validate data model persistence custom DDL tags: - Data Model Persistences requestBody: content: application/json: schema: type: object properties: ddl: type: string required: - ddl responses: '200': description: The custom DDL is valid content: application/json: schema: type: object properties: status: type: string enum: - success '401': $ref: '#/components/responses/UnauthorizedError' '403': $ref: '#/components/responses/PermissionDeniedError' '422': $ref: '#/components/responses/InvalidOperationError' /embed/{hashcode}/shorten_token: post: operationId: Embed_ShortenToken summary: Create a Shortened embed token description: >- Use this API to shorten the embed token if the URL exceeds the browser's size limit. tags: - Embed parameters: - in: path name: hashcode required: true schema: type: string description: The embed code of the dashboard for shortening the token. requestBody: content: application/json: schema: type: object properties: token: type: string required: - token responses: '201': description: Shortened token was created successfully. content: application/json: schema: type: object properties: shortened_token: type: string '400': $ref: '#/components/responses/InvalidParametersError' '401': $ref: '#/components/responses/UnauthorizedError' '404': $ref: '#/components/responses/NotFoundError' tags: - name: Errors description: > |HTTP Code|Description| ---|--- |200 - OK|Everything worked as expected.| |400 - Bad Request|The request was unacceptable due to missing request parameter or wrong request structure.| |401 - Unauthorized|No valid API key provided.| |403 - Forbidden|The API Key owner does not have permission to perform the request.| |404 - Not Found|The requested resource does not exist or cannot found.| |422 - Unprocessable Entity|Cannot process the request parameter due to semantic errors. See the message for more detail.| |429 - Too Many Requests|Too many requests were sent.| |500 - Internal Holistics Error|Something went wrong on Holistics side (rarely).| |Error type|Description| ---|--- |BaseError|Base schema for all types of errors.| |RecordError|Error when saving a record.| |InvalidParameterError|One or more parameters are missing or do not satisfy the endpoint's requirements.| |AuthError|Could not authorize current user, typically due to missing or expired authentication token.| |MaintenanceError|Your admins has set Holistics to Maintenance mode| |SubscriptionError|The subscription of the tenant does not have permission to access the resource. | |PermissionDeniedError|The API Key owner does not have permission to access a resource.| |InternalHolisticsError|Internal Holistics error. Please provide us the `debug id` in error message so we can investigate further.| |InvalidOperationError|Can not process your action due to system constraints. ### Base Error (All errors inherit from this): ### Record Error: - name: Rate-Limiting description: > ## Overview To prevent DDoS attacks, every API request should go through our rate limit layer which will throttle the request if a user exceeds limit quotas. The rate limit is based on user and endpoint, quotas (per time frame) which maybe different for each endpoint are divided by levels as the table below: | Level | Quota | Note | |---------------|----------|---------------------------------------------------------| | Level 1 | 120 | At least every API request is this level | | Level 2 | 60 | Request requires a lot of resource | | Level 3 | 20 | Request that heavily affect our server's resources | ## Return Header And Status Code If a request is blocked because of it exceed the limit quota, status code is set to 429: Too Many Requests
Every API request returns header contains the following fields: RateLimit-Limit: your_limit_quota_of_endpoint
RateLimit-Remaining: remaining_requests_until_reset
RateLimit-Reset: next_reset_time
Retry-After: next_reset_time(only available when status code is 429)
- name: Tutorials description: "# Get Reporting Data via API\n\n\n## Introduction\n\nThis short tutorial shows you how to use the Holistics APIs to get report data in raw tabular form (CSV, Excel).\n\nThis tutorial uses Ruby, but you can easily use any other language for it.\n\n> ⓘ **INFO**\n>\n> We'll be working on client libraries wrapper around our API. Once done, using the APIs will be simpler by just making a few function calls.\n\n## Mechanism\n\nSince Holistics uses a async job queuing system to process job, you can't make a single API call to retrieve the results. We need to submit an 'export request', then wait for the export job to finish, and then make an API call to download the results.\n\n\n**API Endpoints used:**\n- [Export a Dashboard Widget](#tag/Dashboard-Widgets/operation/DashboardWidgets_SubmitExport)\n- [Download an exported job](#tag/Exports/operation/Exports_Download)\n\n## Steps\n\nLet's go through the steps here.\n\n### 1. Setting Up API Key\n\nPlease see [guide](/api/index.md) to set up and retrieve your API key.\n\n### 2. Initial code structure\n\nTo make things simple and reusable, we'll wrap our code around a `HolisticsAPI` class. We'll also use the [httprb](https://github.com/httprb/http) gem to handle making HTTP calls.\n\n```ruby\nrequire 'http'\nclass HolisticsAPI\n def initialize(api_key, host: 'secure.holistics.io')\n @api_key = api_key\n @api_url = \"https://#{host}/api/v2\"\n @http = HTTP.headers({'X-Holistics-Key' => @api_key})\n end\nend\n```\n\n### 3. (Optional) Get Filters ID for your Dashboard Export\n\nIf you want to include **Filters** in your export, you will need to get their Filter IDs. Please follow these steps to obtain them:\n\n**1. Get your Dashboard ID**\n\nThe Dashboard ID can be retrieved by looking at its URL in the browser. In this sample URL below, the Dashboard ID would be 16076.\n\n\n\n**2. Get Filter ID**\n\nSupposed that your dashboard has a sets of filters like the one below. Let's get the ID of the **Date filter** to include it in our export.\n\n\n\nWe will use [Get Dashboard API](#operation/Dashboards_Get) for this purpose. Let's call the API with the Dashboard ID from step 1.\n\n```ruby\ncurl --location --request GET 'https://secure.holistics.io/api/v2/dashboards/{your_dashboard_id}' \\\n--header 'X-Holistics-Key: your_API_key' \\\n--header 'Content-Type: application/json' \\\n```\nThe response would be quite lengthy, but you just need to find the **dynamic_filters** field to get the **Filter ID**.\n\n\n\nYou can then use this Filter ID in the next step.\n\n\n### 4. Submit widget export request\n\nMake sure you have the DashboardWidget ID in hand. The widget ID can be retrieved by opening up the widget in the dashboard, and look at the `_e` parameter in the URL. For example, 4175 is the widget ID of the below.\n\n```\nhttps://secure.holistics.io/dashboards/v3/12345-some-dashboard/?_e=4175\n```\n> ⓘ **INFO**\n>\n> (Optional) Include filter conditions in your export\n> If you wish to include a filter condition in your export, first refer to [step 3](#3-optional-include-filters-in-your-dashboard-export) to get your desired **Filter ID**.\n>\n> Then, append **dashboard_filter_conditions** in your request body.\n>\n> - **dynamic_filter_id** is the Filter ID from step 3.\n> - **condition:**\n> - **operator:** refer to [Data Modeling Condition](#tag/Data-Modeling/DataModelingCondition) for all available operators.\n> - **values:** is an array of strings or integers that go with the operator.\n>\n> For example, assuming that you have completed step 3, to apply a **Date Filter** that filters data from 2 months ago to the export, simply include this snippet to your request.\n>\n> ```ruby\n> {\n> \"dashboard_filter_conditions\": [\n> {\n> \"dynamic_filter_id\": 2335,\n> \"condition\": {\n> \"operator\": \"matches\",\n> \"values\": [\n> \"2 months ago\"\n> ]\n> }\n> }\n> ]\n> }\n> ```\n\nThen we make the call to submit widget export:\n\n```ruby\nclass HolisticsAPI\n # ...\n\n # output: 'csv' or 'excel'\n def submit_report(widget_id, output: 'csv')\n url = @api_url + \"/dashboard_widgets/\" + widget_id.to_s + \"/submit_export\"\n\n response = @http.post(url, json: {output: output})\n res = JSON.parse(response.to_s)\n\n if response.code == 200\n res['job']['id']\n else\n raise StandardError.new(res['message'])\n end\n end\nend\n\n```\n\nIf successful, this method returns the job ID of the job created.\n\n### 5. Waiting for job to complete\n\nThe job will the go to the queue system waiting to be processed. This method below will continuously poll the job's metadata until it is either success, or failure.\n\n\n```ruby\nclass HolisticsAPI\n # ...\n\n def wait_for_job_status(job_id)\n url = @api_url + \"/jobs/\" + job_id.to_s\n\n while true do\n response = @http.get(url)\n res = JSON.parse(response.to_s)\n\n raise StandardError.new(res['message']) if response.code != 200\n\n status = res['job']['status']\n puts \"===> status: #{status}\"\n\n unless ['created', 'running', 'queued'].include?(status)\n return status\n end\n\n # Wait a while before pinging again\n sleep 2\n end\n end\nend\n```\n\n### 6. Downloading the results\n\nOnce the job finishes, we make one final API call to\n\n```ruby\nclass HolisticsAPI\n # ...\n\n def download_export(job_id)\n url = @api_url + \"/exports/download\"\n response = @http.follow.get(url, params: {job_id: job_id})\n\n raise StandardError.new(JSON.parse(response.to_s['message'])) if response.code != 200\n\n response.to_s\n end\nend\n\n```\n\n### 7. Putting things together\n\nOnce the above class is defined, let's put in a short code to perform all 3 steps to get the data.\n\n\n```ruby\nAPI_KEY = 'your_api_key'\nWIDGET_ID = 1234 # your widget\n\napi = HolisticsAPI.new(API_KEY)\n\njob_id = api.submit_report(WIDGET_ID)\nputs \"===> job_id: #{job_id}\"\n\njob_status = api.wait_for_job_status(job_id)\nputs \"===> job_status: #{job_status}\"\n\nif job_status == 'success'\n csv_data = api.download_export(job_id)\n puts csv_data # your CSV-formatted data here!\nend\n\n```\n\n### 7. Profit!\n\nSave the data into CSV, convert them into array, or feed them to other applications. The potentials are limitless!\n\n\n# Create Data Alerts using API\n\n## Introduction\n\n---\n\nIn Holistics, you can set up a system that sends you automatic notifications when data meets certain criteria, allowing you to make timely and strategic business decisions. This concept is called as **Data Alert.** \n\nHolistics offers a\_[set of public API endpoints](#tag/Data-Alerts)\_allowing clients to work with Data Alert. This tutorial shows you how to programmatically create these data alerts using the API.\n\n## The Use case\n\n---\n\nAssuming you are an e-commerce company that wants to track the number and status of orders placed on your platform. You can set up data alerts that trigger notifications when certain conditions are met, such as:\n\n1. **A number of orders placed in a specific time period exceed a certain threshold.**\n2. **A certain percentage of orders are canceled or marked as \"canceled\".**\n\nYou can receive these alerts through email or slack, and they can use this information to quickly respond to any issues or to make informed decisions about adjusting inventory or shipping processes.\n\nLet's walk through how we can create a data alert to **track your number of orders using Holistics API**.\n\n## High-level Approach\n\n---\n\nWe will use the API to create email data alerts. Specifically, we'll send a POST request to\_[Holistics create data alert API](#operation/DataAlerts_Create).\n\nBefore that, we need to prepare the following:\n\n- A dashboard widget with relevant report\n- Holistics API Key: We need to setup the API key. Refer to\_[this guide](#section/Authentication)\_for more info.\n\n## How to create a data alert via API\n\n---\n\n### Step **1. Preparing the dashboard widget**\n\nYou will need to create a dashboard widget containing the data of interest to you. In this example, I used this simple report that counts the total number of orders.\n\n![Untitled](https://cdn.holistics.io/docs/dashboards/dashboard.png)\n\n### Step 2: Making the API Call\n\nWe'll be using the following [endpoint](#tag/Data-Alerts/operation/DataAlerts_Create):\n\n```jsx\nPOST https://secure.holistics.io/api/v2/data_alerts\n```\n\nThere are some notable configuration options in this request:\n\n- `schedule`: Specify how frequently the email schedule should be\n- `viz_conditions`: Specify what alert condition should be check on the report result. By configuring this, we can customize the alert for each alerting use case.\n- `dest`: Specify configurations regarding the alert delivery destination, e.g. the recipients' information.\n- `dynamic_filter_presets`: Specify what dynamic filters should be applied to the report. By configuring this, we can customize the report for each recipient.\n\nBelow is a sample request body. Refer to\_[Holistics API docs](#tag/Data-Alerts/operation/DataAlerts_Create)\_for more information on these fields.\n\n![Untitled](https://cdn.holistics.io/docs/data-alert/samplereq.png)\n\n#### Dest field\n\n- `dest`: Specify configurations regarding recipients' information\n - `title`\_(string): Note that Holistics support\_[dynamic variables](https://docs.holistics.io/docs/delivery/email-schedules#dynamic-variables-support)\_in email title. For example, the title\_`Sales report for {{$today}}`\_sent on 29/09/2021 will be rendered as\_`Sales report for 2021-09-29 Wed`.\n - `type`: This tells Holistics you want to receive notification via email: `EmailDest` or Slack: `SlackDest`\n - If you choose `SlackDest`, you will need to [get the id and the name of your slack channel](https://help.socialintents.com/article/148-how-to-find-your-slack-team-id-and-slack-channel-id#:~:text=the%20Team%20ID.-,Open%20any%20web%20browser%20and%20log%20in%20to%20your%20Slack,represents%20your%20Slack%20Channel%20ID.) for the `slack_channels` field\n\n#### Viz conditions\n\n- `viz_conditions`: Coming to the core of the alert, the condition to set data alert\n - `field_path`: This is used to extract from a specific data model\n - `field_name`: field name of the field in the data model you want to apply the condition.\n - `model_id`: The id of the data model associated with the `field_name`\n - You can get the `field_name` and `model_id` by following these steps\n - From the widget id → [Get a dashboard widget](#tag/Dashboard-Widgets/operation/DashboardWidgets_Get) (include_report=true) then extract `query_report.viz_settings.fields`, you can find the field you want to add condition then extract path`_hash` to get `model_id` and `field_name`\n - `aggregation`: The aggregation that will be applied on the field when processing the condition.\n - `transformation`: The transformation that will be applied on the field when processing the condition.\n - `condition`: be applied on the Data Modeling layer to filter your data. Check out our document [here](#tag/Data-Modeling/DataModelingCondition) for more details.\n - Example: you have a field `id` and want to check whether the number of it is greater than 35000\n\n ```json\n {\n \"field_path\": {\n \"field_name\": \"id\",\n \"model_id\": 1\n },\n \"aggregation\": \"count\",\n \"transformation\": null,\n \"condition\": {\n \"operator\": \"greater_than\",\n \"modifier\": null,\n \"values\": [35000],\n },\n }\n\n ```\n\n\n#### Schedule\n\n`schedule`:\_This field is used to specify the schedule for your email schedule.\n\n`repeat`\_(string): You will need to input a\_[crontab expression](https://crontab.guru/) to let Holistics know how frequently you want your email schedule to run.\n\n#### Dashboard Filters\n\n`dynamic-filter-presets`\_is where you define your filter presets.\n\n`dynamic_filter_id`: To get your\_`filter_id`, send a request to\_[Dashboards#Get API](#operation/Dashboards_Get)\_to get the dashboard info.\n\n`preset_conditions`: Let's go through our example to better illustrate this field.\n\nWe want to set a value for the filter by setting a preset condition.\_**A preset condition consists of an operator and a list of values.**\_Holistics supports various operators and provides several examples\_[here](#tag/Data-Modeling/DataModelingCondition).\n\nIn this case, we want to use operator\_`is`\_and set values to\_`customer_id`. By this, we mean the filter's default value equals exactly to\_`customer_id`.\n\nFinally, we also want to set up another dynamic filter preset to filter data to the whole of last week. Fortunately, Holistics allows a list of dynamic filter presets. For the Date Range filter, we similarly want to use operator\_`is`\_and set values to\_`\"last 7 days\"`.\n\nOur final\_`dynamic_filter_presets`\_object will look like this.\n\n```js\ndynamic_filter_presets = [\n {\n \"dynamic_filter_id\": MY_CUSTOMER_FILTER_ID,\n \"preset_condition\": {\n \"operator\": \"is\",\n \"values\": [\n customer_id\n ]\n }\n },\n {\n \"dynamic_filter_id\": MY_DATE_RANGE_FILTER_ID,\n \"preset_condition\": {\n \"operator\": \"is\",\n \"values\": [\n \"last 7 days\"\n ]\n }\n }\n]\n\n```\n\n\n### **Step 3: Verify to see if your data alert is created[](https://docs.holistics.io/api/v2/create-data-schedule#step-3-double-check-to-see-if-your-email-schedule-is-created)**\n\nThe request should now be ready. After sending it to Holistics, the server will respond with a\_[HTTP status response code](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status)\_to indicate whether the request was successful / failed.\n\nLastly, be sure to head over to the Holistics page to see if your data alert is created.\n\n![Untitled](https://cdn.holistics.io/docs/data-alert/doublecheck.png)\n\n### **Example script[](https://docs.holistics.io/api/v2/create-data-schedule#example-script)**\n\n---\n\nAn example script to send requests written in Ruby is available here:\n\n```ruby\n# install the neccessary dependencies for this script to work\nrequire \"bundler/inline\"\nrequire \"net/http\"\nrequire \"json\"\n\ngemfile do\n source \"https://rubygems.org\"\n gem \"net-http\"\nend\n\n# this the Holisitics API endpoint that we need to send our POST request to\nDATA_ALERT_ENDPOINT = URI(\"https://secure.holistics.io/api/v2/data_alerts\")\n\n# Step 1: Create a POST request to the endpoint below\nrequest = Net::HTTP::Post.new(DATA_ALERT_ENDPOINT)\n\n# Step 2: Provide your authentication information\nrequest[\"X-Holistics-Key\"] = \"mysecretAPIkey\"\n\n# Step 2.1: This line helps the system know that we are sending a JSON request\nrequest.content_type = \"application/json\"\n\n# Step 3: Provide information for your data alert in the request body\nrequest.body = {\n \"data_alert\": {\n \"title\": \"Tracking number of orders\",\n \"source_id\": 41,\n \"source_type\": \"DashboardWidget\",\n # Conditions for the Alert to be Triggered\n \"viz_conditions\": [\n {\n \"field_path\": {\n \"field_name\": \"id\",\n \"model_id\": 12\n },\n \"aggregation\": \"count\",\n \"transformation\": null,\n \"condition\": {\n \"operator\": \"greater_than\",\n \"modifier\": null,\n \"values\": [35000]\n }\n }\n ],\n # Destination for the Alert\n \"dest\": {\n \"type\": \"EmailDest\",\n \"title\": \"The number of orders has just exceeded than 35000\",\n \"recipients\": [\n \"admin@domain.com\"\n ],\n \"options\": {\n \"body_text\": null\n }\n },\n # Schedule for the Alert to be Triggered\n \"schedule\": {\n # Repeat Everyday at 7:00 AM\n \"repeat\": \"0 7 * * *\",\n \"paused\": false\n },\n # Dynamic Filter Presets for the Alert\n \"dynamic_filter_presets\": [\n {\n \"preset_condition\": {\n \"operator\": \"is\",\n \"modifier\": null,\n \"values\": [\"VN\", \"SG\"],\n },\n \"dynamic_filter_id\": 1\n },\n {\n \"preset_condition\": {\n \"operator\": \"is\",\n \"modifier\": null,\n \"values\": [\n \"Male\"\n ],\n },\n \"dynamic_filter_id\": 2\n }\n ]\n }\n}.to_json\n\n# Step 4: Send the request to Holistics!\nresponse = Net::HTTP.start(\n DATA_ALERT_ENDPOINT.hostname,\n DATA_ALERT_ENDPOINT.port,\n :use_ssl => DATA_ALERT_ENDPOINT.scheme == \"https\",\n) do |https|\n https.request(request)\nend\n\n# Optional: Output the result into the terminal\nputs [response.code,response.message].join(' ')\n```\n\n# Create Email Schedules using API\n\n## Introduction\n\nIn Holistics, you can set up schedules sending reports or dashboards to a group of recipients via email, Slack, SFTP, or Azure Blob. This concept is called **Data Schedule**.\n\nHolistics offers a [set of public API endpoints](#tag/Data-Schedules) allowing clients to work with Data Schedule. This tutorial shows you how to use the API to create these data schedules programmatically.\n\n## The Use Case\n\nSuppose you are a B2B SaaS company that has a feature to email usage statistics to your customers every week. You want to set it up such that:\n\n- When a new customer onboards to your platform, you want **Holistics to send a weekly email report** to that customer.\n- The weekly email reports **should be customised to display information regarding the usage data of that customer only**\n\nLet's walk through how we can solve this problem using Holistics API.\n\n\n## High-level Approach\n\nWe will use the API to create email reports. Specifically, we'll send a POST request to [Holistics' create email schedule API](#operation/DataSchedules_Create).\n\nBefore that, we need to prepare the following:\n\n- A dashboard with relevant reports. This dashboard will be emailed to the customer.\n- The dashboard should have a \"Customer\" filter to filter down the data for a particular customer.\n- Holistics API Key: We need to setup the API key. Refer to [this guide](#section/Authentication) for info.\n\n## Step 1: Preparing the Dashboard\n\nYou will need to create a master dashboard that contains the reports you want to send to the customers. In this example, we have a `Customer Usage Data` dashboard which showcases the statistics of jobs that Holistics customers execute in our platform. We also have two filters in this dashboard, `Date Range` and `Customer`. \n\n- The **Customer ID filter** accepts a customer ID, then passes it to the report within the dashboard. The report then replaces the ID with its placeholder in a prepared SQL query, reruns the query, and fetches only data that belongs to that customer. In other words, this filter helps **filter down to the usage data of that customer only**.\n- Similarly, the **Date Range filter**'s value accepts `\"last 7 days\"`, `\"last 14 days\"`, `\"last 30 days\"`, or `\"any time\"`. This filter helps **filter usage data by a date range**. Note that this filter can be optional.\n\nIf you are not sure on how to create dashboards and filters, refer to [Dashboard Docs](https://docs.holistics.io/docs/dashboards).\n\n![](https://cdn.holistics.io/docs/guides/data-schedule-API/pic1.png)\n\n\n## Step 2: Making the API Call\n\nWe'll be using the following [endpoint](#operation/DataSchedules_Create):\n\n```jsx\nPOST https://secure.holistics.io/api/v2/data_schedules\n```\n\nThere are some notable configuration options in this request:\n\n- `schedule`: Specify how frequent the email schedule should be\n- `dynamic_filter_presets`: Specify what dynamic filters should be applied to the reports. By configuring this, we can customise the report for each recipient.\n- `dest`: Specify configurations regarding recipients' information.\n - Remember to set `dest.type` to \"EmailDest\"\n\nBelow is a sample request body. Refer to [Holistics API docs](#operation/DataSchedules_Create) for more information on these fields.\n\n![](https://cdn.holistics.io/docs/guides/data-schedule-API/samplereq.png)\n\n> ⓘ **INFO**\n>\n> 💡 Most of the fields are straightforward which means that you can fill them out by reading our API docs. Refer to this section below for notes on trickier fields.\n\n\n### Common fields\n\n- `id` (integer): This is used to uniquely identified your object. Holistics automatically generates an id for you if you don't specify this.\n- `source_id` (integer): This tells Holistics which dashboard you want to send email to. To determine this value, view your dashboard link. For example, the link [`https://secure.holistics.io/dashboards/v3/16076-demo-my-beautiful-dashboard`](https://secure.holistics.io/dashboards/v3/16076-demo-my-beautiful-dashboard) will have the `source_id` of 16076.\n- `dest`: Specify the information regarding the recipients\n - `title` (string): Note that Holistics support [dynamic variables](https://docs.holistics.io/docs/delivery/email-schedules#dynamic-variables-support) in email title. For example, the title `Sales report for {{$today}}` sent on 29/09/2021 will be rendered as `Sales report for 2021-09-29 Wed`.\n\n### Schedule frequency\n\n`schedule` is used to specify the schedule for your email schedule.\n\n`repeat` (string): You will need to input a `crontab expression` here to let Holistics how frequent you want to your email schedule to run. \n\n### Dynamic filter values\n\n`dynamic-filter-presets` is where you define your filter presets here. \n\n`dynamic_filter_id` (integer): To get your `filter_id`, send a GET request to [Dashboards#Get API](#operation/Dashboards_Get) to get the dashboard info.\n\n`preset_conditions` (object): Let's go through our example to better illustrate this field.\n\nWe want to set a value for the filter by setting a preset condition. **A preset condition consists of an operator and a list of values.** Holistics supports various operators and provides several examples [here](#tag/Data-Modeling/DataModelingCondition).\n\nIn this case, we want to use operator `is` and set values to `customer_id`. By this, we mean the filter's default value equals exactly to `customer_id`.\n\nFinally, we also want to set up another dynamic filter preset to filter data to the whole of last week. Fortunately, Holistics allows a list of dynamic filter presets. For the Date Range filter, we similarly want to use operator `is` and set values to `\"last 7 days\"`.\n\nOur final `dynamic_filter_presets` object will look like this.\n\n```json\ndynamic_filter_presets = [\n {\n \"dynamic_filter_id\": MY_CUSTOMER_FILTER_ID,\n \"preset_condition\": {\n \"operator\": \"is\",\n \"values\": [\n customer_id\n ]\n }\n },\n\t{\n \"dynamic_filter_id\": MY_DATE_RANGE_FILTER_ID,\n \"preset_condition\": {\n \"operator\": \"is\",\n \"values\": [\n \"last 7 days\"\n ]\n }\n }\n]\n```\n\n## Step 3: Double-check to see if your email schedule is created\n\nThe request should now be ready. After sending it to Holistics, the server will respond with a [HTTP status response code](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status) to indicate whether the request was successful / failed. \n\nLastly, be sure to head over to Holistics page to see if your email schedule is created.\n\n![](https://cdn.holistics.io/docs/guides/data-schedule-API/double-check.png)\n\n## Example script \n\nAn example script to send requests written in Ruby is available here:\n\n```ruby\n# install the neccessary dependencies for this script to work\nrequire \"bundler/inline\"\nrequire \"net/http\"\nrequire \"json\"\n\ngemfile do\n source \"https://rubygems.org\"\n gem \"net-http\"\nend\n\n# this the Holisitics API endpoint that we need to send our POST request to\nEMAIL_SCHEDULE_ENDPOINT = URI(\"https://secure.holistics.io/api/v2/data_schedules\")\n\n# Step 1: Create a POST request to the endpoint below\nrequest = Net::HTTP::Post.new(EMAIL_SCHEDULE_ENDPOINT)\n\n# Step 2: Provide your authentication information \nrequest[\"X-Holistics-Key\"] = \"mysecretAPIkey\"\n\n# Step 2.1: This line helps the system know that we are sending a JSON request\nrequest.content_type = \"application/json\"\n\n# Step 3: Provide information for your email schedule in the request body\nrequest.body =\n {\n \"data_schedule\": {\n \"source_type\": \"Dashboard\",\n \"source_id\": 16076,\n \"schedule\": {\n \"repeat\": \"* * * * *\",\n \"paused\": false,\n },\n \"dest\": {\n \"type\": \"EmailDest\",\n \"title\": \"Sale report for {{$today}}\",\n \"recipients\": [\n \"abc@gmail.com\",\n ],\n },\n },\n }.to_json\n\n# Step 4: Send the request to Holistics!\nresponse = Net::HTTP.start(\n EMAIL_SCHEDULE_ENDPOINT.hostname,\n EMAIL_SCHEDULE_ENDPOINT.port,\n :use_ssl => EMAIL_SCHEDULE_ENDPOINT.scheme == \"https\",\n) do |https|\n https.request(request)\nend\n\n# Optional: Output the result into the terminal\nputs [response.code,response.message].join(' ')\n```\n\n# Holistics CLI\n\n>💡 **NOTE**\n>\n> The current Holistics CLI version is: 0.4.0.\n>\n> Requirements:\n> - Ruby 2.7\n\nHolistics CLI is an interface to Holistics Data Preparation module (like data transport, data transform, import). \n\n\n## Setting Up\n\n### Linux/Mac OSX\nIf you are using Linux/Mac OSX, we suggest you install Ruby with a **Ruby Version Manager** such as [rbenv](https://github.com/rbenv/rbenv) or [asdf](https://asdf-vm.com/guide/getting-started.html). \n\nPlease follow the instructions in your RVM of choice to **install Ruby 2.7.4**:\n- rbenv: https://github.com/rbenv/rbenv#installation. \n- asdf: https://asdf-vm.com/guide/getting-started.html.\n\nAfter you have Ruby installed on your computer, run:\n\n```bash\ngem install holistics -v 0.4.0\n```\n\n### Windows\nIf you are using Windows, head over to: [Official Ruby Download Page](https://rubyinstaller.org/downloads).\n\nAnd download Ruby 2.7.4 installer. Remember to select the `Devkit` option for your installer so that you \ncan run the `gem install` command in the next step from your command line. \n\nAfter you have Ruby installed on your computer, run:\n\n```bash\ngem install holistics -v 0.4.0\n```\n\n## Authentication (done once)\n\nThe next step is authentication. You first need to be granted permissions to have an API authentication token. If you are not sure how, visit: [API Authentication](#section/Authentication).\n\n\nAssuming that the above step is successful, you can access your token by going to ⚙️\nMy Account -> API Key. After that, run this in your command line to authenticate yourself.\n\n```\n$ holistics login \nAuthenticating token...\nAuthentication successful. Info:\n- ID: 1\n- Email: admin@you.com\n```\n\n> ⓘ **IMPORTANT - INVALID AUTHENTICATION TOKEN ERROR**\n>\n> By default, the CLI connects to the Asia-Pacific servers. If your account is in another server (EU or US), you will have to specify the `HOLISTICS_HOST` > environment variable in your authentication command.\n>\n> 👉 If you are not sure what server you are on, please follow [this guide](https://docs.holistics.io/docs/data-centers#how-do-i-know-which-data-center-im-on) to find out.\n>\n> Assuming you are in EU server (https://eu.holistics.io), the command will now become:\n>\n> ```bash\n> HOLISTICS_HOST=https://eu.holistics.io holistics login\n> ```\n>\n> You will need to prepend every command with `HOLISTICS_HOST=https://eu.holistics.io`.\n>\n> Alternatively, specify it only once as a **global variable** by running:\n>\n> ```bash\n> export HOLISTICS_HOST=https://eu.holistics.io\n> ```\n>\n> And you can run the commands without prepending the host everytime.\n\n\n## CLI Commands\n\n### Help Command\n\nFor general help or a list of command, run:\n\n```\n$ holistics help\n```\nHere is a list of some Holistics CLI commands you can run:\n[![Holistics CLI commands](https://cdn.holistics.io/docs-images/cli-commands.png)](https://cdn.holistics.io/docs-images/cli-commands.png)\n\n# Migrate API V1 to V2\n\n## Introduction\nThis documentation will guide you through the process of transitioning from API V1 to the new API V2. It will also provide information about the migration plan and outline what you can expect in our new API version. Our primary goal is to assist you in achieving a smooth and successful transition to Holistics’s latest API version.\n\n## Why it is time to move to API V2\nFor the past few months, we have considered API V1 as our legacy API. While it is still functional, it is not actively maintained. Meanwhile, we have been developing API V2 as a more powerful, flexible, and well-structured version of V1.\n\nNow that API V2 has surpassed its predecessor in both functionality and experience, we are deprecating V1 and are here to assist you in migrating your applications to V2.\n\n## Our deprecation plan for API V1\n\n> ⓘ **INFO**\n>\n> The entire API V1 will cease to function by **November 20th, 2023**.\n\nThis deprecation includes all functionalities available in these two V1 kits:\n\n- [Users API](https://docs.holistics.io/api/v1/user-api)\n- [Group API](https://docs.holistics.io/api/v1/group-api)\n\nBe assured that we have supported all of these functionalities API in V2.\n\nNext steps, you will need to manually update your applications that are utilizing V1 to switch them to V2.\n\n## Equivalent functions between API V1 & API V2\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
API V1API V2Changes
[User] Get all users in a tenant with full informationGET - List users\n
    \n
  • Groups are in a different list, not included in each user
  • \n
  • V2 applies pagination, you have to query page by page
  • \n
  • V2 has user counter information
  • \n
\n
[User] Invite a new user to HolisticsPOST - Invite Multiple UsersV2 allows inviting multiple emails with additional user settings, including API usage, group IDs, and data export permissions
[User] Resend invitation to userPOST - Resend invitation to user\n
    \n
  • We introduced inviting multiple users API in API V2
  • \n
  • In order to make invite multiple users and resend invitation user consistent, we return the job info of created job
  • \n
\n
[User] Soft-delete a userDEL - Delete a user
[User] Restore a deleted userPOST - Restore a deleted user
[User] Allow/ Revoke a user's API accessPUT - Update userBy setting attribute: allow_authentication_token: boolean
[User] Revoke Authentication Token from a user

PUT - Update user (Upcoming)

\n
[User] Check whether email address is already used for a user in HolisticsGET - Check whether an email address is already used for a user in your Holistics workspace
[User] Change user role in HolisticsPUT - Update userBy setting attribute: “role”: enum remove_groups: passing empty group_ids
[Group] Get all groups in a tenantGET - List Groups\n
    \n
  • V2 applies pagination, you have to query page by page
  • \n
  • V2 includes all users’s id instead of num_user in V1
  • \n
  • V2 supports include_users
  • \n
\n
[Group] Create a new groupPOST - Create GroupResponse’s structure change
[Group] Update information of an existing groupPUT - Update a GroupNow included user_ids in groups
[Group] Delete an existing groupDEL - Delete a Group
[Group] Add a user into a groupPOST - Add User to Group
[Group] Remove a user from a groupPOST - Remove User from Group
\n\n\n## FAQ\n### How will the migration affect existing applications that are utilizing API V1?\n- We expect no interference in your automation workflow after the migration since all functionalities of V1 are completely covered by V2\n- However, since there will be some differences in the data schema (or response structure) between the two versions, you would need to follow our documents to set up precisely\n\n### Should I do anything prior to this migration?\nWe suggest you check which applications will be affected by such an update, and inform your team that they will not be available during that time.\n\n### What do I do if I encounter unexpected issues?\nWe are committed to providing support throughout the migration. If you encounter any problems, please reach out to us at\_support@holistics.io\_for assistance.\n" - name: Jobs description: >- Async (asynchronous) operations are operations that are executed within a background Job. If an API endpoint triggers an async operation, it will return an AsyncResult response containing the background Job info. You can use the bellow APIs to poll for the updated Job status. - name: AML Studio description: AML Studio APIs - name: Dashboards description: Reporting Dashboards - name: Dashboard Widgets description: Reporting Dashboard Widgets - name: Data Schedules description: Data delivery using automated schedules - name: Data Alerts description: >- Send automatic notification to you and your team when the data meets certain conditions - name: Exports - name: Data Modeling description: >- ## DataModelingCondition Condition that can be applied on the Data Modeling layer to filter your data. See the examples in the Example panel. - name: Dependencies description: >- ## Downstream dependencies Get ids of objects which are dependent on the object you input. The response schema varies based on the input type and its current dependants. - name: Users description: Users management - name: Groups description: Groups management - name: Data Model Persistences x-holistics-internal: true description: Data Model Persistences - name: Embed description: Embedded Analytics