# Social media module: database proposal 4 (usage pricing)

For db-admin. Additive only: two nullable columns on `social_api_usage` (proposal 3), no new table, no index change. Nothing here has been executed; datahandler-dev does not run DDL. Written by `Model\Social\Usage\Meter` (via `Usage\RateCard`), read by `Model\Social\Service\UsageService` and the `SocialUsageReport` cron.

## Why

X bills pay-per-use with unit prices that differ by more than 100x across calls (a post with a link is $0.20, a plain post $0.015, reading your own post back $0.001). Splitting X's monthly invoice pro rata by call count would be wrong, so each ledger row now carries what the platform lists for that call at the time it was made.

## ALTER

```sql
ALTER TABLE `social_api_usage`
  ADD COLUMN `charge` VARCHAR(48)    NULL AFTER `billable`,
  ADD COLUMN `price`  DECIMAL(10,6)  NULL AFTER `charge`;
```

| column | meaning |
|---|---|
| `charge` | the rate-card entry the call was classified as (X: `post_create`, `post_create_url`, `post_delete`, `post_read`, `user_read`, `media_upload`, `token`); NULL when the card has no entry for the call |
| `price` | USD list price of the call when it was made; `0.000000` when the charge is known but the call failed (non-2xx); NULL when unpriced |

Existing rows stay NULL (unpriced). The ledger had no rows of consequence before this change (0 since the table was created), so no backfill.

## Until the columns exist

With the code deployed first, every insert fails (unknown column), `Meter::record` catches it and logs one line per call, and the call itself still goes through. Deploy after the ALTER, or accept the log noise in between; nothing is lost either way except the rows written in the gap.
