Skip to content

Billing & Ledger Service API (1.0.0)

The Billing & Ledger Service is the financial engine of the NPS Billing Platform. It manages pricing (Rates, Rate Cards), subscription configurations, allocation rules for split billing scenarios (divorced households, subsidies), charge lifecycle, and double-entry accounting ledger.

Key Concepts

Charge Lifecycle

Charges follow a strict lifecycle with immutability after invoicing:

  • PENDING → Created but not validated
  • BILLED → Validated and ready to invoice (still editable)
  • INVOICED → Invoiced (IMMUTABLE - moved to SettledCharge)
  • PAID → Paid directly without invoice
  • VOID → Cancelled

Allocation Configuration

Defines how charges are split between multiple accounts (e.g., divorced parents, subsidy agencies). Three rule types:

  • RESPONSIBLE_PARTY: Percentage-based split
  • COVERAGE_TRANSFER: Fixed amount covered (e.g., $25 subsidy per charge)
  • BILLING_CAP: Maximum amount per period

Double-Entry Ledger

All financial transactions follow the accounting equation (Debits = Credits). Journal entries are immutable once created - corrections use adjustment entries.

Monetary Values

All monetary amounts are stored as DECIMAL type in cents (e.g., 5000 = $50.00). Use DECIMAL or NUMERIC type (BigDecimal in Java) for precision and to avoid rounding errors. Never use integers or floating-point for money.

Languages
Servers
Mock server
https://docs.nelnetpay.com/_mock/apis/billing-ledger-service
UAT server
https://api.uat.nelnetpay.com/billing
Production server
https://api.nelnetpay.com/billing

Rates

Manage rate catalog (pricing for services)

Operations

RateCards

Manage rate card groupings for UI organization

Operations

Subscriptions

Manage billable entity subscriptions to rates

Operations

AllocationConfigurations

Manage charge allocation configurations for split billing

Operations

Charges

Manage billable charges (mutable pre-invoice state)

Operations

List Charges

Request

List charges (mutable pre-invoice state) for the authenticated merchant.

Status Filtering:

  • PENDING - Created but not validated
  • BILLED - Ready to invoice
  • VOID - Cancelled

Charges with status INVOICED or PAID are in the SettledCharges table.

Security
OAuth2
Query
statusstring

Filter by charge status

Enum"PENDING""BILLED""VOID"
billable_entity_idstring(uuid)

Filter by billable entity ID

account_idstring(uuid)

Filter by account ID

event_date_fromstring(date)

Filter charges with event date on or after this date

event_date_tostring(date)

Filter charges with event date on or before this date

pageinteger>= 1

Page number (1-indexed)

Default 1
Example: page=1
page_sizeinteger[ 1 .. 200 ]

Number of items per page

Default 50
Example: page_size=50
curl -i -X GET \
  'https://docs.nelnetpay.com/_mock/apis/billing-ledger-service/charges?status=PENDING&billable_entity_id=497f6eca-6276-4993-bfeb-53cbbbba6f08&account_id=497f6eca-6276-4993-bfeb-53cbbbba6f08&event_date_from=2019-08-24&event_date_to=2019-08-24&page=1&page_size=50' \
  -H 'Authorization: Bearer <YOUR_TOKEN_HERE>'

Responses

Successful response

Bodyapplication/json
resultsArray of objectsrequired
results[].​idstring(uuid)required
results[].​entityIdstring(uuid)required
results[].​billableEntityIdstring(uuid)required
results[].​accountIdstring(uuid)

Primary account for this charge (from allocation)

results[].​subscriptionIdstring or null(uuid)

Subscription that generated this charge (if any)

results[].​rateIdstring(uuid)required
results[].​quantitynumber(double)required
results[].​amountintegerrequired

Amount in cents BEFORE discounts

results[].​prorationFactornumber(double)

Proration factor (e.g., 0.5 for half month)

Default 1
results[].​proratedAmountinteger

Amount after proration (in cents)

results[].​netAmountintegerrequired

Final amount after discounts (in cents)

results[].​discountRateIdsArray of strings(uuid)
results[].​discountAmountsArray of integers

Discount amounts in cents (parallel to discountRateIds)

results[].​allocationConfigIdstring(uuid)required
results[].​overrideAllocationobject

Manual allocation override (optional)

results[].​statusstringrequired

Status of mutable charge

Enum"PENDING""BILLED""VOID"
results[].​eventDatestring(date)required

Date of the event that generated this charge

results[].​rateVersioninteger

Version of rate when charge was created

results[].​subscriptionVersioninteger

Version of subscription when charge was created

results[].​allocationVersioninteger

Version of allocation config when charge was created

results[].​discountRateVersionsArray of integers

Versions of discount rates when charge was created (parallel to discountRateIds)

results[].​tagsobject
results[].​optimisticLockVersioninteger(int64)read-only

Optimistic locking version (managed by Hibernate @Version). Prevents concurrent update conflicts.

results[].​createdAtstring(date-time)required
results[].​updatedAtstring(date-time)
paginationobjectrequired
pagination.​totalRecordsintegerrequired

Total number of records across all pages

Example: 100
pagination.​currentPageintegerrequired

Current page number (1-indexed)

Example: 1
pagination.​totalPagesintegerrequired

Total number of pages

Example: 10
pagination.​nextPageinteger or null

Next page number, null if on last page

Example: 2
pagination.​prevPageinteger or null

Previous page number, null if on first page

Example: null
Response
application/json
{ "results": [ {} ], "pagination": { "totalRecords": 100, "currentPage": 1, "totalPages": 10, "nextPage": 2, "prevPage": null } }

Create Charge

Request

Create a new charge for a billable entity.

Validation at Creation:

  1. Fetches all accounts associated with billableEntityId (via Profile Service)
  2. Validates billableEntity is associated with ALL accounts in allocationConfig
  3. Validates allocationConfig covers 100% of ALL accounts for the billableEntity
  4. Returns 422 if validation fails

Charge Calculation:

  • amount = quantity × rate.pricePerUnit
  • proratedAmount = amount × prorationFactor
  • netAmount = proratedAmount - sum(discountAmounts)

Idempotency: Include Idempotency-Key header to prevent duplicate charges.

Security
OAuth2
Headers
Idempotency-Keystring(uuid)

Unique key to ensure idempotent operations (UUID recommended)

Bodyapplication/jsonrequired
billableEntityIdstring(uuid)required
subscriptionIdstring(uuid)
rateIdstring(uuid)required
quantitynumber(double)>= 0required
prorationFactornumber(double)[ 0 .. 1 ]
Default 1
allocationConfigIdstring(uuid)required
discountRateIdsArray of strings(uuid)
overrideAllocationobject
eventDatestring(date)required
tagsobject
curl -i -X POST \
  https://docs.nelnetpay.com/_mock/apis/billing-ledger-service/charges \
  -H 'Authorization: Bearer <YOUR_TOKEN_HERE>' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: 497f6eca-6276-4993-bfeb-53cbbbba6f08' \
  -d '{
    "billableEntityId": "550e8400-e29b-41d4-a716-446655440010",
    "rateId": "550e8400-e29b-41d4-a716-446655440001",
    "quantity": 5,
    "allocationConfigId": "550e8400-e29b-41d4-a716-446655440020",
    "discountRateIds": [
      "550e8400-e29b-41d4-a716-446655440002"
    ],
    "eventDate": "2026-01-20"
  }'

Responses

Charge created successfully

Bodyapplication/json
idstring(uuid)required
entityIdstring(uuid)required
billableEntityIdstring(uuid)required
accountIdstring(uuid)

Primary account for this charge (from allocation)

subscriptionIdstring or null(uuid)

Subscription that generated this charge (if any)

rateIdstring(uuid)required
quantitynumber(double)required
amountintegerrequired

Amount in cents BEFORE discounts

prorationFactornumber(double)

Proration factor (e.g., 0.5 for half month)

Default 1
proratedAmountinteger

Amount after proration (in cents)

netAmountintegerrequired

Final amount after discounts (in cents)

discountRateIdsArray of strings(uuid)
discountAmountsArray of integers

Discount amounts in cents (parallel to discountRateIds)

allocationConfigIdstring(uuid)required
overrideAllocationobject

Manual allocation override (optional)

statusstringrequired

Status of mutable charge

Enum"PENDING""BILLED""VOID"
eventDatestring(date)required

Date of the event that generated this charge

rateVersioninteger

Version of rate when charge was created

subscriptionVersioninteger

Version of subscription when charge was created

allocationVersioninteger

Version of allocation config when charge was created

discountRateVersionsArray of integers

Versions of discount rates when charge was created (parallel to discountRateIds)

tagsobject
optimisticLockVersioninteger(int64)read-only

Optimistic locking version (managed by Hibernate @Version). Prevents concurrent update conflicts.

createdAtstring(date-time)required
updatedAtstring(date-time)
Response
application/json
{ "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "entityId": "156e622c-6cdf-4c27-9bc9-2f2db69919f5", "billableEntityId": "efd73805-0b19-4de3-9f1e-a64de8c44765", "accountId": "3d07c219-0a88-45be-9cfc-91e9d095a1e9", "subscriptionId": "d079718b-ff63-45dd-947b-4950c023750f", "rateId": "dc6263b0-e8fb-4144-a111-53fde6c86836", "quantity": 0.1, "amount": 0, "prorationFactor": 1, "proratedAmount": 0, "netAmount": 0, "discountRateIds": [ "497f6eca-6276-4993-bfeb-53cbbbba6f08" ], "discountAmounts": [ 0 ], "allocationConfigId": "dacda6b8-3e25-4031-b6a4-1ec5aa108ab2", "overrideAllocation": {}, "status": "PENDING", "eventDate": "2019-08-24", "rateVersion": 0, "subscriptionVersion": 0, "allocationVersion": 0, "discountRateVersions": [ 0 ], "tags": { "property1": "string", "property2": "string" }, "optimisticLockVersion": 0, "createdAt": "2019-08-24T14:15:22Z", "updatedAt": "2019-08-24T14:15:22Z" }

Get Charge Details

Request

Retrieve details of a specific charge

Security
OAuth2
Path
chargeIdstring(uuid)required

Unique identifier for the charge

curl -i -X GET \
  'https://docs.nelnetpay.com/_mock/apis/billing-ledger-service/charges/{chargeId}' \
  -H 'Authorization: Bearer <YOUR_TOKEN_HERE>'

Responses

Successful response

Bodyapplication/json
idstring(uuid)required
entityIdstring(uuid)required
billableEntityIdstring(uuid)required
accountIdstring(uuid)

Primary account for this charge (from allocation)

subscriptionIdstring or null(uuid)

Subscription that generated this charge (if any)

rateIdstring(uuid)required
quantitynumber(double)required
amountintegerrequired

Amount in cents BEFORE discounts

prorationFactornumber(double)

Proration factor (e.g., 0.5 for half month)

Default 1
proratedAmountinteger

Amount after proration (in cents)

netAmountintegerrequired

Final amount after discounts (in cents)

discountRateIdsArray of strings(uuid)
discountAmountsArray of integers

Discount amounts in cents (parallel to discountRateIds)

allocationConfigIdstring(uuid)required
overrideAllocationobject

Manual allocation override (optional)

statusstringrequired

Status of mutable charge

Enum"PENDING""BILLED""VOID"
eventDatestring(date)required

Date of the event that generated this charge

rateVersioninteger

Version of rate when charge was created

subscriptionVersioninteger

Version of subscription when charge was created

allocationVersioninteger

Version of allocation config when charge was created

discountRateVersionsArray of integers

Versions of discount rates when charge was created (parallel to discountRateIds)

tagsobject
optimisticLockVersioninteger(int64)read-only

Optimistic locking version (managed by Hibernate @Version). Prevents concurrent update conflicts.

createdAtstring(date-time)required
updatedAtstring(date-time)
Response
application/json
{ "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "entityId": "156e622c-6cdf-4c27-9bc9-2f2db69919f5", "billableEntityId": "efd73805-0b19-4de3-9f1e-a64de8c44765", "accountId": "3d07c219-0a88-45be-9cfc-91e9d095a1e9", "subscriptionId": "d079718b-ff63-45dd-947b-4950c023750f", "rateId": "dc6263b0-e8fb-4144-a111-53fde6c86836", "quantity": 0.1, "amount": 0, "prorationFactor": 1, "proratedAmount": 0, "netAmount": 0, "discountRateIds": [ "497f6eca-6276-4993-bfeb-53cbbbba6f08" ], "discountAmounts": [ 0 ], "allocationConfigId": "dacda6b8-3e25-4031-b6a4-1ec5aa108ab2", "overrideAllocation": {}, "status": "PENDING", "eventDate": "2019-08-24", "rateVersion": 0, "subscriptionVersion": 0, "allocationVersion": 0, "discountRateVersions": [ 0 ], "tags": { "property1": "string", "property2": "string" }, "optimisticLockVersion": 0, "createdAt": "2019-08-24T14:15:22Z", "updatedAt": "2019-08-24T14:15:22Z" }

Update Charge

Request

Update a charge (partial update).

Restrictions: Only charges with status PENDING or BILLED can be updated. Once a charge is INVOICED, it becomes immutable (moved to SettledCharges).

Security
OAuth2
Path
chargeIdstring(uuid)required

Unique identifier for the charge

Bodyapplication/jsonrequired
quantitynumber(double)>= 0
prorationFactornumber(double)[ 0 .. 1 ]
discountRateIdsArray of strings(uuid)
overrideAllocationobject
eventDatestring(date)
tagsobject
curl -i -X PATCH \
  'https://docs.nelnetpay.com/_mock/apis/billing-ledger-service/charges/{chargeId}' \
  -H 'Authorization: Bearer <YOUR_TOKEN_HERE>' \
  -H 'Content-Type: application/json' \
  -d '{
    "quantity": 0.1,
    "prorationFactor": 1,
    "discountRateIds": [
      "497f6eca-6276-4993-bfeb-53cbbbba6f08"
    ],
    "overrideAllocation": {},
    "eventDate": "2019-08-24",
    "tags": {
      "property1": "string",
      "property2": "string"
    }
  }'

Responses

Charge updated successfully

Bodyapplication/json
idstring(uuid)required
entityIdstring(uuid)required
billableEntityIdstring(uuid)required
accountIdstring(uuid)

Primary account for this charge (from allocation)

subscriptionIdstring or null(uuid)

Subscription that generated this charge (if any)

rateIdstring(uuid)required
quantitynumber(double)required
amountintegerrequired

Amount in cents BEFORE discounts

prorationFactornumber(double)

Proration factor (e.g., 0.5 for half month)

Default 1
proratedAmountinteger

Amount after proration (in cents)

netAmountintegerrequired

Final amount after discounts (in cents)

discountRateIdsArray of strings(uuid)
discountAmountsArray of integers

Discount amounts in cents (parallel to discountRateIds)

allocationConfigIdstring(uuid)required
overrideAllocationobject

Manual allocation override (optional)

statusstringrequired

Status of mutable charge

Enum"PENDING""BILLED""VOID"
eventDatestring(date)required

Date of the event that generated this charge

rateVersioninteger

Version of rate when charge was created

subscriptionVersioninteger

Version of subscription when charge was created

allocationVersioninteger

Version of allocation config when charge was created

discountRateVersionsArray of integers

Versions of discount rates when charge was created (parallel to discountRateIds)

tagsobject
optimisticLockVersioninteger(int64)read-only

Optimistic locking version (managed by Hibernate @Version). Prevents concurrent update conflicts.

createdAtstring(date-time)required
updatedAtstring(date-time)
Response
application/json
{ "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "entityId": "156e622c-6cdf-4c27-9bc9-2f2db69919f5", "billableEntityId": "efd73805-0b19-4de3-9f1e-a64de8c44765", "accountId": "3d07c219-0a88-45be-9cfc-91e9d095a1e9", "subscriptionId": "d079718b-ff63-45dd-947b-4950c023750f", "rateId": "dc6263b0-e8fb-4144-a111-53fde6c86836", "quantity": 0.1, "amount": 0, "prorationFactor": 1, "proratedAmount": 0, "netAmount": 0, "discountRateIds": [ "497f6eca-6276-4993-bfeb-53cbbbba6f08" ], "discountAmounts": [ 0 ], "allocationConfigId": "dacda6b8-3e25-4031-b6a4-1ec5aa108ab2", "overrideAllocation": {}, "status": "PENDING", "eventDate": "2019-08-24", "rateVersion": 0, "subscriptionVersion": 0, "allocationVersion": 0, "discountRateVersions": [ 0 ], "tags": { "property1": "string", "property2": "string" }, "optimisticLockVersion": 0, "createdAt": "2019-08-24T14:15:22Z", "updatedAt": "2019-08-24T14:15:22Z" }

Delete Charge

Request

Delete a charge (hard delete for PENDING, soft delete/void for BILLED).

Restrictions: Cannot delete charges with status INVOICED or PAID. Use ledger adjustments for corrections to invoiced charges.

Security
OAuth2
Path
chargeIdstring(uuid)required

Unique identifier for the charge

curl -i -X DELETE \
  'https://docs.nelnetpay.com/_mock/apis/billing-ledger-service/charges/{chargeId}' \
  -H 'Authorization: Bearer <YOUR_TOKEN_HERE>'

Responses

Charge deleted successfully

Response
No content

Void Charge

Request

Void a charge (sets status to VOID).

Use Case: When a charge was created in error but you want to keep audit trail.

Security
OAuth2
Path
chargeIdstring(uuid)required

Unique identifier for the charge

Bodyapplication/json
reasonstring

Reason for voiding the charge

curl -i -X POST \
  'https://docs.nelnetpay.com/_mock/apis/billing-ledger-service/charges/{chargeId}/void' \
  -H 'Authorization: Bearer <YOUR_TOKEN_HERE>' \
  -H 'Content-Type: application/json' \
  -d '{
    "reason": "string"
  }'

Responses

Charge voided successfully

Bodyapplication/json
idstring(uuid)required
entityIdstring(uuid)required
billableEntityIdstring(uuid)required
accountIdstring(uuid)

Primary account for this charge (from allocation)

subscriptionIdstring or null(uuid)

Subscription that generated this charge (if any)

rateIdstring(uuid)required
quantitynumber(double)required
amountintegerrequired

Amount in cents BEFORE discounts

prorationFactornumber(double)

Proration factor (e.g., 0.5 for half month)

Default 1
proratedAmountinteger

Amount after proration (in cents)

netAmountintegerrequired

Final amount after discounts (in cents)

discountRateIdsArray of strings(uuid)
discountAmountsArray of integers

Discount amounts in cents (parallel to discountRateIds)

allocationConfigIdstring(uuid)required
overrideAllocationobject

Manual allocation override (optional)

statusstringrequired

Status of mutable charge

Enum"PENDING""BILLED""VOID"
eventDatestring(date)required

Date of the event that generated this charge

rateVersioninteger

Version of rate when charge was created

subscriptionVersioninteger

Version of subscription when charge was created

allocationVersioninteger

Version of allocation config when charge was created

discountRateVersionsArray of integers

Versions of discount rates when charge was created (parallel to discountRateIds)

tagsobject
optimisticLockVersioninteger(int64)read-only

Optimistic locking version (managed by Hibernate @Version). Prevents concurrent update conflicts.

createdAtstring(date-time)required
updatedAtstring(date-time)
Response
application/json
{ "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "entityId": "156e622c-6cdf-4c27-9bc9-2f2db69919f5", "billableEntityId": "efd73805-0b19-4de3-9f1e-a64de8c44765", "accountId": "3d07c219-0a88-45be-9cfc-91e9d095a1e9", "subscriptionId": "d079718b-ff63-45dd-947b-4950c023750f", "rateId": "dc6263b0-e8fb-4144-a111-53fde6c86836", "quantity": 0.1, "amount": 0, "prorationFactor": 1, "proratedAmount": 0, "netAmount": 0, "discountRateIds": [ "497f6eca-6276-4993-bfeb-53cbbbba6f08" ], "discountAmounts": [ 0 ], "allocationConfigId": "dacda6b8-3e25-4031-b6a4-1ec5aa108ab2", "overrideAllocation": {}, "status": "PENDING", "eventDate": "2019-08-24", "rateVersion": 0, "subscriptionVersion": 0, "allocationVersion": 0, "discountRateVersions": [ 0 ], "tags": { "property1": "string", "property2": "string" }, "optimisticLockVersion": 0, "createdAt": "2019-08-24T14:15:22Z", "updatedAt": "2019-08-24T14:15:22Z" }

Create Multiple Charges

Request

Create multiple charges in a single request.

Use Case: Creating charges for multiple billable entities at once (e.g., batch from recurring billing).

Atomicity: All charges are created in a single transaction. If any fails, all are rolled back.

Security
OAuth2
Headers
Idempotency-Keystring(uuid)

Unique key to ensure idempotent operations (UUID recommended)

Bodyapplication/jsonrequired
chargesArray of objects<= 100 itemsrequired

Array of charges to create (max 100)

charges[].​billableEntityIdstring(uuid)required
charges[].​subscriptionIdstring(uuid)
charges[].​rateIdstring(uuid)required
charges[].​quantitynumber(double)>= 0required
charges[].​prorationFactornumber(double)[ 0 .. 1 ]
Default 1
charges[].​allocationConfigIdstring(uuid)required
charges[].​discountRateIdsArray of strings(uuid)
charges[].​overrideAllocationobject
charges[].​eventDatestring(date)required
charges[].​tagsobject
curl -i -X POST \
  https://docs.nelnetpay.com/_mock/apis/billing-ledger-service/charges/bulk \
  -H 'Authorization: Bearer <YOUR_TOKEN_HERE>' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: 497f6eca-6276-4993-bfeb-53cbbbba6f08' \
  -d '{
    "charges": [
      {
        "billableEntityId": "efd73805-0b19-4de3-9f1e-a64de8c44765",
        "subscriptionId": "d079718b-ff63-45dd-947b-4950c023750f",
        "rateId": "dc6263b0-e8fb-4144-a111-53fde6c86836",
        "quantity": 0.1,
        "prorationFactor": 1,
        "allocationConfigId": "dacda6b8-3e25-4031-b6a4-1ec5aa108ab2",
        "discountRateIds": [
          "497f6eca-6276-4993-bfeb-53cbbbba6f08"
        ],
        "overrideAllocation": {},
        "eventDate": "2019-08-24",
        "tags": {
          "property1": "string",
          "property2": "string"
        }
      }
    ]
  }'

Responses

All charges created successfully

Bodyapplication/json
dataArray of objects
createdinteger

Number of charges created

Response
application/json
{ "data": [ {} ], "created": 0 }

SettledCharges

Query settled charges (immutable post-invoice state)

Operations

Refunds

Manage refunds for invoices, charges, or standalone refunds

Operations

Adjustments

Manage manual adjustments and corrections

Operations

Ledger

Manage double-entry accounting ledger

Operations
Webhooks

Exports

Export data in CSV format for GL integrations

Operations