---
title: "Run Phone Billing Endpoint"
method: POST
path: "/internal/run-phone-billing"
tags: ["Internal", "Internal"]
---

# Run Phone Billing Endpoint

`POST /internal/run-phone-billing`

## Request

- Base URL: `https://api.call2me.app`
- URL: `https://api.call2me.app/internal/run-phone-billing`
- Auth: HTTP bearer

Run monthly recurring billing for phone numbers.

Intended to run daily via Cloud Scheduler. The logic is idempotent per day
(already-charged numbers skip). Handles the full lifecycle:

  1. Numbers where next_billing_at <= NOW() and status='active' without grace:
     - Try to deduct monthly_price_usd from wallet.
     - Success: advance next_billing_at +30d, log 'charged'.
     - Fail (insufficient balance): start 10-day grace, suspend_at=+3d,
       send warning email.

  2. Numbers in grace (grace_ends_at IS NOT NULL) not yet released:
     - Retry charge every day. Success → reactivate (clear grace, advance
       next_billing_at, send reactivation email).
     - If suspended_at passed and status='active': flip to 'suspended',
       send suspended email.

  3. Numbers where grace_ends_at <= NOW() and still unpaid:
     - Release at the carrier that holds it (Telnyx or Twilio), mark
       phone_numbers.status='inactive', send released email.

Scope: provider IN ('telnyx', 'twilio') — the carriers we rent from and
resell. `sip` and `netgsm` rows are deliberately out of scope: it is not
established that we carry a monthly cost for those, and several look like
customer-supplied trunks, where charging rent would be wrong.

## Headers

- `x-internal-key` string, nullable

## Response `200`

Successful Response

- unknown

## Other responses

- `422`: Validation Error

---

[API](https://skmtc.dev/call2me/apis/call2me-api.md) · [All operations](https://skmtc.dev/call2me/apis/call2me-api/llms.txt) · [OpenAPI document](https://skmtc.dev/call2me/apis/call2me-api/revisions/3951f9b7e47d?raw)
