Connecting a FOCUS data source
Overview
DigiUsher can ingest billing data from any source — datacenter costs, SaaS tools, internal chargebacks, or any other expense — as long as it's formatted as a FOCUS-compliant CSV. You upload CSV files to an S3 bucket organized in monthly folders, and DigiUsher ingests them automatically on a recurring schedule.
Common use cases:
- Datacenter costs — colocation, power, networking, hardware amortization
- SaaS tools — Datadog, Snowflake, New Relic, or any vendor that provides billing data
- Internal chargebacks — shared services, platform teams, cost allocation
- Multi-cloud consolidation — providers not natively supported by DigiUsher
What You'll Need
| Item | Details |
|---|---|
| S3 bucket | Any AWS region (no region restriction) |
| IAM role | Cross-account role granting DigiUsher read access |
| Billing data | FOCUS-formatted CSV files organized in monthly folders |
Data Format
Folder Structure
Files must be organized in monthly folders using the YYYY-MM naming convention:
s3://your-bucket/billing-exports/
├── 2025-01/
│ ├── expenses.csv
│ └── additional.csv.gz
├── 2025-02/
│ └── expenses.csv
└── 2025-03/
└── expenses.csv.gz- Multiple files per month are supported — they are merged during ingestion
- Supported formats:
.csvand.csv.gz(gzip-compressed) - All rows in a file must have a
ChargePeriodStartdate within the same month as the folder name
Column Specification
Your CSV files must follow the FOCUS specification. The full column reference — including required columns, optional columns, allowed enum values, and data types — is available in the FOCUS Any Column Specification sheet and embedded below:
Example CSV
Here's a minimal example with the required columns:
BilledCost,BillingAccountId,BillingCurrency,BillingPeriodStart,BillingPeriodEnd,ChargeCategory,ChargeFrequency,ChargePeriodStart,ChargePeriodEnd,EffectiveCost,ListCost,Provider,ResourceId,ServiceCategory,ServiceName
150.00,acct-001,USD,2025-03-01T00:00:00Z,2025-03-31T23:59:59Z,Usage,Recurring,2025-03-01T00:00:00Z,2025-03-02T00:00:00Z,150.00,180.00,Equinix,cab-42,Networking,Colocation
0.50,acct-001,USD,2025-03-01T00:00:00Z,2025-03-31T23:59:59Z,Usage,Usage-based,2025-03-01T00:00:00Z,2025-03-02T00:00:00Z,0.50,,Internal,,Compute,Shared GPU Cluster
-25.00,acct-001,USD,2025-03-01T00:00:00Z,2025-03-31T23:59:59Z,Credit,One-Time,2025-03-01T00:00:00Z,2025-03-31T23:59:59Z,-25.00,,Vendor,,Others,Promotional CreditAmounts can be negative
Credits, discounts, and refunds should be represented as negative amounts in BilledCost and EffectiveCost.
S3 Setup
Create or Choose an S3 Bucket
You can use an existing S3 bucket or create a new one. Any AWS region is fine.
- Go to S3 → Create bucket
- Choose a globally unique name (e.g.,
acme-corp-focus-billing) - Select your preferred region
- Block all public access: enabled (default)
- Create the bucket
BUCKET_NAME="acme-corp-focus-billing"
aws s3api create-bucket \
--bucket "$BUCKET_NAME" \
--region us-east-1
aws s3api put-public-access-block \
--bucket "$BUCKET_NAME" \
--public-access-block-configuration \
BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=trueUpload Your Billing Data
Organize your CSV files into monthly folders under a prefix:
# Example: upload March 2025 data
aws s3 cp expenses.csv s3://acme-corp-focus-billing/billing-exports/2025-03/expenses.csvImportant
Every row in a file must have a ChargePeriodStart date that falls within the month indicated by the folder name. For example, files in 2025-03/ must only contain rows with ChargePeriodStart in March 2025. Files with mismatched dates will be rejected.
Create an IAM Role
Create an IAM role that allows DigiUsher to read from your bucket.
- Go to IAM → Roles → Create role
- Select Another AWS account
- Enter Account ID:
058264546051 - Check Require external ID and paste your ExternalId from DigiUsher
- Click Next (do not attach any managed policies yet)
- Name the role (e.g.,
DigiUsherFocusRole) - Create the role
cat > trust-policy.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowDigiUsherAssumeRole",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::058264546051:root"
},
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {
"sts:ExternalId": "YOUR_EXTERNAL_ID"
}
}
}
]
}
EOF
aws iam create-role \
--role-name DigiUsherFocusRole \
--assume-role-policy-document file://trust-policy.jsonAttach S3 Read Policy
Grant the role read-only access to your billing bucket.
- Go to IAM → Roles → select
DigiUsherFocusRole - Click Add permissions → Create inline policy
- Switch to the JSON tab
- Paste the policy below (replace
YOUR_BUCKET_NAMEandYOUR_PREFIX) - Name it
DigiUsherFocusBillingAccess
cat > s3-policy.json << EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DigiUsherFocusBillingAccess",
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::$BUCKET_NAME",
"arn:aws:s3:::$BUCKET_NAME/billing-exports/*"
]
}
]
}
EOF
aws iam put-role-policy \
--role-name DigiUsherFocusRole \
--policy-name DigiUsherFocusBillingAccess \
--policy-document file://s3-policy.jsonNote the Role ARN
- Go to IAM → Roles → select
DigiUsherFocusRole - Copy the Role ARN (e.g.,
arn:aws:iam::123456789012:role/DigiUsherFocusRole)
aws iam get-role \
--role-name DigiUsherFocusRole \
--query 'Role.Arn' \
--output textConnect in DigiUsher
Enter the following into the DigiUsher platform to complete the connection:
| Field | Where to Find |
|---|---|
| Role ARN | IAM → Roles → DigiUsherFocusRole → ARN |
| Bucket Name | Your S3 bucket name (e.g., acme-corp-focus-billing) |
| Bucket Prefix | The folder prefix containing your YYYY-MM/ folders (e.g., billing-exports/) |
| External ID | (Optional) Generated by DigiUsher for confused deputy protection |
How Ingestion Works
Once connected, DigiUsher automatically:
- Discovers new files by listing your S3 bucket on each import cycle
- Validates each CSV against the FOCUS schema (required columns, data types, enum values)
- Ingests validated data into DigiUsher's analytics engine
- Tracks files by ETag — previously ingested files are not re-processed unless their content changes
Sub-Account Mapping
If your CSV includes a SubAccountId column, DigiUsher automatically creates child data sources for each unique value. This lets you break down costs by department, team, or business unit. If SubAccountId is not present, all costs are attributed to the parent data source.
Lookback Window
By default, DigiUsher looks back 2 months when discovering billing periods. Older monthly folders are skipped. To backfill historical data, contact support.
Verification Checklist
- CSV files uploaded to
YYYY-MM/folders under your prefix - Required columns present and non-null (see column spec above)
-
BillingCurrencyuses valid ISO 4217 currency codes -
ChargePeriodStartdates match the folder month - IAM role created with trust policy referencing DigiUsher account
- S3 read policy (
s3:ListBucket,s3:GetObject) attached to the role - Role ARN, bucket name, and prefix entered in DigiUsher
Troubleshooting
"No billing periods found"
- Verify your folders follow the
YYYY-MM/naming convention (e.g.,2025-03/, not202503/orMarch-2025/) - Check that the bucket prefix in DigiUsher matches where your folders are located
- Ensure your data is within the 2-month lookback window
"FOCUS CSV validation failed"
- Check that all required columns are present (see the column spec above)
- Verify enum columns (
ChargeCategory,ChargeFrequency,ServiceCategory) use allowed values - Ensure
BillingCurrencyis a valid ISO 4217 code (e.g.,USD,EUR,GBP)
"Access Denied"
- Verify the IAM role trust policy references the correct DigiUsher account ID (
058264546051) - Confirm the ExternalId matches what's configured in DigiUsher
- Check that the S3 policy grants
s3:ListBucketon the bucket ands3:GetObjecton the prefix
Data not appearing after connection
- The first import may take up to an hour depending on data volume
- Check that files have the
.csvor.csv.gzextension - Previously ingested files (same ETag) are not re-processed — upload new or modified files
Need Help?
If you encounter any issues not covered above, contact us at support@digiusher.com and we'll help you get set up.
DigiUsher Documentation