Datarails FinanceOS
Datarails FinanceOS brings structure and intelligence to your financial data. It provides a managed, organized database that keeps your numbers clean and reliable. Every change is fully traced with a built-in audit trail, so you always know who changed what and when. A robust permission mechanism ensures each user sees only the data they're authorized to access. And with built-in financial logic, the app understands your business context out of the box - no manual setup required.
- Integration type
- Plugin
- Verification status
- Not applicable
- Platform
- ChatGPT
- Primary Subcategory
- Financial Planning & FP&A Analytics
- Secondary Subcategories
- None listed
- Brand
- Datarails
- Access
- Account required
- First tracked
- 2026-05-20
- Tool count
- 32
- Geography
- US
The Primary Subcategory used for this profile’s headline score.
Other Subcategories where the Integration is visible.
ChatGPT Plugin Discoverability Score
ChatGPT organic discovery is not live yet
Datarails FinanceOS is tracked in the ChatGPT Plugin registry. Public organic-discovery measurement is not live for ChatGPT yet, so there is no score to publish today.
Get notified when your score goes live
Enter your work email and we’ll notify you when ChatGPT Plugin organic discovery scoring launches.
No spam. Unsubscribe any time.
Competing in ChatGPT Financial Planning & FP&A Analytics
View CategoryHow the Discoverability Score works
Organic discovery scoring for Datarails FinanceOS on ChatGPT is not live yet. The score will use measured agent conversations when it launches.
Organic discovery scoring is pending. Your Plugin score will appear on this scale when measurement goes live.
FoundDiagnostic
Whether Claude found your Plugin in connector search. It must be Found before it can reach the picker, but the score counts picker appearances—not search results.
PickedMain score
How often your Plugin appeared in the picker, or Claude invoked it directly, across contested conversations. This percentage is the Discoverability Score; the headline number is rounded.
PositionedDiagnostic
What position your Plugin appeared in when it was shown in the picker. This shows prominence, but it does not affect the score.
32 tools agents can invoke
Chat with a Datarails specialized agent. This opens a SUB-CONVERSATION: you are a relay between the user and that agent, not the one answering. START: pass agent_name (or agent_id) and the user's prompt, leave session_id empty. The result includes a session_id. Use list_specialized_agents first to pick an agent. (Advanced: environment_id targets a specific agent runtime; omit to use the default.) STAY IN THE SESSION (important): once you have a session_id, treat every following user message as part of THIS sub-conversation — call this tool again with the SAME session_id and the user's message passed through faithfully (don't answer it yourself, don't summarize or rewrite it). Relay the agent's reply back to the user verbatim. If the agent asks a question, show it to the user and send their answer back with the same session_id. Keep relaying turn after turn. LEAVE THE SESSION: there is no close call — simply stop using that session_id once the user clearly wants to stop, switch to a different agent, or do something unrelated. Starting a new conversation (no session_id) or a different agent ends the relay. FILES IN: to give the agent a file (incl. images), first call upload_file(filename), PUT the bytes, then pass the returned filename in 'files', e.g. files=[{filename}]. Do NOT call upload_file unless you are attaching a file this turn. Files mount into the agent's sandbox on start and on any follow-up. FILES OUT: if a result includes a 'files' array, the agent produced files — each has a filename (no link). To share or open one, call download_file(filename) for a time-limited URL. Don't download a file unless the user wants it.
Get a fresh, time-limited download URL for a file by its filename — either a file a specialized agent generated (a filename in a chat_with_specialized_agent result's 'files') or one you uploaded with upload_file. Returns {filename, mime_type, url, expires_at}. Call this ONLY when the user actually wants the file (to open or share it) — don't pre-fetch. The name must be one returned to you this session; arbitrary names are rejected.
Fetch (or poll for) the result of a start_aggregation_by_alias job. Single non-blocking check. Given the handle from start_aggregation_by_alias, returns either the aggregated rows or {"status": "running", "handle": {...}, "retry_after_seconds": N} — call again with the SAME handle after ~N seconds. Args: handle: The handle from start_aggregation_by_alias (request_token + alias). Pass it back unchanged. Unknown/expired handle returns an error — restart with start_aggregation_by_alias. Note: large results are capped to a response-size limit. If capped, the result comes back as {"data": ..., "truncated": true, "total_rows": N, "returned_rows": M, "guidance": ...} instead of the bare rows — narrow the query (fewer columns/dimensions, add filters, or use a business metric for a named KPI) and call again to get the rows you need.
Fetch (or poll for) the result of a start_aggregation_by_id job. Does a single check — it does not block. Given the handle from start_aggregation_by_id, it returns one of: * the aggregated rows (job complete), OR * {"status": "running", "handle": {...}, "retry_after_seconds": N} — still processing; call this tool again with the SAME handle after ~N seconds. Args: handle: The handle object returned by start_aggregation_by_id (contains request_token and table_id). Pass it back unchanged. If the handle is unknown or expired, an error is returned — restart with start_aggregation_by_id. Note: large results are capped to a response-size limit. If capped, the result comes back as {"data": ..., "truncated": true, "total_rows": N, "returned_rows": M, "guidance": ...} instead of the bare rows — narrow the query (fewer columns/dimensions, add filters, or use a business metric for a named KPI) and call again to get the rows you need.
Get server-computed metric time-series data. NO MANUAL AGGREGATION NEEDED. This is the preferred way to get KPI values over time. The server computes the metric (including CALC ratios like Debt to Assets) and returns time-series data — eliminating the need for Claude to manually aggregate and calculate. Args: metric_ids: List of metric IDs (from list_business_metrics). Supports multiple metrics in one call. scenario: Optional list of scenario values (e.g., ["Actuals"] or ["Budget", "Forecast"]). Omit to include all scenarios. scenario_cycle: Optional list of planning cycle (version) values within Budget/Forecast scenarios. Omit to aggregate across all cycles. Only meaningful with scenario including "Budget" or "Forecast". planning_scenario: Optional list of planning scenario values. Omit to include all planning scenarios. scenario_details: Optional list of scenario detail values. Omit to include all scenario details. aggregation_period: "day" | "month" | "quarter" | "year" (default: month) aggregation_type: "DEFAULT" | "MTD" | "QTD" | "YTD" date_start: Optional start date "YYYY-MM-DD" date_end: Optional end date "YYYY-MM-DD" dimension_filters: Optional dict like {"Department": ["Sales"]} Returns list of {date, amount} points per metric. An empty series for a metric (status:"success", data:[]) usually means an errored/unmapped source or a range that matched zero rows. For best results call list_business_metrics first and skip metrics whose status_info sets error_message or source_warning.
Get full detail for a specific business metric including calculation config. Args: metric_id: The metric ID (from list_business_metrics) Returns: - template_id: which table the metric reads from - aggregator: how values are combined (SUM, AVG, etc.) - date_field_id, value_field_id: which fields to aggregate - base_metrics: for CALC metrics, the component metric IDs - configuration: formula details (for calculated metrics like ratios)
Drill into a business metric — return the source rows behind its values, with per-field metadata. Args: metric_ids: List of metric IDs (max 50) dimension_filters: Optional pre-filter ({dimension_name: [values]}) date_start: Optional start date (YYYY-MM-DD) date_end: Optional end date (YYYY-MM-DD) Notes: - BASE metrics: returns drill-down rows for that metric's underlying records. - CALC metrics: returns drill-downs for each component base metric (e.g. drilling into "Gross Profit" yields drill-downs for "Revenue" and "COGS"). - Slow — can take 30+ seconds per metric. - The raw payload can be very large; request narrow metric_ids and date ranges. Empty data for a metric usually means it is errored (check its status_info.error_message / status_info.source_warning).
Stream the source rows that back a single business metric — the underlying detail or aggregated rows used to compute it. Returns a flat array of row objects for ONE metric (not the standard success/data envelope). Narrow the rows with scenario, dimension_filters, and a date range. Args: metric_id: The metric ID (from list_business_metrics). One metric. scenario: Optional list of scenario names to filter on (e.g. ["Actuals"] or ["Budget", "Forecast"]). Omit for the default scenario. dimension_filters: Optional {dimension_name: [values]} — values are OR'd within a dimension and AND'd across dimensions; keys must match a dimension declared on the metric. date_start: Optional inclusive lower-bound date "YYYY-MM-DD". date_end: Optional inclusive upper-bound date "YYYY-MM-DD". aggregation_period: "day" | "month" | "quarter" | "year" (default: day). CALC metrics only — BASE metrics always return raw detail rows and ignore this. aggregation_type: "DEFAULT" | "MTD" | "QTD" | "YTD" (default: DEFAULT). CALC metrics only; ignored for BASE metrics. Result sets can be large — narrow with date ranges and filters. Note: large results are capped to a response-size limit. If capped, the result comes back as {"data": ..., "truncated": true, "total_rows": N, "returned_rows": M, "guidance": ...} instead of the bare rows — narrow the query (fewer columns/dimensions, add filters, or use a business metric for a named KPI) and call again to get the rows you need.
Report whether this Datarails connector is enabled for your organization. Always available; call this if other tools are missing or a Datarails action fails with connector_not_enabled.
FX rates snapshot (USD base). Single point in time, no history. Thin wrapper over `/foreign_exchange/v1/currency-rates`. The backend returns the most-recent rate set the org has loaded — there is no period/date parameter. The response includes a `date` field indicating when the snapshot was captured; the snapshot may lag wall-clock time depending on how the org keeps its rate table up to date. Currency coverage varies by org (the rate set only includes currencies the org has actually loaded — not a fixed global list). Inspect the response before assuming a given ISO code is present. For historical or period-specific FX, this endpoint is not suitable.
Get rows from an aliased table (addressed by alias) with optional column selection. KEY ADVANTAGE: Use `select` to return ONLY the columns you need. A typical table has 228 columns — selecting 5 reduces tokens by ~95%. Args: alias: Table alias (e.g., 'ap', 'bank_transactions') select: List of field aliases to return (e.g., ['amount', 'payment_status']). If None, returns all columns (not recommended). filters: Optional list of {name, values, is_excluded?} objects addressed by field alias, where values takes one of two forms: * Value list — match any of the listed values (set membership / IN): {"name": "payment_status", "values": ["Paid", "Pending"]} Set is_excluded: true to exclude the listed values (NOT IN). * Advanced — a condition tree for comparisons, ranges, and text matching: {"name": "amount", "values": {"type": "advanced", "val": [ {"condition": "gte", "value": "1000"}, {"condition": "lt", "value": "5000", "operator": "and"} ]}} Each val entry is {condition, value, operator?}: - condition: equals, dn_equals (does not equal), contains, dn_contains, bw (begins with), ew (ends with), gt, gte, lt, lte, in, range (exclusive between), total_range (inclusive between), is null. - value: a string for scalar conditions; a list of strings for in; a two-item [from, to] list of strings for range and total_range. Numbers/dates are passed as strings (e.g. epoch "1750000000"); the backend casts per field. For is null, set value to "" (it is ignored downstream). - operator: how this condition chains with the previous one, 'and' (default) or 'or' to start an alternative branch. is_excluded applies to value lists only, not advanced filters. limit: Max rows (default 100, max 500) offset: Rows to skip for pagination (default 0) ALWAYS use `select` to minimize token usage. Use field aliases (from list_aliased_fields), not raw field names. Note: large results are capped to a response-size limit. If capped, the result comes back as {"data": ..., "truncated": true, "total_rows": N, "returned_rows": M, "guidance": ...} instead of the bare rows — narrow the query (fewer columns/dimensions, add filters, or use a business metric for a named KPI) and call again to get the rows you need.
Get rows from a table (addressed by id) with optional column selection. Fetches raw rows — use for row-level inspection or when the user wants specific records. For totals/grouped breakdowns use get_aggregated_data_by_id (no row limit); for named KPIs check list_business_metrics first. Args: table_id: The id of the table (from list_data_models). select: List of field ids to return (e.g. [101, 103], from get_fields_by_id). Raw tables are wide (~200 columns); project to the few you need. Omit to return all columns (not recommended). filters: Optional list of {field_id, values, is_excluded?} objects, addressed by numeric field id (from get_fields_by_id), where values takes one of two forms: * Value list — match any of the listed values (set membership / IN): {"field_id": 104, "values": ["Actuals", "Budget"]} Set is_excluded: true to exclude the listed values (NOT IN). * Advanced — a condition tree for comparisons, ranges, and text matching: {"field_id": 105, "values": {"type": "advanced", "val": [ {"condition": "gte", "value": "1000"}, {"condition": "lt", "value": "5000", "operator": "and"} ]}} Each val entry is {condition, value, operator?}: - condition: equals, dn_equals (does not equal), contains, dn_contains, bw (begins with), ew (ends with), gt, gte, lt, lte, in, range (exclusive between), total_range (inclusive between), is null. - value: a string for scalar conditions; a list of strings for in; a two-item [from, to] list of strings for range and total_range. Numbers/dates are passed as strings (e.g. epoch "1750000000"); the backend casts per field. For is null, set value to "" (it is ignored downstream). - operator: how this condition chains with the previous one, 'and' (default) or 'or' to start an alternative branch. is_excluded applies to value lists only, not advanced filters. limit: Max rows (default 100, max 500). offset: Rows to skip for pagination (default 0). Note: large results are capped to a response-size limit. If capped, the result comes back as {"data": ..., "truncated": true, "total_rows": N, "returned_rows": M, "guidance": ...} instead of the bare rows — narrow the query (fewer columns/dimensions, add filters, or use a business metric for a named KPI) and call again to get the rows you need.
Fetch (or poll for) the result of a start_distinct_values_by_alias job. Single non-blocking check. Given the handle from start_distinct_values_by_alias, returns either the sorted list of distinct values or {"status": "running", "handle": {...}, "retry_after_seconds": N} — call again with the SAME handle after ~N seconds. Args: handle: The handle from start_distinct_values_by_alias (request_token, alias, field_alias). Pass it back unchanged. limit: Max number of values to return (default 100).
Fetch (or poll for) the result of a start_distinct_values_by_id job. Single non-blocking check. Given the handle from start_distinct_values_by_id, returns either the sorted list of distinct values or {"status": "running", "handle": {...}, "retry_after_seconds": N} — call again with the SAME handle after ~N seconds. Args: handle: The handle from start_distinct_values_by_id (request_token, table_id, field_id). Pass it back unchanged. limit: Max number of values to return (default 100).
Get the fields (columns) of a table, addressed by id. Args: table_id: The id of the table (from list_data_models). Returns the table's name and alias plus, for each field: id (numeric field id, used by the by-id tools), alias (business-friendly name, empty if none), name, type, and description.
Get users in the organization with roles and departments. Default returns ~9 KB (50 users) flattened to: - id, first_name, last_name, email, is_active - role (ADMIN, CONTRIBUTOR, VIEWER, SUPER_ADMIN) - department (FINANCE_FPA, SALES, R&D, etc.) - job_role (VP, DIRECTOR, BOARD_MEMBER, etc.) Useful for understanding org structure and tailoring responses. Args: include_full: When True, returns the raw envelope (~60 KB) including permission_groups, telemetry, badge info.
IMPORTANT: This tool MUST be called at the START of every new conversation, before any other tool. It returns the catalog of all available skills, agents, and workflows on this server. Use the catalog to understand what capabilities are available. When a user's request matches a skill, call `load_skills_and_md_files` with the skill's path to retrieve the full instructions for executing it. Returns JSON with: - skills: list of available skills with their paths and metadata - directory_tree: the full plugin content directory structure
Get guided workflows for common financial analysis tasks. Call without arguments to see all available workflows. Call with a workflow name to get step-by-step guidance. Use this tool when: - A user is new and wants to know what they can do - A user asks for help or says "what can you do?" - You need guidance on which tools to use for a specific task - A user wants a financial summary, expense analysis, revenue trends, etc. Args: workflow_name: Optional. One of: getting-started, financial-summary, expense-analysis, revenue-trends, budget-comparison, data-quality, explore-data, api-test
List the fields of an aliased table, with aliases and descriptions. Args: alias: Table alias (e.g., 'financials', 'ap', 'trial_balance') Returns field information including: - alias: business-friendly name for the field - name: original raw field name - type: data type - description: what this field means in business context PREFER this over get_fields_by_id when an alias is available — it gives business context.
Start here for any named-KPI question (revenue, margin, expenses, budget variance, headcount, ratios). Returns the org's defined metrics with business context, status, dimensions, and formulas — so you can pick the right metric and call `get_business_metric_data` instead of manually aggregating raw tables. Returns a flat list. Each metric contains: - id, name, description, category, kind (USER/BASE/CALC) - time_aggregation (how the metric rolls up over time), format - dimensions[]: which fields the metric can be sliced by - status_info: { status, source_warning?, error_message?, last_updated } Use `status_info` to triage: a non-empty `error_message` flags a broken metric, and a `source_warning` flags source tables that aren't configured/mapped or only partially loaded (so get_business_metric_data may return 0 rows or incomplete data). Note: `status_info` is a triage hint, not a contract with the data endpoint. Some metrics with an `error_message` still return values from `get_business_metric_data`, and some clean ones come back empty — verify by calling `get_business_metric_data` when in doubt. Best starting point for understanding what KPIs the org tracks.
List all data models (tables) available to the caller — with or without an alias. For named-KPI questions (revenue, margin, expenses, budget variance, headcount, ratios), prefer `list_business_metrics` first — the metric catalog typically answers them directly. Use this tool for raw-data exploration or when no metric covers the question. Each entry carries both identities: the numeric id used by the by-id (raw) endpoints and the alias used by the by-alias endpoints (empty when a table has no alias). Tables with an alias also offer human-readable field aliases and descriptions — prefer the by-alias tools for those. Args: name: Optional table name (case-insensitive exact match) for a cheap single-table lookup. Empty array if nothing matches. alias: Optional alias (e.g., "financials", "ap") — same filter, matched against the table's alias. has_alias: Optional — true returns only tables that have an alias. Without filters, returns every table. Pair with get_fields_by_id(id) or list_aliased_fields(alias) for the field list.
List filebox items (folders, files, templates, lookup tables) in the org. Useful for discovering org-level content structure — top-level folders like "Actuals", "Reports", "Configuration", "Analysis". Each item has a `parent` (parent id or null), so the tree can be reconstructed. Args: include_full: When True, also returns permissions[], tags_config, bucket — about 8× larger (~280 KB). Default trim returns ~36 KB (199 items: id, parent, name, is_folder, scenario, use_type, is_process_root).
List the Datarails specialized agents you can talk to. Returns each agent's id, name, and description. Use this to discover which agent to pass to chat_with_specialized_agent.
List the XL functions visible to the calling user. XL functions are the named aggregations that Excel DR.GET formulas reference as their first argument: `=DR.GET(<FunctionName>, "[Dimension]", CellRef, ...)`. Never guess or hardcode a function name — always discover it here. Each entry carries: - `name`: the exact token to use as DR.GET's first argument - `template`: the owning table `{id, name}` — pass `template.id` to `get_fields_by_id` to learn which dimension fields are valid in the formula's `"[Dimension]"` pairs - `vals` / `aggfun`: the value field(s) being aggregated and how - `default_agg_datefield`: id of the date field used for default time aggregation (resolve to a name via `get_fields_by_id`) Validate dimension values with `get_distinct_values_by_id` before writing them into a workbook. Args: include_archived: Include archived functions (default False — archived functions can't be used in new formulas). include_full: Return raw records including authorship metadata (default False trims `last_edited_by`).
Load skill and workflow instructions by their relative paths. Call this tool immediately whenever the user's request matches a skill from the plugin catalog. Do not wait for the user to ask for it — as soon as you identify the right skill, load it and follow its instructions. The loaded content contains step-by-step execution guides that tell you which tools to call and in what order. Args: paths: List of relative paths from the plugin root directory. Example: ["skills/intelligence/SKILL.md", "agents/finance-analyst.md", "CLAUDE.md"] Returns JSON mapping each requested path to its full text content, or null if the file was not found.
Distinct-value sample per categorical field. Capped at 5 fields. Thin wrapper that calls `/tables/v1/{id}/fields/by-name/{field}/distinct` in parallel for up to 5 fields. Returns `{field: {distinct_count, sample_values}}` where `sample_values` is capped at the first 10 distinct values. Does NOT compute: per-value frequency counts, null counts/percentages, uniqueness ratios. Fields beyond the 5-field cap are silently dropped — pass an explicit `fields` list if you need a specific selection. For frequency analysis, call `get_aggregated_data_by_id` with the field as a dimension and `COUNT` as the metric. Args: table_id: The ID of the table to profile fields: Optional list of specific fields. If None, the first 5 fields the backend classifies as categorical are profiled.
Basic numeric stats: SUM, AVG, MIN, MAX, COUNT per field. Thin wrapper over `/tables/v1/{id}/aggregate`. Returns the backend's native aggregate response shape (column-oriented `DR_Values` / `col_keys` / `row_keys` layout); aggregator names are encoded in the column keys rather than as named result fields. Does NOT compute: median, standard deviation, outliers, percentiles, null counts. For richer distributional analysis use the `datarails-financeos:profile` skill (Claude only) or call this tool and post-process the rows. Args: table_id: The ID of the table to profile fields: Optional list of specific fields to profile. If None, all fields the backend classifies as numeric are profiled.
Start a server-computed aggregation over an aliased table WITHOUT blocking. The by-alias twin of start_aggregation_by_id. Use instead of get_aggregated_data_by_alias for large aggregations. Kicks off the job and returns a handle immediately; it does NOT return data. Args (identical to get_aggregated_data_by_alias): alias: Table alias (e.g. 'ap', 'bank_transactions', 'trial_balance'). dimensions: List of field aliases to group by. metrics: List of {field, agg} specs, e.g. [{"field": "amount", "agg": "SUM"}]. filters: Optional list of {name, values, is_excluded?} objects. Returns {"status": "pending", "handle": {...}, "guidance": ...}. Pass the handle unchanged to get_aggregation_result_by_alias.
Start a server-computed aggregation over a table (by id) WITHOUT blocking. Use this instead of get_aggregated_data_by_id for large aggregations that would otherwise exceed the request timeout. It kicks off the job and returns immediately with a handle; it does NOT return data. Args (identical to get_aggregated_data_by_id): table_id: The id of the table to aggregate. dimensions: List of field ids to group by (e.g. [101, 102]). metrics: List of {field_id, agg} specs, e.g. [{"field_id": 103, "agg": "SUM"}]. filters: Optional list of {field_id, values, is_excluded?} objects (value-list or advanced grammar), same as get_aggregated_data_by_id. Returns {"status": "pending", "handle": {...}, "guidance": ...}. Pass the handle unchanged to get_aggregation_result_by_id, then poll until it returns the result.
Start a distinct-values lookup for an aliased field WITHOUT blocking. The non-blocking twin of get_distinct_values_by_alias. Returns a handle immediately. Args: alias: Table alias. field_alias: Field alias (from list_aliased_fields). Returns {"status": "pending", "handle": {...}, "guidance": ...}. Pass the handle unchanged to get_distinct_values_result_by_alias.
Start a distinct-values lookup for a table field (by id) WITHOUT blocking. The non-blocking twin of get_distinct_values_by_id. Kicks off the job and returns a handle immediately. Args: table_id: The id of the table (from list_data_models). field_id: The numeric field id (from get_fields_by_id). Returns {"status": "pending", "handle": {...}, "guidance": ...}. Pass the handle unchanged to get_distinct_values_result_by_id.
Upload a file to storage and get back its stored filename, without putting the file's bytes through your context. Call this ONLY when you need to attach a file to a managed agent this turn — don't upload speculatively. Steps: 1. Call this with the file's name → returns {upload_url, filename, expires_at, max_size_bytes}. 2. Upload the raw file bytes with an HTTP PUT to upload_url, e.g. `curl -X PUT -T <path-to-file> "<upload_url>"` (do NOT read the file into your context or base64-encode it — PUT it directly). 3. Call chat_with_specialized_agent with files=[{filename}] to attach it. The upload_url is time-limited. Never resize or alter the user's file to make it fit.
How do I improve a ChatGPT Plugin's discoverability?
The levers are the listing surface agents actually read: names, descriptions, keywords, tool metadata, and registry health. Which lever matters depends on where discovery breaks, which is what continuous measurement shows.
What are Datarails FinanceOS alternatives on ChatGPT?
As of 2026-08-14, Datarails FinanceOS competes with Aleph, Cube, Drivetrain, GrowPanel, Nella Finance AI, Parallel, SaaSFlow, Secfi in ChatGPT Financial Planning & FP&A Analytics, ranked by public Discoverability Score.
Where is this profile measured?
This profile uses the geography attached to the latest public registry snapshot: US. Locale tags are intentionally omitted.