MMetiss AI|Docs

Utility Bill AI

The Utility Bill AI service accepts a customer's electricity bill as a PDF or image and returns a structured JSON object containing customer details, billing information, meter readings, and up to 12 months of historical usage — all extracted by Google Gemini with no manual data entry.

Processing pipeline

STEP 1UploadPDF, PNG,JPG, or JPEGelectricity billSTEP 2ValidateSubscription,file type &size checkSTEP 3Gemini ExtractAI parses billinto structuredJSON (up to 3×)STEP 4StoreFile uploadedto GCS, resultsaved to DBSTEP 5Return JSONStructured billdata + filestatus array

Supported input

FormatNotes
PDFMulti-page PDFs are treated as a single document. All pages are analysed together.
PNG / JPG / JPEGMultiple image files are treated as one document. OCR noise (routing codes, asterisks) is filtered automatically.
Electricity bills only. The service validates that the uploaded document is an electricity bill. Gas-only bills and non-utility documents are rejected with a 400 error.

Extracted data

A successful extraction returns a JSON object with three top-level sections:

customerInformation

FieldTypeDescription
customerNamestringExtracted from the payment stub. OCR noise and routing codes are filtered out.
accountNumberstringUtility account number.
serviceNumberstringService reference number, if explicitly labelled on the bill.
serviceAddressAddressAddress where electricity is provided (line1, line2, city, state, zip, country).

billingInformation

FieldTypeDescription
utilityProviderNamestringName of the utility company.
invoiceDatestringBill issue date in YYYY-MM-DD format.
billingPeriodStart / EndstringStart and end dates of the billing period in YYYY-MM-DD format.
amountDuestringTotal amount due. Negative values indicate credits. Currency symbols are stripped.
pastDuestringPrevious balance remaining after last payment.
dueDatestringPayment due date in YYYY-MM-DD format.
billingAddressAddressAddress the bill is mailed to, extracted from the payment stub.

electricityUsage

FieldTypeDescription
metersarrayPer-meter readings — each includes meterNumber, usageKwh, servicePeriodStart, servicePeriodEnd.
electricRatestringCustomer's rate plan or class (e.g. "Residential Regular R-1").
electricityTierstringTier information, if explicitly marked on the bill.
supplyRatePerKwhstring RequiredSupply or generation rate per kWh. The service retries extraction up to 3 times if this field is missing.
marketStatestringTwo-letter state abbreviation of the service address (e.g. MA, RI).
usageByMontharrayUp to 12 months of historical usage. Each entry: month, year, value, unit. Missing months are extrapolated using seasonal patterns from available data.

Retry logic

Gemini is called up to 3 times per request. After each attempt the service checks whether usageByMonth contains at least 12 months. If the count is sufficient, processing stops early. Retries also stop if the result does not change between attempts.

supplyRatePerKwh is the one field that is always required. If Gemini cannot find it, the extraction is retried regardless of usage month count.

API endpoints

Method & pathModeUse when
POST /process-billSynchronousFiles uploaded directly in the request body. Returns the full result immediately after processing.
POST /process-utility-billAsynchronousFiles already stored in GCS (uploaded separately). Triggers background processing — poll for status.
POST /poll-utility-bill-statusPollingReturns the current status of an async job. Statuses: IN_PROGRESS, COMPLETED, FAILED.
GET /healthHealth check. Returns {'status': 'ok'}.

Request — POST /process-bill

Multipart form data:

POST /v1/utility-bill-service/process-bill
Authorization: Bearer <id_token>
Content-Type: multipart/form-data

files:              <file>         # PDF, PNG, JPG, or JPEG
transactionId:      <uuid>
transactionGroupId: <uuid>
externalId:         <user_email>   # optional, defaults to token email

Response

{
  "apiVersion": "1.0",
  "transactionId": "...",
  "transactionGroupId": "...",
  "id": "...",
  "data": {
    "items": [
      {
        "customerInformation": { ... },
        "billingInformation": { ... },
        "electricityUsage": {
          "meters": [...],
          "electricRate": "Residential Regular R-1",
          "supplyRatePerKwh": "0.18213",
          "marketState": "MA",
          "usageByMonth": [
            { "month": "January", "year": "2025", "value": "980", "unit": "kWh" },
            ...
          ]
        }
      }
    ]
  },
  "fileStatus": [
    { "filename": "bill.pdf", "status": "success" }
  ]
}

Task status (async mode)

When using POST /process-utility-bill, poll for completion using the transactionId:

POST /v1/utility-bill-service/poll-utility-bill-status
{ "transactionId": "<uuid>" }

# Response
{
  "status": "IN_PROGRESS",
  "percentage": "50%",
  "message": "Utility bill extracted successfully..."
}

Percentage milestones: 0% initiated → 10% validated → 20% processing → 50% extracted → 100% complete or failed.

Error cases

StatusCodeCause
400Invalid file typeUploaded file is not a supported format or is not an electricity bill.
400Incomplete billCustomer name or service address could not be extracted after all retries.
400Subscription inactiveThe organisation's utility-bill service subscription has ended or is not active.
500Processing failedGemini returned an unparseable response after all retries.