| name | doit-mcp-api |
| description | Use this skill when the user asks to integrate with the DoiT API, generate API code, build programmatic queries, or needs DoiT API reference. Triggers on requests like "call the DoiT API", "write code to query costs", "DoiT API example", "integrate DoiT into my app", or any DoiT API development task. For interactive cost queries and reports, prefer the doit-mcp-reporting skill instead. |
| version | 1.1.0 |
DoiT API Code Generator
Generate correct DoiT Platform API calls for cost analytics. Use this skill to produce production-ready code when developers need to integrate DoiT cost analytics into their applications.
Tool Selection
Use MCP tools as the primary interface for all DoiT API operations. Only generate API code when the developer explicitly needs it for integration into their own applications.
Ava Fallback (Ask Ava)
If an MCP tool call fails, returns an error, returns empty/unexpected results, or does not answer the user's question, fall back to Ava — DoiT's AI assistant that can answer any cloud cost question.
Ava can be reached via both the DCI CLI and MCP. Prefer the DCI CLI (dci ask-ava-sync) because it returns cleaner JSON output. Before calling Ava, check if the DCI CLI is installed by running command -v dci. If it is not installed, you MUST ask the user if they want to install it: "To get a better answer, I can ask Ava (DoiT's AI assistant). The recommended way is via the DCI CLI. Would you like to install it? (brew install doitintl/dci-cli/dci)". If the user agrees, invoke the doit-mcp-setup skill to install and authenticate the DCI CLI, then call Ava. If the user declines, fall back to the MCP Ava tool instead.
When to use Ava fallback:
- An MCP tool call fails or times out
- Query results are empty and you cannot determine why
- The user's question is about DoiT API behavior, field meanings, or best practices that structured tools cannot answer
- You need contextual or explanatory information that the API reference alone does not cover
How to call Ava:
dci ask-ava-sync ephemeral: true, question: "<rephrase the user's question or describe what you need>" --output json
- Always set
ephemeral: true to avoid persisting throwaway conversations.
- Rephrase the question to include relevant context (e.g., endpoint, error message, dimension ID) from earlier steps.
- Parse the
answer field from the JSON response and present it to the user.
When to Use
Activate this skill when a developer:
- Asks how to call the DoiT API
- Needs to build a cost analysis query
- Wants to list, filter, or retrieve reports
- Needs to query dimensions, anomalies, or incidents
- Is debugging a DoiT API call
- Wants code examples in any language
Quick Reference
Dimension Mappings
Map natural language to dimension IDs:
| Natural Language | Dimension ID | Type |
|---|
| "by service" | service_description | fixed |
| "by project" | project_id | fixed |
| "by project name" | project_name | fixed |
| "by region" | region | fixed |
| "by cloud provider" | cloud_provider | fixed |
| "by resource" | resource_id | fixed |
| "by SKU" | sku_description | fixed |
| "by unit" | pricing_unit | fixed |
| "by billing account" | billing_account_id | fixed |
| "by cost type" | cost_type | fixed |
| "by team" | Use attribution_group type with UUID ID from list_dimensions | attribution_group |
| "by invoice" | invoice_month | fixed |
Cloud Provider Filter Values
| Natural Language | Filter Value |
|---|
| "AWS", "Amazon" | amazon-web-services |
| "GCP", "Google Cloud" | google-cloud |
| "Azure", "Microsoft" | microsoft-azure |
Time Range Mappings
| Developer Says | Generated timeRange |
|---|
| "last 30 days" | { mode: 'last', amount: 30, unit: 'day', includeCurrent: false } |
| "last 7 days" | { mode: 'last', amount: 7, unit: 'day', includeCurrent: false } |
| "last month" | { mode: 'last', amount: 1, unit: 'month', includeCurrent: false } |
| "this month" | { mode: 'last', amount: 1, unit: 'month', includeCurrent: true } |
| "last quarter" | { mode: 'last', amount: 1, unit: 'quarter', includeCurrent: false } |
| "last year" | { mode: 'last', amount: 1, unit: 'year', includeCurrent: false } |
| "Q1 2024" | Use customTimeRange with calculated dates |
Metric Types
| Developer Says | Metric Config |
|---|
| "cost", "costs", "spend" | { type: 'basic', value: 'cost' } |
| "usage", "consumption" | { type: 'basic', value: 'usage' } |
| "savings" | { type: 'basic', value: 'savings' } |
| "credits" | { type: 'basic', value: 'credit' } |
| "discounts" | { type: 'basic', value: 'discount' } |
Time Interval Mappings
Control data aggregation granularity:
| User Intent | timeInterval | Typical Rows | Use Case |
|---|
| "hourly breakdown" | 'hour' | 24-720 rows | Real-time monitoring |
| "daily breakdown" | 'day' or omit | 7-365 rows | Default behavior |
| "weekly totals" | 'week' | 4-52 rows | Weekly reports |
| "monthly totals" | 'month' | 1-12 rows | Monthly analysis (recommended) |
| "quarterly totals" | 'quarter' | 1-4 rows | Quarterly reviews |
| "yearly totals" | 'year' | 1-5 rows | Annual reports |
Note: Omitting timeInterval defaults to daily breakdown. For time ranges > 7 days, specify timeInterval to avoid hundreds of rows.
Parameter Reference
Common optional parameters:
| Parameter | Type | Default | Description |
|---|
customerId | string | All accessible | Specific customer ID for multi-customer environments |
timeInterval | string | 'day' | Aggregation level: hour, day, week, month, quarter, year |
filters | array | [] | Filter results by dimension values |
group | array | [] | Dimensions to group results by |
customerId Usage:
- Omit: Query returns data for all accessible customers
- Include: Query returns data for specific customer only (e.g.,
'KzDE3pXU4KeQ3b53ciDN')
Filter Combination Logic
Understanding how filters combine:
| Pattern | Syntax | Logic | Example |
|---|
| OR within filter | values: ['A', 'B'] | Matches A OR B | values: ['aws', 'gcp'] matches AWS or GCP |
| AND between filters | Multiple filter objects | All must match | Filter 1 AND Filter 2 AND Filter 3 |
| NOT (exclusion) | inverse: true | Excludes values | inverse: true, values: ['test'] excludes test |
| Complex | Combine patterns | Nested logic | (A OR B) AND (C OR D) AND NOT (E OR F) |
Example:
filters: [
{
id: 'cloud_provider',
type: 'fixed',
inverse: false,
values: ['amazon-web-services', 'google-cloud']
},
{
id: 'region',
type: 'fixed',
inverse: false,
values: ['us-east-1']
},
{
id: 'attribution_group',
type: 'attribution',
inverse: true,
values: ['test']
}
]
MCP Tool Mapping
When using the DoiT MCP server instead of direct HTTP calls:
| Operation | MCP Tool | HTTP Endpoint | Usage Notes |
|---|
| Run ad-hoc query | run_query | POST /reports/query | Pass config object directly in arguments |
| List reports | list_reports | GET /reports | No arguments required |
| Get report results | get_report_results | GET /reports/{id}/results | Requires reportId argument |
| List dimensions | list_dimensions | GET /dimensions | Optional filter argument |
| Get dimension | get_dimension | GET /dimensions/{id} | Requires dimensionId argument |
| Get anomalies | get_anomalies | GET /anomalies | Optional startDate, endDate arguments |
| Get incidents | get_cloud_incidents | GET /cloud-incidents | Optional filtering arguments |
| Validate user | validate_user | GET /user | No arguments required |
Generic MCP Client Usage
interface MCPClient {
callTool(request: { name: string; arguments: Record<string, any> }): Promise<any>;
}
const result = await mcpClient.callTool({
name: 'run_query',
arguments: {
config: {
dataSource: 'billing',
metric: { type: 'basic', value: 'cost' },
timeRange: { mode: 'last', amount: 1, unit: 'month', includeCurrent: false },
timeInterval: 'month'
}
}
});
Basic Query Structure
Response Schema
Query results automatically include these columns alongside your grouped dimensions:
| Column | Type | Description |
|---|
| (grouped dim) | string | Each group dimension becomes a column |
year | string | Year of the data point |
month | string | Month of the data point |
cost | float | The metric value (named by metric type) |
timestamp | timestamp | Unix timestamp of the period |
Note: Results include a ∑ Other aggregated row when the limit value is exceeded.
const monthlyQuery = {
config: {
dataSource: 'billing',
metric: { type: 'basic', value: 'cost' },
timeRange: { mode: 'last', amount: 1, unit: 'month', includeCurrent: false },
timeInterval: 'month',
group: [{
id: 'service_description',
type: 'fixed',
limit: { metric: { type: 'basic', value: 'cost' }, sort: 'desc', value: 25 }
}]
}
};
const dailyQuery = {
config: {
dataSource: 'billing',
metric: { type: 'basic', value: 'cost' },
timeRange: { mode: 'last', amount: 30, unit: , : },
: [{
: ,
: ,
: { : { : , : }, : , : }
}]
}
};
[!IMPORTANT]
Always verify dimension IDs with list_dimensions before using them in queries to prevent 400 Bad Request errors.
[!WARNING]
Omitting timeInterval returns daily data by default, which can produce hundreds of rows. For cost analysis over weeks or months, always specify timeInterval: 'month' or 'week' to aggregate results.
Additional Resources
Reference Files
For detailed specifications and patterns, consult:
references/api-reference.md — Full endpoint specifications, request/response schemas, validation rules
references/code-examples.md — Complete TypeScript, Python, Go, and cURL examples
references/troubleshooting.md — Error handling, HTTP status codes, common scenarios
- Report Comparison Workflow — Step-by-step guide for matching query results with saved reports
Example Files
Working examples in examples/ that can be copied and adapted:
examples/query-costs-by-service.ts — TypeScript example
examples/query-costs-by-service.py — Python example
examples/query-costs-by-service.sh — Bash/cURL example