Data Connections

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

ItemDetails
S3 bucketAny AWS region (no region restriction)
IAM roleCross-account role granting DigiUsher read access
Billing dataFOCUS-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: .csv and .csv.gz (gzip-compressed)
  • All rows in a file must have a ChargePeriodStart date 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 Credit

Amounts 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.

  1. Go to S3Create bucket
  2. Choose a globally unique name (e.g., acme-corp-focus-billing)
  3. Select your preferred region
  4. Block all public access: enabled (default)
  5. 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=true

Upload 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.csv

Important

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.

  1. Go to IAMRolesCreate role
  2. Select Another AWS account
  3. Enter Account ID: 058264546051
  4. Check Require external ID and paste your ExternalId from DigiUsher
  5. Click Next (do not attach any managed policies yet)
  6. Name the role (e.g., DigiUsherFocusRole)
  7. 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.json

Attach S3 Read Policy

Grant the role read-only access to your billing bucket.

  1. Go to IAMRoles → select DigiUsherFocusRole
  2. Click Add permissionsCreate inline policy
  3. Switch to the JSON tab
  4. Paste the policy below (replace YOUR_BUCKET_NAME and YOUR_PREFIX)
  5. 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.json

Note the Role ARN

  1. Go to IAMRoles → select DigiUsherFocusRole
  2. Copy the Role ARN (e.g., arn:aws:iam::123456789012:role/DigiUsherFocusRole)
aws iam get-role \
  --role-name DigiUsherFocusRole \
  --query 'Role.Arn' \
  --output text

Connect in DigiUsher

Enter the following into the DigiUsher platform to complete the connection:

FieldWhere to Find
Role ARNIAM → Roles → DigiUsherFocusRole → ARN
Bucket NameYour S3 bucket name (e.g., acme-corp-focus-billing)
Bucket PrefixThe 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:

  1. Discovers new files by listing your S3 bucket on each import cycle
  2. Validates each CSV against the FOCUS schema (required columns, data types, enum values)
  3. Ingests validated data into DigiUsher's analytics engine
  4. 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)
  • BillingCurrency uses valid ISO 4217 currency codes
  • ChargePeriodStart dates 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/, not 202503/ or March-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 BillingCurrency is 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:ListBucket on the bucket and s3:GetObject on 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 .csv or .csv.gz extension
  • 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.