openmeter icon indicating copy to clipboard operation
openmeter copied to clipboard

feat(invoice): feature cost

Open hekike opened this issue 4 months ago • 1 comments

This is a PoC to help understand the cost behind invoice line items and break them down by meter dimensions. This is useful to understand the invoiced cost of individual users, workspaces, etc.

TODO

  • [ ] Finalize API
  • [ ] Move into service
  • [ ] Add tests

Invoice Feature Cost

GET /api/v1/billing/invoices/01K3M32GV47W7RD1XR93091X2Y/lines/01K3M32GVCEZ8BTG62DX0NVBQH/cost?windowSize=MINUTE&groupBy=model

{
  "costPerUnit": "0.01",
  "currency": "USD",
  "from": "2025-08-26T21:03:19Z",
  "rows": [
    {
      "cost": "1",
      "groupBy": {
        "model": "gpt-3"
      },
      "usage": "100",
      "windowEnd": "2025-08-26T21:10:00Z",
      "windowStart": "2025-08-26T21:09:00Z"
    },
    {
      "cost": "1",
      "groupBy": {
        "model": "gpt-3"
      },
      "usage": "100",
      "windowEnd": "2025-08-26T21:15:00Z",
      "windowStart": "2025-08-26T21:14:00Z"
    },
    {
      "cost": "1",
      "groupBy": {
        "model": "gpt-4"
      },
      "usage": "100",
      "windowEnd": "2025-08-26T21:15:00Z",
      "windowStart": "2025-08-26T21:14:00Z"
    }
  ],
  "to": "2025-09-26T21:03:19Z",
  "totalCost": "3",
  "totalUsage": "300"
}

Invoice

GET /api/v1/billing/invoices/01K3M32GV47W7RD1XR93091X2Y

{
  "collectionAt": "2025-09-26T21:03:19Z",
  "createdAt": "2025-08-26T21:03:19.396259Z",
  "currency": "USD",
  "customer": {
    "id": "01K3M32BS0MCA6ZCZQS60EA5CT",
    "name": "Customer 2",
    "usageAttribution": {
      "subjectKeys": [
        "customer-2"
      ]
    }
  },
  "id": "01K3M32GV47W7RD1XR93091X2Y",
  "lines": [
    {
      "children": [
        {
          "category": "regular",
          "createdAt": "2025-08-26T14:20:30.396154-07:00",
          "currency": "USD",
          "id": "01K3M41ZNW07N1NZM67DF4DZT8",
          "invoice": {
            "id": "01K3M32GV47W7RD1XR93091X2Y"
          },
          "invoiceAt": "2025-09-26T21:03:19Z",
          "managedBy": "system",
          "metadata": null,
          "name": "AI Tokens: usage in period",
          "paymentTerm": "in_arrears",
          "perUnitAmount": "0.01",
          "period": {
            "from": "2025-08-26T21:03:19Z",
            "to": "2025-09-26T21:03:19Z"
          },
          "quantity": "300",
          "rateCard": {
            "price": {
              "amount": "0.01",
              "paymentTerm": "in_arrears",
              "type": "flat"
            },
            "quantity": "300"
          },
          "status": "detailed",
          "totals": {
            "amount": "3",
            "chargesTotal": "0",
            "discountsTotal": "0",
            "taxesExclusiveTotal": "0",
            "taxesInclusiveTotal": "0",
            "taxesTotal": "0",
            "total": "3"
          },
          "type": "flat_fee",
          "updatedAt": "2025-08-26T14:20:30.396154-07:00"
        }
      ],
      "createdAt": "2025-08-26T21:03:19.404195Z",
      "currency": "USD",
      "featureKey": "ai_tokens",
      "id": "01K3M32GVCEZ8BTG62DX0NVBQH",
      "invoice": {
        "id": "01K3M32GV47W7RD1XR93091X2Y"
      },
      "invoiceAt": "2025-09-26T21:03:19Z",
      "managedBy": "subscription",
      "metadata": null,
      "name": "AI Tokens",
      "period": {
        "from": "2025-08-26T21:03:19Z",
        "to": "2025-09-26T21:03:19Z"
      },
      "price": {
        "amount": "0.01",
        "type": "unit"
      },
      "quantity": "300",
      "rateCard": {
        "featureKey": "ai_tokens",
        "price": {
          "amount": "0.01",
          "type": "unit"
        }
      },
      "status": "valid",
      "subscription": {
        "billingPeriod": {
          "from": "2025-08-26T21:03:19Z",
          "to": "2025-09-26T21:03:19Z"
        },
        "item": {
          "id": "01K3M32GQAE770PXQH2D2AFF3X"
        },
        "phase": {
          "id": "01K3M32GQC65X37KRT5AY3CCAN"
        },
        "subscription": {
          "id": "01K3M32GQET6ZS9ZCX5WG2K6BR"
        }
      },
      "totals": {
        "amount": "3",
        "chargesTotal": "0",
        "discountsTotal": "0",
        "taxesExclusiveTotal": "0",
        "taxesInclusiveTotal": "0",
        "taxesTotal": "0",
        "total": "3"
      },
      "type": "usage_based",
      "updatedAt": "2025-08-26T21:03:19.404195Z"
    }
  ],
  "metadata": null,
  "number": "GATHER-CU2-USD-1",
  "period": {
    "from": "2025-08-26T21:03:19Z",
    "to": "2025-09-26T21:03:19Z"
  },
  "quantitySnapshotedAt": "2025-08-26T14:20:30.354639-07:00",
  "status": "gathering",
  "statusDetails": {
    "availableActions": {
      "invoice": {}
    },
    "extendedStatus": "gathering",
    "failed": false,
    "immutable": false
  },
  "supplier": {
    "addresses": [
      {
        "country": "US"
      }
    ],
    "name": "OpenMeter"
  },
  "totals": {
    "amount": "3",
    "chargesTotal": "0",
    "discountsTotal": "0",
    "taxesExclusiveTotal": "0",
    "taxesInclusiveTotal": "0",
    "taxesTotal": "0",
    "total": "3"
  },
  "type": "standard",
  "updatedAt": "2025-08-26T21:03:19.42197Z",
  "workflow": {...}
}

hekike avatar Aug 26 '25 21:08 hekike

[!IMPORTANT]

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • [ ] Create PR with unit tests
  • [ ] Post copyable unit tests in a comment
  • [ ] Commit unit tests in branch feat/invoice-cost

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

coderabbitai[bot] avatar Aug 26 '25 21:08 coderabbitai[bot]