@11ma/billing-sdk
v0.3.7
Published
Billing export SDK — self-contained TypeScript client for PPA billing data over DAGQL
Readme
@11ma/billing-sdk
Self-contained TypeScript client for PPA billing over DAGQL — export, acknowledgements, and Trieve writebacks.
Install
npm install @11ma/billing-sdkQuick Start
import { BillingClient } from "@11ma/billing-sdk"
const client = new BillingClient({
baseUrl: process.env.DAGQL_BASE_URL!,
apiKey: process.env.DAGQL_API_KEY!,
appSecret: process.env.DAGQL_APP_SECRET!,
})
// Pull billing data
const response = await client.export("2024-01", { limit: 50 })
for await (const org of client.exportAll("2024-01")) {
for (const site of org.sites) {
// ExpenseSmart identity fields on each site
console.log(
site.store_id, // client store #
site.cass_account_number, // e.g. 11MA-001-18352
site.full_service_address, // single-line service address
site.total_usd,
)
}
}
// Acknowledge export receipt
await client.ack("2024-01", orgId)
// Cass ExpenseSmart account verified in Trieve
// Accepts persisted Site.cass_account_number or export-derived 11MA-{facility_id}
await client.confirmCassAccount({
cassAccountNumber: "11MA-FAC-001",
status: "ACTIVE",
})
// Payment confirmed in ExpenseSmart + bank deposit
await client.reportPaymentStatus("2024-01", orgId, siteId, "PAID", {
reference: "trieve-inv-456",
paidAt: "2024-02-15T12:00:00.000Z",
expenseSmartVerified: true,
bankDepositConfirmed: true,
})API
| Method | Description |
|--------|-------------|
| client.export(period, options?) | Fetch one page of billing data |
| client.exportAll(period, pageSize?) | Auto-paginating async generator |
| client.ack(period, orgId, options?) | Acknowledge receipt of billing export |
| client.confirmCassAccount(options) | Update Site.cass_account_status after ExpenseSmart provisioning |
| client.reportPaymentStatus(period, orgId, siteId, status, options?) | Record payment / verification via ExternalSync (BillingPayment) |
Integrator RBAC
The Trieve service account needs:
- Read on organizations/sites (export, lookups)
- Write on sites (
confirmCassAccount) - Write on org-scoped
ExternalSyncrows (ack,reportPaymentStatus)
All writebacks are idempotent where noted in method docs.
Export tax & warnings
- Tax rates are resolved as-of the last instant of the billing month (not period start), so a mid-month SureTax sync still applies to that month's export.
- Prefer the DAGQL jurisdiction chain (
SiteInTaxJurisdiction→TaxJurisdiction→JurisdictionTaxRate). When no rate is effective,tax.rate_percentis0and billable sites with a positive subtotal also getwarnings[]with codeTAX_RATE_UNRESOLVED. - Check
response.errors/response.warnings(ExportIssue) before treating zeroed totals as valid bills — e.g.SCHEDULE_NOT_BILLABLE,TAX_RATE_UNRESOLVED.
ExpenseSmart identity fields
Each exported site includes three identifiers Cass ExpenseSmart bill processors use to match a Dollar General (or other) store:
| Field | Example | Source |
|-------|---------|--------|
| store_id | "18352" | Client-issued store number |
| cass_account_number | "11MA-001-18352" | Site.cass_account_number, or 11MA-{facility_id} fallback when unique in the export payload |
| cass_account_number_source | "persisted" / "derived" | Provenance of the Cass account number (null when omitted) |
| full_service_address | "4120 Highway 41, Goodlettsville, TN 37072" | Composed from service address + city/state/zip |
Structured address remains available for layout; put full_service_address and cass_account_number on the PPA invoice.
Export vs writeback: Export may synthesize 11MA-{facility_id} for invoice print when the Site scalar is unset. confirmCassAccount resolves the same value via persisted cass_account_number first, then by facility_id when the number matches the canonical form, and always pins cass_account_number with the status update. Facility fallback refuses sites whose persisted cass already differs. If the synthetic value is already claimed by another site in the export payload, export emits null and a CASS_ACCOUNT_COLLISION warning — run Cass backfill before matching.
Rate Resolution
Pluggable strategies for escalation and rate structures:
import { BillingClient, compoundingEscalator, touRate } from "@11ma/billing-sdk"
const client = new BillingClient({
// ...auth config
resolution: {
escalator: compoundingEscalator,
rateStructure: touRate,
},
})Documentation
Full interactive docs with live credentials: /billing-sdk/docs in the PowerBuilDER app.
Operations & credentials (handoff / Treve / npm publish): docs/operations/billing-sdk-and-trieve-operations.md
Migration from REST
Deploy removes GET /api/v1/trieve/export, POST /api/v1/trieve/ack, and POST /api/v1/cass/account-status from powerbuilder.ai. Use this SDK against the DAGQL host (port 8080) instead:
| Legacy REST | Billing SDK |
|-------------|-------------|
| GET /api/v1/trieve/export | client.export(period) |
| POST /api/v1/trieve/ack | client.ack(period, orgId) |
| POST /api/v1/cass/account-status | client.confirmCassAccount(...) |
- Auth:
Authorization: Bearer+X-Password(replacesX-Trieve-Keyon powerbuilder.ai). - Field renames:
estimated_subtotal/estimated_tax→subtotal_usd/tax_usd. - Archival spec: docs/plans/trieve-data-export.md
Provision a scoped service account (Read on orgs/sites, Write on sites and org-scoped ExternalSync) before cutover. REST removal is not feature-flagged.
License
MIT
