BlogTechnical
Technical12 min read

The Complete Guide to Utility Bill APIs

Everything developers need to know about integrating utility bill data into their applications—architecture patterns, data models, and best practices.

V
Vespine Team
November 28, 2024

Integrating utility bill data into your application opens up powerful capabilities—from automated expense management to sustainability reporting. This guide covers everything you need to know about utility bill APIs.

Understanding Utility Data APIs

Unlike traditional APIs that query databases, utility bill APIs must solve a unique challenge: extracting data from hundreds of different utility provider portals, each with their own authentication, navigation, and document formats.

API Architecture
# Typical flow
1. Register utility account with credentials
2. Agent logs into provider portal
3. Agent navigates to billing section
4. PDF downloaded and stored
5. Data extracted via AI parsing
6. Webhook fires with structured JSON

The Statement Data Model

A well-designed utility bill API returns structured data that's immediately usable:

Statement Object
{
  "id": "stmt_abc123",
  "account_id": "acct_xyz789",
  "provider": "pge",
  "statement_date": "2024-11-15",
  "due_date": "2024-12-05",
  "amount_due": 234.56,
  "previous_balance": 0.00,
  "service_address": {
    "line1": "123 Main Street",
    "city": "San Francisco",
    "state": "CA",
    "zip": "94102"
  },
  "usage": {
    "kwh": 892,
    "billing_days": 30,
    "avg_daily_kwh": 29.7
  },
  "charges": [
    { "description": "Electric Usage", "amount": 178.40 },
    { "description": "Delivery Charges", "amount": 42.16 },
    { "description": "Taxes & Fees", "amount": 14.00 }
  ],
  "pdf_url": "https://api.vespine.io/v1/statements/stmt_abc123/pdf",
  "created_at": "2024-11-16T08:23:45Z"
}

Integration Patterns

Pattern 1: Webhook-Driven

The recommended approach for most applications. Vespine pushes data to your endpoint when new bills are available:

webhook_handler.py
@app.post("/webhooks/vespine")
async def handle_webhook(request: Request):
    payload = await request.json()
    
    # Verify webhook signature
    signature = request.headers.get("X-Vespine-Signature")
    if not verify_signature(payload, signature):
        raise HTTPException(401, "Invalid signature")
    
    if payload["event"] == "statement.created":
        statement = payload["data"]
        
        # Process the new bill
        await process_utility_bill(
            account_id=statement["account_id"],
            amount=statement["amount_due"],
            due_date=statement["due_date"],
            pdf_url=statement["pdf_url"]
        )
    
    return {"received": True}

Pattern 2: Polling

For simpler integrations or when webhooks aren't feasible:

poll_statements.js
// Poll for new statements daily
const fetchNewStatements = async () => {
  const since = getLastSyncTimestamp();
  
  const response = await fetch(
    `https://api.vespine.io/v1/statements?since=${since}`,
    { headers: { Authorization: `Bearer ${API_KEY}` } }
  );
  
  const { data: statements } = await response.json();
  
  for (const stmt of statements) {
    await processStatement(stmt);
  }
  
  updateLastSyncTimestamp();
};

Authentication & Security

Utility bill APIs handle sensitive credentials. Here's how authentication typically works:

API Key Authentication

Bearer tokens for server-to-server calls. Keep these secret—never expose in client-side code.

Webhook Signatures

HMAC-SHA256 signatures verify webhook payloads. Always validate before processing.

Credential Encryption

Utility portal credentials are AES-256 encrypted at rest. Zero plaintext storage.

IP Allowlisting

Restrict API access to known IPs for additional security layer.

Error Handling

Utility portals are notoriously flaky. Build resilience into your integration:

Error CodeMeaningAction
CREDENTIAL_INVALIDLogin failedPrompt user to update credentials
PORTAL_UNAVAILABLEUtility site downAutomatic retry in 1 hour
NO_BILL_FOUNDNo new bill availableNormal—check again next cycle
RATE_LIMITEDToo many requestsExponential backoff

Best Practices

  1. Implement idempotency. Webhooks may fire multiple times. Use statement IDs to dedupe.
  2. Store PDFs locally. Download and store PDFs for compliance. URLs may expire.
  3. Handle partial data gracefully. Some fields may be null if not available on the bill.
  4. Monitor job status. Check sync job status to catch credential issues early.
  5. Use sandbox for testing. Don't test against production utility portals.

Ready to Start Building?

Get API access and explore our developer documentation.

View API Docs