Skip to main content

API

The Infracost Cloud API enables you to programmatically manage tagging policies, guardrails, price books and custom properties. This is particularly useful for enterprises that need to sync data from external systems like ServiceNow, Backstage, or internal CMDBs rather than managing everything manually through the dashboard.

What the API enables

Sync tag values from your source of truth

Large enterprises often maintain thousands of application IDs, service names, or cost center codes in systems like ServiceNow. Rather than manually keeping Infracost's tagging policies in sync, you can push valid values via the API on a schedule.

When engineers write infrastructure-as-code, Infracost validates their tag values against your authoritative list, automatically catching typos, incorrect capitalization, and invalid entries before code is merged. No more cleaning up tagging data after the fact.

Manage guardrails programmatically

Create, update, and delete cost guardrails through the API. This is useful for:

  • Automating guardrail creation across multiple organizations
  • Adjusting thresholds based on external budget data
  • Integrating guardrail management into your infrastructure provisioning workflows

Keep custom properties in sync

If you maintain organizational hierarchy data in Backstage, ServiceNow, or a CMDB, you can push updates to Infracost automatically. This ensures cost attribution stays current as teams reorganize and ownership changes.

Price Book Management

Create, update and delete custom price books through the API. This is useful to provide custom pricing data when you have committed use discounts and similar with your cloud provider (e.g. AWS Private Pricing).

We currently support custom price book management of AWS and Azure Price Books.

Authentication

API requests require a service account token (your CLI token won't work with the API).

Create a service account token to access the api

To create one:

  1. Log in to Infracost Cloud
  2. Go to Org Settings > API tokens
  3. Click Create service account
  4. Copy the generated token

Include the token in your requests:

curl -H "Authorization: Bearer $INFRACOST_API_TOKEN" \
https://api.infracost.io/v1/orgs/{orgSlug}/...

You'll also need your organization slug, available from Org Settings > General.

API reference

Full API documentation with request/response schemas is available at api.infracost.io/v1/docs.

Tagging policies

Update allowed tag values

The most common API use case is pushing a list of valid tag values from an external system. This validates that engineers use correct values (no typos, proper formatting) when tagging resources.

Example: Validate app_id tags against a list of registered applications from ServiceNow.

Create a JSON file (tags.json):

{
"data": {
"attributes": {
"tags": [
{
"key": "app_id",
"mandatory": true,
"valueType": "LIST",
"allowedValues": [
"app-inventory-prod",
"app-payments-prod",
"app-auth-prod",
"app-analytics-prod"
]
}
]
}
}
}

Get your policy ID from Governance > Tagging policies > select your policy (the ID is in the URL).

Update the policy:

curl -X PATCH \
-H "Authorization: Bearer $INFRACOST_API_TOKEN" \
-H "Content-Type: application/json" \
--data @tags.json \
https://api.infracost.io/v1/orgs/{orgSlug}/tagging-policies/{policyId}

💡 Tip: Run this on a schedule (e.g., daily via cron or CI) to keep Infracost in sync with your application registry. Engineers get immediate feedback when they use an unregistered application ID.

Customize the validation message

You can customize the message engineers see when validation fails. Include instructions for how to fix the issue:

{
"data": {
"attributes": {
"tags": [
{
"key": "app_id",
"mandatory": true,
"valueType": "LIST",
"allowedValues": ["app-inventory-prod", "app-payments-prod"],
"message": "The application ID isn't registered. Please ensure your application is listed at https://services.acme-inc.com/register before using it in infrastructure code."
}
]
}
}
}

Guardrails

Create a guardrail

Create a JSON file (guardrail.json):

{
"data": {
"type": "guardrails",
"attributes": {
"name": "Production Cost Limit",
"scope": "PULL_REQUEST",
"increaseThreshold": 500,
"message": "This PR increases monthly costs by more than $500. Please get approval from your team lead before merging.",
"prComment": true,
"blockPr": false,
"filters": {
"repos": {
"include": ["production-infra", "platform-services"],
"exclude": []
}
}
}
}
}

Create the guardrail:

curl -X POST \
-H "Authorization: Bearer $INFRACOST_API_TOKEN" \
-H "Content-Type: application/json" \
--data @guardrail.json \
https://api.infracost.io/v1/orgs/{orgSlug}/guardrails

Guardrail operations

OperationMethodEndpoint
List all guardrailsGET/v1/orgs/{orgSlug}/guardrails
Get a guardrailGET/v1/orgs/{orgSlug}/guardrails/{id}
Create a guardrailPOST/v1/orgs/{orgSlug}/guardrails
Update a guardrailPATCH/v1/orgs/{orgSlug}/guardrails/{id}
Delete a guardrailDELETE/v1/orgs/{orgSlug}/guardrails/{id}

Guardrail attributes

AttributeTypeDescription
namestringDisplay name for the guardrail
scopestringPULL_REQUEST (evaluate per PR) or PROJECT (evaluate per project)
increaseThresholdnumberTrigger when cost increase exceeds this amount
increasePercentageThresholdnumberTrigger when cost increase exceeds this percentage
totalThresholdnumberTrigger when total cost exceeds this budget
messagestringCustom message shown when guardrail triggers
prCommentbooleanShow guardrail info in PR comments
blockPrbooleanBlock PR from merging when triggered
webhookUrlstringURL to receive webhook notifications
filters.repos.includearrayOnly apply to these repositories
filters.repos.excludearrayExclude these repositories

Custom properties

Update custom properties CSV

Push your organizational hierarchy data to Infracost. This is useful for syncing from Backstage, ServiceNow, or other systems that maintain team ownership data.

Create a CSV file (custom_properties.csv):

service_id,team,division,cost_center,slack_channel
auth-service,identity,platform,CC-1001,#identity-team
payment-api,payments,product,CC-1002,#payments-eng
inventory-svc,logistics,product,CC-1002,#logistics

Upload the CSV:

curl -X POST \
-H "Authorization: Bearer $INFRACOST_API_TOKEN" \
-H "Content-Type: text/csv" \
--data-binary @custom_properties.csv \
https://api.infracost.io/v1/orgs/{orgSlug}/custom-properties

⚠️ Warning: You must use --data-binary with curl. Using --data or -d strips newlines from the CSV, resulting in no data being uploaded.

💡 Tip: Schedule this to run daily. Custom properties don't typically change frequently, so daily syncs keep data current without excessive API calls.

Price Books

Price Books are an enterprise feature, meaning that a price book is owned by an enterprise, not an organisation. However, organisations then use ingested price books.

As such, the API Token used for the requests needs to be by a user or service account with orgAdmin permissions of the primary org of an enterprise.

A full flow would look something like this:

Create the Price Book:

curl -X POST \
'https://api.infracost.io/v1/enterprises/{enterpriseId}/price-books' \
-H "Authorization: Bearer $INFRACOST_API_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"provider": "AZURE"}' # or AWS.
{
"data": {
"id": "4687fa2f-076d-487f-ba47-7c35b4530e6b",
"enterpriseId": "61a1ad7c-c20a-4f17-8e01-51da84033fc7",
"createdAt": "2026-02-06T11:42:20.692Z",
"updatedAt": "2026-02-06T11:42:20.692Z",
"provider": "AZURE",
"status": "WAITING_FOR_UPLOAD",
"statusMessage": "",
"sourceFiles": []
}
}

Create a price book file:

curl -X POST \
"https://api.infracost.io/v1/enterprises/{enterpriseId}/price-books/{priceBookId}/files" \
-H "Authorization: Bearer $INFRACOST_API_TOKEN"
{
"data": {
"file": {
"id": "d3528900-4e6a-4e8e-8b1c-82bc8f111d1f",
"createdAt": "2026-02-06T11:44:59.923Z",
"updatedAt": "2026-02-06T11:44:59.923Z",
"enterpriseId": "61a1ad7c-c20a-4f17-8e01-51da84033fc7",
"priceBookId": "4687fa2f-076d-487f-ba47-7c35b4530e6b"
},
"preSignedUrl": "https://infracost-prod-price-books.s3.us-east-2.amazonaws.com/{enterpriseId}/{priceBookId}/{fileId}.csv?..."
}
}

Use the preSignedUrl to upload your custom price book file. If you have multiple files, repeat this process and upload all files individually.

curl -X PUT \
'https://infracost-prod-price-books.s3.us-east-2.amazonaws.com/{enterpriseId}/{priceBookId}/{fileId}.csv?...' \
-H 'Content-Type: text/csv' \
--data-binary '@<path to your priceBookFile>'

Supported cloud providers and their formats are:

  • Azure: please follow this guide to export your pricing data and get your price book files. This should give you CSV files with the following columns:
    • EnrollmentNumber
    • MeterId
    • MeterName
    • MeterType
    • MeterCategory
    • MeterSubCategory
    • ServiceFamily
    • Product
    • SkuID
    • ProductID
    • MeterRegion
    • UnitOfMeasure
    • PartNumber
    • EffectiveStartDate
    • EffectiveEndDate
    • UnitPrice
    • BasePrice
    • MarketPrice
    • CurrencyCode
    • IncludedQuantity
    • OfferId
    • Term
    • PriceType
  • AWS: This option is designed for cases when you want to use blended prices, see this docs section.
    • productcode
    • instancetype
    • databaseengine
    • operatingsystem
    • deploymentoption
    • licensemodel
    • hourlyprice
    • vcpu
    • memory
    • region
    • databaseedition
    • description

Once uploaded, trigger the ingestion of the price book:

curl -X POST \
'https://api.infracost.io/v1/enterprises/{enterpriseId}/price-books/{priceBookId}/ingest' \
-H "Authorization: Bearer $INFRACOST_API_TOKEN"
{
"data": {
"id": "4687fa2f-076d-487f-ba47-7c35b4530e6b",
"enterpriseId": "61a1ad7c-c20a-4f17-8e01-51da84033fc7",
"createdAt": "2026-02-06T11:42:20.692Z",
"updatedAt": "2026-02-06T13:15:35.804Z",
"provider": "AZURE",
"status": "PROCESSING",
"statusMessage": "",
"sourceFiles": [
{
"id": "d3528900-4e6a-4e8e-8b1c-82bc8f111d1f",
"createdAt": "2026-02-06T11:44:59.923Z",
"updatedAt": "2026-02-06T11:44:59.923Z",
"enterpriseId": "61a1ad7c-c20a-4f17-8e01-51da84033fc7",
"priceBookId": "4687fa2f-076d-487f-ba47-7c35b4530e6b"
}
]
}
}

You can poll for the status by running a GET command:

curl -X GET \
'https://api.infracost.io/v1/enterprises/{enterpriseId}/price-books/{priceBookId}' \
-H "Authorization: Bearer $INFRACOST_API_TOKEN"

Once the returned price book shows 'SUCCESS' as a status, the price book can be activated.

curl -X PATCH \
"https://api.infracost.io/v1/organizations/{organizationId}" \
-H "Authorization: Bearer $INFRACOST_API_TOKEN" \
-H "Content-Type: application/json" \
--data '{"customPriceBookId": "{priceBookId}"}'
{
"data": {
"id": "04b2632b-a0f1-4140-b5fe-a09074727336",
"name": "...",
"slug": "...",
"customPriceBookId": "4687fa2f-076d-487f-ba47-7c35b4530e6b",
"createdAt": "2026-02-08T12:33:12.173Z",
"updatedAt": "2026-02-09T10:35:50.124Z"
}
}

Price Books can also be listed:

curl -X GET \
'https://api.infracost.io/v1/enterprises/{enterpriseId}/price-books' \
-H "Authorization: Bearer $INFRACOST_API_TOKEN"

and deleted:

curl -X DELETE \
'https://api.infracost.io/v1/enterprises/{enterpriseId}/price-books/{priceBookId}' \
-H "Authorization: Bearer $INFRACOST_API_TOKEN"

Rate limits

The API is rate-limited to ensure fair usage. If you receive a 429 Too Many Requests response, wait before retrying. For bulk operations, we recommend:

  • Batching updates rather than making individual calls per item
  • Running syncs during off-peak hours
  • Using exponential backoff for retries

Troubleshooting

If you run into any issues, please join our community Slack channel, we'll help you very quickly 😄

401 Unauthorized

Common causes: Invalid or expired token, using a CLI token instead of a service account token.

Solution: Create a new service account token from Org Settings > API tokens. Verify you're using the service account token, not your personal CLI token.

404 Not Found

Common causes: Incorrect organization slug or resource ID, or the resource doesn't exist.

Solution: Verify your org slug in Org Settings > General. For policy/guardrail IDs, copy the ID from the URL when viewing the resource in the dashboard.

400 Bad Request

Common causes: Malformed JSON, missing required fields, or invalid field values.

Solution: Validate your JSON syntax. Check the API docs for required fields and valid values.

CSV upload shows no data

Common causes: Using --data instead of --data-binary with curl, which strips newlines.

Solution: Always use --data-binary when uploading CSV files:

curl --data-binary @file.csv ...  # Correct
curl --data @file.csv ... # Wrong - strips newlines