{
  "_readme": [
    "Expense events use the same endpoint and the same shape as sales, with",
    "type 'expense'. They net against income per source, which is what makes",
    "the per-source profit and loss chart meaningful.",
    "",
    "POST https://api.crmsolid.com/public/v1/revenue/events",
    "Authorization: Bearer rsk_live_…",
    "",
    "Amounts are positive. The type field, not the sign, decides direction."
  ],
  "examples": [
    {
      "_case": "Daily ad spend, pushed once per day by a scheduled job",
      "externalId": "adspend-google-2026-08-31",
      "type": "expense",
      "amount": 184.2,
      "currency": "USD",
      "occurredAt": "2026-08-31T23:59:00Z",
      "category": "Ads and marketing",
      "description": "Google Ads spend, 31 Aug",
      "metadata": {
        "platform": "google-ads",
        "campaign": "brand-defense"
      }
    },
    {
      "_case": "Shipping cost tied to a specific order, so it nets against that sale",
      "externalId": "shipping-order-2026-000481",
      "type": "expense",
      "amount": 12.4,
      "currency": "USD",
      "occurredAt": "2026-08-31T16:05:00Z",
      "category": "Shipping",
      "description": "Courier, order 000481",
      "relatedExternalId": "order-2026-000481"
    },
    {
      "_case": "Refund. A negative sale, not an expense - it reverses the original income.",
      "externalId": "order-2026-000481",
      "type": "sale",
      "amount": -149.9,
      "currency": "USD",
      "occurredAt": "2026-09-03T10:11:00Z",
      "status": "refunded",
      "_note": "Reusing the original externalId updates the existing event to refunded. Use a NEW externalId only for a partial refund, so both rows survive."
    },
    {
      "_case": "Partial refund, which needs its own id so the original stays intact",
      "externalId": "refund-order-2026-000481-partial",
      "type": "sale",
      "amount": -50.0,
      "currency": "USD",
      "occurredAt": "2026-09-03T10:12:00Z",
      "status": "refunded",
      "relatedExternalId": "order-2026-000481"
    },
    {
      "_case": "Monthly platform fee, posted by a recurring job",
      "externalId": "platform-fee-2026-08",
      "type": "expense",
      "amount": 79.0,
      "currency": "USD",
      "occurredAt": "2026-08-31T00:00:00Z",
      "category": "Software and SaaS",
      "description": "Storefront platform fee, August"
    }
  ],
  "_gotchas": [
    "Post expenses with the SAME rsk_ key as the sales for that source, or the",
    "profit and loss chart will show income with no costs against it.",
    "occurredAt decides which day the expense lands on, not the time you posted it.",
    "Rejected events appear in the sync log with the validation error. Read it there",
    "rather than guessing - the most common cause is amount sent as a string."
  ]
}
