Dry Run ignores account Billing Cycle Day (BCD) and uses startDate as period anchor, producing incorrect proration

16 views
Skip to first unread message

Julia Nunes

unread,
May 15, 2026, 1:47:34 PMMay 15
to Kill Bill users mailing-list

Summary: When calling POST /1.0/kb/invoices/dryRun with dryRunType: SUBSCRIPTION_ACTION and dryRunAction: START_BILLING, KillBill calculates the invoice item period starting from the startDate instead of aligning to the account's configured Billing Cycle Day (BCD). The real billing engine aligns correctly to the BCD — the dry run does not replicate this behavior, producing an incorrect prorated amount.

Expected: Period from 2026-05-15 to the next BCD date (e.g. 2026-05-20 if BCD = 20), prorated accordingly. Actual: Period returned is 2026-05-15 → 2026-06-14 (startDate + 30 days), BCD is completely ignored. Amount: 12,765 CLP instead of the correct prorated value.

Account ID: 41f01d55-82d8-4314-999a-1cdf74ab09d3 Bundle ID: 93f8fbac-2ca5-4dbc-a79f-1735aa4e96e7 Product: CDFHD_Chile_001 (ADD_ON) | Billing policy: IMMEDIATE | Env: bss-prd.directvgo.com

Root cause hypothesis: The dry run path does not read the account BCD when computing the cycle anchor — it falls back to startDate directly, bypassing the BCD alignment logic used in the actual invoicing engine.

Impact: Checkout flows that rely on dry run for billing preview show an incorrect amount to the customer, creating a discrepancy with what is actually charged.



curl --location 'https://killbill.bss-prd.directvgo.com/1.0/kb/invoices/dryRun?accountId=41f01d55-82d8-4314-999a-1cdf74ab09d3' \
--header 'X-Killbill-CreatedBy: <string>' \
--header 'X-Killbill-Reason: <string>' \
--header 'X-Killbill-Comment: <string>' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'Authorization: Basic bWlkZGxld2FyZS5jbDoyOy0nMzkjc35CR0EqX2hHLikwaw==' \
--data '{
  "dryRunType": "SUBSCRIPTION_ACTION",
  "dryRunAction": "START_BILLING",
  "phaseType": "EVERGREEN",
  "bundleId":"93f8fbac-2ca5-4dbc-a79f-1735aa4e96e7",
  "billingPeriod": "MONTHLY",
  "productName": "CDFHD_Chile_001",
  "productCategory": "ADD_ON",
  "billingPolicy": "IMMEDIATE",
    "priceOverrides": [
        {
        "phaseType": "EVERGREEN",
        "recurringPrice": 13190
        }
    ]  
}'


{
    "amount": 12765,
    "currency": "CLP",
    "status": "COMMITTED",
    "creditAdj": 0,
    "refundAdj": 0,
    "invoiceId": "b43e6f82-a263-4a88-bac8-cb74857996e6",
    "invoiceDate": "2026-05-15",
    "targetDate": "2026-05-15",
    "invoiceNumber": null,
    "balance": 12765,
    "accountId": "41f01d55-82d8-4314-999a-1cdf74ab09d3",
    "bundleKeys": null,
    "credits": null,
    "items": [
        {
            "invoiceItemId": "c41eb4fa-f2b7-42b5-9921-7089bcf822db",
            "invoiceId": "b43e6f82-a263-4a88-bac8-cb74857996e6",
            "linkedInvoiceItemId": null,
            "accountId": "41f01d55-82d8-4314-999a-1cdf74ab09d3",
            "childAccountId": null,
            "bundleId": "93f8fbac-2ca5-4dbc-a79f-1735aa4e96e7",
            "subscriptionId": "849d4ebd-25ed-4b33-aaff-36521ad6fc72",
            "productName": "CDFHD_Chile_001",
            "planName": "PL_CDFHD_Chile_001-dryrun-1024",
            "phaseName": "PL_CDFHD_Chile_001-dryrun-1024-evergreen",
            "usageName": null,
            "prettyProductName": null,
            "prettyPlanName": null,
            "prettyPhaseName": null,
            "prettyUsageName": null,
            "itemType": "RECURRING",
            "description": "PL_CDFHD_Chile_001-dryrun-1024-evergreen",
            "startDate": "2026-05-15",
            "endDate": "2026-06-14",
            "amount": 12765,
            "rate": 13190,
            "currency": "CLP",
            "quantity": null,
            "itemDetails": null,
            "catalogEffectiveDate": "2026-05-14T15:11:21.000Z",
            "childItems": null,
            "auditLogs": []
        }
    ],
    "trackingIds": [],
    "isParentInvoice": false,
    "parentInvoiceId": null,
    "parentAccountId": null,
    "auditLogs": []
}



karan bansal

unread,
May 18, 2026, 5:23:56 AMMay 18
to Kill Bill users mailing-list
Hi Julia,

I ran a few tests locally to reproduce the behavior that you described, but the results showed that BCD is honored in all scenarios. 

Could you please provide me the below information : 

1) Use this endpoint for the respective account and retrieve the billCycleDayLocal

2) The catalog's <billingAlignment> rule for product category ADD_ON (or for CDFHD_Chile_001 specifically)

3) Use this endpoint for the respective bundle id and check when the base subscription started. 

Regards
Karan

Julia Nunes

unread,
May 19, 2026, 11:29:38 PMMay 19
to Kill Bill users mailing-list


###### CREATE ACCOUNT ######

curl--location 'https://127.0.0.1:8080/1.0/kb/accounts' \
--header 'accept: application/json' \
--header 'X-Killbill-CreatedBy: bfb-ms-bss-customer-subscription' \
--header 'X-Killbill-ApiKey: ARGENTINA' \
--header 'X-Killbill-ApiSecret: ARGENTINA' \
--header 'Content-Type: application/json' \
--header 'Authorization: ••••••' \
--data - raw '{
  "name": "Gerald Prosacco",
  "firstNameLength": "5",
  "email": "Dami...@example.org",
  "currency": "ARS",
  "timeZone": "Etc/UCT",
  "address1": "R Teste",
  "address2": "",
  "postalCode": "00000-000",
  "city": "Bs Aires",
  "state": "SP",
  "country": "AR",
  "locale": "pt_BR",
  "phone": "(11) 90000-0000",
  "notes": "Create automated account - pt_BR"
}'


##### ADD DEFAULT PAYMENT METHOD #####

curl --location 'https://127.0.0.1:8080/1.0/kb/accounts/4c13f450-6363-4da8-8ba7-9aa840e49372/paymentMethods?isDefault=true&payAllUnpaidInvoices=false' \
--header 'accept: application/json' \
--header 'X-Killbill-CreatedBy: bfb-ms-bss-customer-subscription' \
--header 'X-Killbill-ApiKey: ARGENTINA' \
--header 'X-Killbill-ApiSecret: ARGENTINA' \
--header 'Content-Type: application/json' \
--header 'Authorization: ••••••' \
--data '{
  "pluginName": "__EXTERNAL_PAYMENT__",
  "pluginInfo": {
    "properties": [
    ]
  }
}'


#### CREATE SUBSCRIPTION ####

curl --location 'https://127.0.0.1:8080/1.0/kb/accounts/4c13f450-6363-4da8-8ba7-9aa840e49372/paymentMethods?isDefault=true&payAllUnpaidInvoices=false' \
--header 'accept: application/json' \
--header 'X-Killbill-CreatedBy: bfb-ms-bss-customer-subscription' \
--header 'X-Killbill-ApiKey: ARGENTINA' \
--header 'X-Killbill-ApiSecret: ARGENTINA' \
--header 'Content-Type: application/json' \
--data '{
  "pluginName": "__EXTERNAL_PAYMENT__",
  "pluginInfo": {
    "properties": [
    ]
  }
}'


#### CREATE SUBSCRIPTION ####

curl --location 'https://127.0.0.1:8080/1.0/kb/subscriptions' \
--header 'accept: application/json' \
--header 'X-Killbill-CreatedBy: bfb-ms-bss-customer-subscription' \
--header 'X-Killbill-ApiKey: ARGENTINA' \
--header 'X-Killbill-ApiSecret: ARGENTINA' \
--header 'Content-Type: application/json' \
--header 'Authorization: ••••••' \
--data '{
    "accountId": "4c13f450-6363-4da8-8ba7-9aa840e49372",
    "phaseType": "EVERGREEN",
    "planName": "PL_DTVGO_AR_LITE"
}'


#### UPDATE BCD #####

curl --location --request PUT 'https://127.0.0.1:8080/1.0/kb/subscriptions/512e8f20-c7df-4e9b-a69c-c40cc9212bfa/bcd' \
--header 'accept: application/json' \
--header 'X-Killbill-CreatedBy: bfb-ms-bss-customer-subscription' \
--header 'X-Killbill-ApiKey: ARGENTINA' \
--header 'X-Killbill-ApiSecret: ARGENTINA' \
--header 'Content-Type: application/json' \
--header 'Authorization: ••••••' \
--data '{ "billCycleDayLocal": 3 }'


### DRYRUN  ADD ON ###

curl --location 'https://127.0.0.1:8080/1.0/kb/invoices/dryRun?accountId=4c13f450-6363-4da8-8ba7-9aa840e49372' \
--header 'accept: application/json' \
--header 'X-Killbill-CreatedBy: bfb-ms-bss-customer-subscription' \
--header 'X-Killbill-ApiKey: ARGENTINA' \
--header 'X-Killbill-ApiSecret: ARGENTINA' \
--header 'Content-Type: application/json' \
--header 'Authorization: ••••••' \

--data '{
  "dryRunType": "SUBSCRIPTION_ACTION",
  "dryRunAction": "START_BILLING",
  "phaseType": "EVERGREEN",
  "bundleId":"180bc842-3464-410f-b8d5-a993ce48a688",
  "billingPeriod": "MONTHLY",
  "productName": "AR_HBO_OTT",

  "productCategory": "ADD_ON",
  "billingPolicy": "IMMEDIATE",
    "priceOverrides": [
        {
        "phaseType": "EVERGREEN",
        "recurringPrice": 9200
        }
    ]  
}'

RESPONSE

{
    "amount": 4451.61,
    "currency": "ARS",
    "status": "COMMITTED",
    "creditAdj": 0.00,
    "refundAdj": 0.00,
    "invoiceId": "fdefcf7d-3750-474a-8a26-e446e26003f5",
    "invoiceDate": "2026-06-04",
    "targetDate": "2026-06-04",
    "invoiceNumber": null,
    "balance": 4451.61,
    "accountId": "4c13f450-6363-4da8-8ba7-9aa840e49372",

    "bundleKeys": null,
    "credits": null,
    "items": [
        {
            "invoiceItemId": "6c63e0c3-246d-40cb-af68-009b44ba2658",
            "invoiceId": "fdefcf7d-3750-474a-8a26-e446e26003f5",
            "linkedInvoiceItemId": null,
            "accountId": "4c13f450-6363-4da8-8ba7-9aa840e49372",
            "childAccountId": null,
            "bundleId": "180bc842-3464-410f-b8d5-a993ce48a688",
            "subscriptionId": "0b07088e-dfa0-46d4-884e-bd5d0dec5b27",
            "productName": "AR_HBO_OTT",
            "planName": "PL_AR_HBO_OTT-dryrun-6",
            "phaseName": "PL_AR_HBO_OTT-dryrun-6-evergreen",

            "usageName": null,
            "prettyProductName": null,
            "prettyPlanName": null,
            "prettyPhaseName": null,
            "prettyUsageName": null,
            "itemType": "RECURRING",
            "description": "PL_AR_HBO_OTT-dryrun-6-evergreen",
            "startDate": "2026-06-04",
            "endDate": "2026-06-19",
            "amount": 4451.61,
            "rate": 9200,
            "currency": "ARS",
            "quantity": null,
            "itemDetails": null,
            "catalogEffectiveDate": "2025-06-26T02:00:25.000Z",

            "childItems": null,
            "auditLogs": []
        }
    ],
    "trackingIds": [],
    "isParentInvoice": false,
    "parentInvoiceId": null,
    "parentAccountId": null,
    "auditLogs": []
}

##### DRYRUN CHANGE ######

curl --location 'https://127.0.0.1:8080/1.0/kb/invoices/dryRun?accountId=4c13f450-6363-4da8-8ba7-9aa840e49372' \
--header 'accept: application/json' \
--header 'X-Killbill-CreatedBy: bfb-ms-bss-customer-subscription' \
--header 'X-Killbill-ApiKey: ARGENTINA' \
--header 'X-Killbill-ApiSecret: ARGENTINA' \
--header 'Content-Type: application/json' \
--header 'Authorization: ••••••' \
--data '{
  "dryRunType": "SUBSCRIPTION_ACTION",
  "dryRunAction": "CHANGE",
  "phaseType": "EVERGREEN",
  "bundleId":"180bc842-3464-410f-b8d5-a993ce48a688",
  "subscriptionId":"512e8f20-c7df-4e9b-a69c-c40cc9212bfa",
  "planName": "PL_PLAN_PRO",

  "billingPolicy": "IMMEDIATE",
    "priceOverrides": [
        {
        "phaseType": "EVERGREEN",
        "recurringPrice": 80000
        }
    ]  
}'

RESPONSE

{
    "amount": 59083.01,
    "currency": "ARS",
    "status": "COMMITTED",
    "creditAdj": 0.00,
    "refundAdj": 0.00,
    "invoiceId": "7130cd69-15b2-4d79-bd62-8be78fe2f714",
    "invoiceDate": "2026-06-04",
    "targetDate": "2026-06-04",
    "invoiceNumber": null,
    "balance": 59083.01,
    "accountId": "4c13f450-6363-4da8-8ba7-9aa840e49372",

    "bundleKeys": null,
    "credits": null,
    "items": [
        {
            "invoiceItemId": "edd81e02-8f76-4953-b137-2235f51602dc",
            "invoiceId": "7130cd69-15b2-4d79-bd62-8be78fe2f714",
            "linkedInvoiceItemId": null,
            "accountId": "4c13f450-6363-4da8-8ba7-9aa840e49372",
            "childAccountId": null,
            "bundleId": "180bc842-3464-410f-b8d5-a993ce48a688",
            "subscriptionId": "512e8f20-c7df-4e9b-a69c-c40cc9212bfa",
            "productName": "PLAN_PRO",
            "planName": "PL_PLAN_PRO-dryrun-8",
            "phaseName": "PL_PLAN_PRO-dryrun-8-evergreen",

            "usageName": null,
            "prettyProductName": null,
            "prettyPlanName": null,
            "prettyPhaseName": null,
            "prettyUsageName": null,
            "itemType": "RECURRING",
            "description": "PL_PLAN_PRO-dryrun-8-evergreen",
            "startDate": "2026-06-04",
            "endDate": "2026-07-03",
            "amount": 77333.33,
            "rate": 80000,
            "currency": "ARS",
            "quantity": null,
            "itemDetails": null,
            "catalogEffectiveDate": "2025-06-26T02:00:25.000Z",
            "childItems": null,
            "auditLogs": []
        },
        {
            "invoiceItemId": "64eafa87-b90e-464a-89bb-5bd0dd9e4025",
            "invoiceId": "7130cd69-15b2-4d79-bd62-8be78fe2f714",
            "linkedInvoiceItemId": "3f047a32-5428-4ad9-a13f-b5db21705fcf",
            "accountId": "4c13f450-6363-4da8-8ba7-9aa840e49372",
            "childAccountId": null,
            "bundleId": null,
            "subscriptionId": null,
            "productName": null,
            "planName": null,
            "phaseName": null,

            "usageName": null,
            "prettyProductName": null,
            "prettyPlanName": null,
            "prettyPhaseName": null,
            "prettyUsageName": null,
            "itemType": "REPAIR_ADJ",
            "description": "Adjustment (subscription change)",
            "startDate": "2026-06-04",
            "endDate": "2026-06-19",
            "amount": -9290.32,
            "rate": null,
            "currency": "ARS",
            "quantity": null,
            "itemDetails": null,
            "catalogEffectiveDate": null,
            "childItems": null,
            "auditLogs": []
        },
        {
            "invoiceItemId": "17467c97-2a2f-4163-930d-9881d53ff847",
            "invoiceId": "7130cd69-15b2-4d79-bd62-8be78fe2f714",
            "linkedInvoiceItemId": "b9ba490b-45ae-4ea3-b6ff-2cb08da028ab",
            "accountId": "4c13f450-6363-4da8-8ba7-9aa840e49372",
            "childAccountId": null,
            "bundleId": null,
            "subscriptionId": null,
            "productName": null,
            "planName": null,
            "phaseName": null,

            "usageName": null,
            "prettyProductName": null,
            "prettyPlanName": null,
            "prettyPhaseName": null,
            "prettyUsageName": null,
            "itemType": "REPAIR_ADJ",
            "description": "Adjustment (subscription change)",
            "startDate": "2026-06-19",
            "endDate": "2026-07-03",
            "amount": -8960.00,
            "rate": null,
            "currency": "ARS",
            "quantity": null,
            "itemDetails": null,
            "catalogEffectiveDate": null,

karan bansal

unread,
May 20, 2026, 3:08:20 AMMay 20
to Kill Bill users mailing-list
Hi Julia,

Thank you for sending these details. I tried running both scenarios ( Chile-001 and Argentina ) per my understanding of the steps and dates to compare the dry run vs actual invoice. Below are the steps and results for each test. Please do review these and let me know if I need to set something differently. 

Case 1: Chile-001

Steps : 

Create a fresh tenant and account with currency CLP, no explicit BCD
Set clock to May 14, 2026
Create a base subscription (DTVGO_Chile, MONTHLY, 10,000 CLP)
Because the subscription starts on May 14, Kill Bill auto-sets the account BCD = 14
Advance clock to May 15, 2026
Run dry run: SUBSCRIPTION_ACTION / START_BILLING for CDFHD_Chile_001 (ADD_ON), rate 13,190 CLP, MONTHLY, IMMEDIATE
Create the real ADD_ON subscription with the same parameters
Compare dry run result vs real invoice

Actual outcome : 

Dry run: May 15 → June 14, amount 12,765 CLP — matches your numbers exactly
Real invoice: May 15 → June 14, amount 12,765 CLP — same as dry run

Case 2: Argentina

Steps : 

Create a fresh tenant and account with currency ARS, no explicit BCD
Set clock to May 19, 2026
Create a base subscription (DTVGO_AR, MONTHLY, 10,000 ARS)
Account BCD auto-set to 19
Call PUT /subscriptions/{id}/bcd with { "billCycleDayLocal": 3 } — override subscription BCD to 3
Check account BCD — it's still 19 (unchanged)
Advance clock to June 4, 2026
Run dry run: SUBSCRIPTION_ACTION / START_BILLING for AR_HBO_OTT (ADD_ON), rate 9,200 ARS, MONTHLY, IMMEDIATE
Create the real ADD_ON subscription with the same parameters
Compare dry run result vs real invoice

Actual outcome : 

Account BCD after override: still 19 (the override only changed the subscription, not the account)
Dry run: June 4 → June 19, amount 4,451.61 ARS — matches your email numbers exactly
Real invoice: June 4 → June 19, amount 4,451.61 ARS — same as dry run

Case 3: This test basically checks what would happen if I set Account BCD prior to any subscription

Steps : 

Create a fresh tenant
Set clock to May 14, 2026
Create an account with currency CLP and explicitly set billCycleDayLocal: 20 in the account creation request. Account BCD is now 20 (set before any subscription exists)
Create a base subscription on May 14 — account BCD stays 20 (not overwritten)
Advance clock to May 15, 2026
Run dry run: SUBSCRIPTION_ACTION / START_BILLING for CDFHD_Chile_001 (ADD_ON), rate 13,190 CLP, MONTHLY, IMMEDIATE — same parameters as your Chile request
Create the real ADD_ON subscription with the same parameters
Compare dry run result vs real invoice

Actual outcome : 

Account BCD: 20 (confirmed)
Dry run: May 15 → May 20, amount 2,198 CLP
Real invoice: May 15 → May 20, amount 2,198 CLP

Regards
Karan
Reply all
Reply to author
Forward
0 new messages