@ingenx-io/valets-schema-mcp-server 0.2.6 → 0.2.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/data/docs/collections/firestore-paths.md +20 -0
  2. package/data/docs/enums/app-status.md +1 -1
  3. package/data/docs/enums/attention-status.md +1 -1
  4. package/data/docs/enums/booking-status.md +1 -1
  5. package/data/docs/enums/contract-status.md +1 -1
  6. package/data/docs/enums/customer-payment-status.md +1 -1
  7. package/data/docs/enums/customer-payment-target-type.md +1 -1
  8. package/data/docs/enums/delivery-type.md +1 -1
  9. package/data/docs/enums/deployment-link-type.md +1 -1
  10. package/data/docs/enums/event-status.md +1 -1
  11. package/data/docs/enums/expense-payment-status.md +24 -0
  12. package/data/docs/enums/fulfillment-status.md +2 -2
  13. package/data/docs/enums/loyalty-transaction-type.md +2 -2
  14. package/data/docs/enums/milestone-status.md +2 -2
  15. package/data/docs/enums/notification-channel.md +2 -2
  16. package/data/docs/enums/notification-entity-type.md +2 -2
  17. package/data/docs/enums/notification-status.md +2 -2
  18. package/data/docs/enums/order-status.md +2 -2
  19. package/data/docs/enums/outbound-message-format.md +2 -2
  20. package/data/docs/enums/outbound-message-purpose.md +2 -2
  21. package/data/docs/enums/outbound-message-status.md +2 -2
  22. package/data/docs/enums/payment-method.md +4 -3
  23. package/data/docs/enums/payment-proof-status.md +2 -2
  24. package/data/docs/enums/payment-status.md +2 -2
  25. package/data/docs/enums/pending-issue.md +2 -2
  26. package/data/docs/enums/return-status.md +2 -2
  27. package/data/docs/enums/session-status.md +2 -2
  28. package/data/docs/enums/site-status.md +2 -2
  29. package/data/docs/enums/stocktake-frequency.md +2 -2
  30. package/data/docs/enums/stocktake-item-status.md +2 -2
  31. package/data/docs/enums/stocktake-status.md +2 -2
  32. package/data/docs/enums/ticket-status.md +2 -2
  33. package/data/docs/enums/waba-label.md +2 -2
  34. package/data/docs/enums/whatsapp-button-sub-type.md +2 -2
  35. package/data/docs/enums/whatsapp-template-component.md +2 -2
  36. package/data/docs/enums/whatsapp-template-status.md +2 -2
  37. package/data/docs/index.md +8 -5
  38. package/data/docs/models/allowed-user.md +1 -1
  39. package/data/docs/models/analytics-backfill.md +1 -1
  40. package/data/docs/models/analytics-daily.md +1 -1
  41. package/data/docs/models/analytics-event.md +1 -1
  42. package/data/docs/models/analytics-hourly.md +1 -1
  43. package/data/docs/models/app-payment.md +1 -1
  44. package/data/docs/models/app.md +1 -1
  45. package/data/docs/models/booking-version.md +1 -1
  46. package/data/docs/models/booking.md +1 -1
  47. package/data/docs/models/contract.md +1 -1
  48. package/data/docs/models/customer-payment-allocation.md +1 -1
  49. package/data/docs/models/customer-payment.md +22 -21
  50. package/data/docs/models/customer.md +1 -1
  51. package/data/docs/models/event.md +1 -1
  52. package/data/docs/models/expense.md +434 -0
  53. package/data/docs/models/loyalty-config.md +2 -2
  54. package/data/docs/models/loyalty-reward.md +2 -2
  55. package/data/docs/models/loyalty-status.md +2 -2
  56. package/data/docs/models/loyalty-transaction.md +2 -2
  57. package/data/docs/models/magic-link-request.md +2 -2
  58. package/data/docs/models/metrics-current.md +22 -2
  59. package/data/docs/models/metrics-daily.md +92 -41
  60. package/data/docs/models/metrics-monthly.md +22 -2
  61. package/data/docs/models/notification-record.md +68 -35
  62. package/data/docs/models/order-item.md +2 -2
  63. package/data/docs/models/order.md +56 -55
  64. package/data/docs/models/outbound-payment-allocation.md +2 -2
  65. package/data/docs/models/outbound-payment.md +3 -2
  66. package/data/docs/models/payment-webhook-delivery.md +321 -0
  67. package/data/docs/models/payment-webhook-endpoint.md +2 -2
  68. package/data/docs/models/sale.md +2 -2
  69. package/data/docs/models/site-payment.md +2 -2
  70. package/data/docs/models/site.md +2 -2
  71. package/data/docs/models/stocktake-item.md +2 -2
  72. package/data/docs/models/stocktake.md +2 -2
  73. package/data/docs/models/ticket.md +2 -2
  74. package/data/docs/models/user.md +2 -2
  75. package/data/docs/models/whatsapp-inbound-message.md +42 -18
  76. package/data/docs/models/whatsapp-outbound-lifecycle-event.md +2 -2
  77. package/data/docs/models/whatsapp-outbound-message.md +56 -32
  78. package/data/docs/models/whatsapp-template.md +2 -2
  79. package/data/static/llms.txt +110 -11
  80. package/data/static/openapi.yaml +444 -15
  81. package/data/static/schemas.json +394 -13
  82. package/package.json +1 -1
@@ -109,6 +109,15 @@ components:
109
109
  - COMPLETED
110
110
  description: Ticketed event lifecycle (D32). Mobile-only today; Dashboard in
111
111
  Wave 4.
112
+ ExpensePaymentStatus:
113
+ type: string
114
+ enum:
115
+ - PENDING
116
+ - PARTIALLY_PAID
117
+ - PAID
118
+ - FAILED
119
+ description: Payment status of an Expense. Stored enum — OVERDUE is not stored,
120
+ it is derived at read time from dueDate (#13).
112
121
  FulfillmentStatus:
113
122
  type: string
114
123
  enum:
@@ -222,7 +231,11 @@ components:
222
231
  - PAYPAL
223
232
  - STRIPE
224
233
  - OTHER
225
- description: Unified payment method set with African + global methods (D02).
234
+ - OM
235
+ description: 'Unified payment method set with African + global methods (D02).
236
+ Note: the metrics writer historically emits "OM" instead of "ORANGE_MONEY"
237
+ as a paymentsByMethod map key — treat OM as deprecated; canonical value is
238
+ ORANGE_MONEY (#21).'
226
239
  PaymentProofStatus:
227
240
  type: string
228
241
  enum:
@@ -2223,7 +2236,10 @@ components:
2223
2236
  notes (#10).'
2224
2237
  paymentMethod:
2225
2238
  $ref: '#/components/schemas/PaymentMethod'
2226
- description: Unified payment method set with African + global methods (D02).
2239
+ description: 'Unified payment method set with African + global methods (D02).
2240
+ Note: the metrics writer historically emits "OM" instead of "ORANGE_MONEY"
2241
+ as a paymentsByMethod map key — treat OM as deprecated; canonical value
2242
+ is ORANGE_MONEY (#21).'
2227
2243
  referenceNumber:
2228
2244
  type: string
2229
2245
  description: Unique payment reference (receipt number, transaction ID, etc.).
@@ -2520,6 +2536,146 @@ components:
2520
2536
  - $ref: '#/components/schemas/Event'
2521
2537
  description: Write payload for partial update (PATCH) of a Event document. All
2522
2538
  fields optional. Fields marked `readOnly` or `x-immutable` must not be sent.
2539
+ Expense:
2540
+ type: object
2541
+ properties:
2542
+ id:
2543
+ readOnly: true
2544
+ description: (Read-only) Firestore document ID, auto-generated.
2545
+ type:
2546
+ - string
2547
+ - 'null'
2548
+ companyId:
2549
+ type: string
2550
+ x-immutable: true
2551
+ description: (Immutable) FK → Company document ID.
2552
+ title:
2553
+ type: string
2554
+ description: Human-readable expense title (e.g. "Loyer mars 2026", "Facture
2555
+ EAU").
2556
+ description:
2557
+ description: Optional longer description or notes.
2558
+ type:
2559
+ - string
2560
+ - 'null'
2561
+ amount:
2562
+ type: number
2563
+ description: Total expense amount (XOF).
2564
+ currency:
2565
+ type: string
2566
+ const: XOF
2567
+ description: Currency code. Locked to XOF.
2568
+ dueDate:
2569
+ anyOf:
2570
+ - $ref: '#/components/schemas/FirestoreTimestamp'
2571
+ - type: 'null'
2572
+ description: When the expense is due. Used to compute OVERDUE state at read
2573
+ time (not stored in paymentStatus).
2574
+ paymentStatus:
2575
+ $ref: '#/components/schemas/ExpensePaymentStatus'
2576
+ x-note: 'OVERDUE is intentionally excluded — it is never stored in Firestore.
2577
+ Compute it at read time: expense.paymentStatus !== PAID && expense.dueDate
2578
+ < now() (#13). Helper: isExpenseOverdue(expense: Expense): boolean.'
2579
+ description: Current payment status. OVERDUE is never stored — derive from
2580
+ dueDate at read time (#13).
2581
+ amountDue:
2582
+ x-note: Authoritative for simple (non-allocation) expenses. Legacy field
2583
+ maintained for backward compatibility when no OutboundPaymentAllocation
2584
+ records exist (#12).
2585
+ description: Amount still owed. Authoritative when no OutboundPaymentAllocation
2586
+ records exist for this expense.
2587
+ type:
2588
+ - number
2589
+ - 'null'
2590
+ amountPaid:
2591
+ description: Amount paid to date (simple tracking, no allocations).
2592
+ type:
2593
+ - number
2594
+ - 'null'
2595
+ allocatedAmount:
2596
+ readOnly: true
2597
+ x-note: Server-set — computed from OutboundPaymentAllocation records. Clients
2598
+ must never write this field (#12).
2599
+ description: (Read-only) Total amount allocated via OutboundPaymentAllocation
2600
+ records. Authoritative when allocations exist.
2601
+ type:
2602
+ - number
2603
+ - 'null'
2604
+ balance:
2605
+ readOnly: true
2606
+ x-note: Server-set — computed as amount - allocatedAmount. Authoritative
2607
+ remaining amount when allocations exist. Prefer this over amountDue when
2608
+ OutboundPaymentAllocation records are present (#12).
2609
+ description: '(Read-only) Remaining balance: amount minus allocatedAmount.
2610
+ Authoritative when OutboundPaymentAllocation records exist.'
2611
+ type:
2612
+ - number
2613
+ - 'null'
2614
+ paidDate:
2615
+ anyOf:
2616
+ - $ref: '#/components/schemas/FirestoreTimestamp'
2617
+ - type: 'null'
2618
+ x-when: Set when paymentStatus transitions to PAID (fully settled). Null
2619
+ for partially paid or unpaid expenses. For multi-payment history, read
2620
+ OutboundPaymentAllocation records (#19).
2621
+ description: When the expense was fully settled (paymentStatus = PAID).
2622
+ Null otherwise.
2623
+ paymentReference:
2624
+ x-note: Reference for the most recent payment transaction (check number,
2625
+ wire ID, Wave ref, etc.). Overwritten on each payment. For full payment
2626
+ history read OutboundPaymentAllocation records (#19).
2627
+ description: Most recent payment transaction reference. Overwritten on each
2628
+ payment; not a full history.
2629
+ type:
2630
+ - string
2631
+ - 'null'
2632
+ createdBy:
2633
+ type: string
2634
+ x-immutable: true
2635
+ description: (Immutable) FK → User/staff UID who created this expense record.
2636
+ createdAt:
2637
+ anyOf:
2638
+ - $ref: '#/components/schemas/FirestoreTimestamp'
2639
+ - type: 'null'
2640
+ readOnly: true
2641
+ description: (Read-only) Server-generated creation timestamp.
2642
+ updatedAt:
2643
+ anyOf:
2644
+ - $ref: '#/components/schemas/FirestoreTimestamp'
2645
+ - type: 'null'
2646
+ readOnly: true
2647
+ description: (Read-only) Server-generated last-update timestamp.
2648
+ required:
2649
+ - companyId
2650
+ - title
2651
+ - amount
2652
+ - currency
2653
+ - paymentStatus
2654
+ - createdBy
2655
+ additionalProperties: false
2656
+ description: 'Expense (GH#12/#13/#19 partial). Collection: companies/{companyId}/expenses/{expenseId}.
2657
+ Dual balance tracking: amountPaid/amountDue for simple expenses; allocatedAmount/balance
2658
+ (server-set) for allocation-settled expenses. OVERDUE excluded from stored
2659
+ enum — derive at read time. Full domain (Payee FK, Contract FK) in #20.'
2660
+ ExpenseCreate:
2661
+ allOf:
2662
+ - $ref: '#/components/schemas/Expense'
2663
+ description: Write payload for creating a new Expense document. Fields marked
2664
+ `readOnly` are server-set and must not be included. Fields marked `x-immutable`
2665
+ may be set once at creation.
2666
+ required:
2667
+ - companyId
2668
+ - title
2669
+ - amount
2670
+ - currency
2671
+ - paymentStatus
2672
+ - createdBy
2673
+ ExpenseUpdate:
2674
+ allOf:
2675
+ - $ref: '#/components/schemas/Expense'
2676
+ description: Write payload for partial update (PATCH) of a Expense document.
2677
+ All fields optional. Fields marked `readOnly` or `x-immutable` must not be
2678
+ sent.
2523
2679
  LoyaltyConfig:
2524
2680
  type: object
2525
2681
  properties:
@@ -3006,6 +3162,9 @@ components:
3006
3162
  orderCompletionRate30d:
3007
3163
  type: number
3008
3164
  readOnly: true
3165
+ x-note: Firestore REST API v1 writes integerValue when the stored value
3166
+ is whole (e.g. 0), doubleValue when fractional (e.g. 82.17). Admin SDK
3167
+ smooths this to a JS number; REST clients must coerce the union (#11).
3009
3168
  description: (Read-only) Percentage of orders completed or delivered in
3010
3169
  the last 30 days. Always full recalc.
3011
3170
  todayPurchasesCount:
@@ -3022,11 +3181,16 @@ components:
3022
3181
  averagePurchaseAmount:
3023
3182
  type: number
3024
3183
  readOnly: true
3184
+ x-note: Firestore REST API v1 writes integerValue when whole (e.g. 10070),
3185
+ doubleValue when fractional (e.g. 10006.5). Admin SDK smooths this; REST
3186
+ clients must coerce (#11).
3025
3187
  description: (Read-only) Average purchase value across last 200 purchases
3026
3188
  (rolling, not time-windowed).
3027
3189
  monthlyRevenue:
3028
3190
  type: number
3029
3191
  readOnly: true
3192
+ x-note: Observed as integerValue on all sampled tenants (whole XOF amounts).
3193
+ Will be doubleValue if fractional. REST clients must coerce (#11).
3030
3194
  description: (Read-only) Total purchase value in the current calendar month
3031
3195
  (UTC).
3032
3196
  monthlyPurchasesCount:
@@ -3063,6 +3227,8 @@ components:
3063
3227
  todayCollectedAmount:
3064
3228
  type: number
3065
3229
  readOnly: true
3230
+ x-note: Observed as integerValue "0" on all sampled tenants. Will be doubleValue
3231
+ if fractional payments occur. REST clients must coerce (#11).
3066
3232
  description: (Read-only) Sum of totalAmount for bookings where PAYMENT_PAID_AT
3067
3233
  is today. Resets at midnight.
3068
3234
  todayRevenue:
@@ -3108,6 +3274,8 @@ components:
3108
3274
  averageRating:
3109
3275
  type: number
3110
3276
  readOnly: true
3277
+ x-note: Observed as integerValue "0" on all tenants (no reviews yet). Will
3278
+ be doubleValue once real ratings exist. REST clients must coerce (#11).
3111
3279
  description: (Read-only) Average rating from the last 200 reviews (rolling).
3112
3280
  Always full recalc.
3113
3281
  lowStockItemsCount:
@@ -3255,6 +3423,9 @@ components:
3255
3423
  orderCompletionRate30d:
3256
3424
  type: number
3257
3425
  readOnly: true
3426
+ x-note: Firestore REST API v1 writes integerValue when the stored value
3427
+ is whole (e.g. 0), doubleValue when fractional (e.g. 82.17). Admin SDK
3428
+ smooths this to a JS number; REST clients must coerce the union (#11).
3258
3429
  description: (Read-only) Percentage of orders completed or delivered in
3259
3430
  the last 30 days. Always full recalc.
3260
3431
  todayPurchasesCount:
@@ -3271,11 +3442,16 @@ components:
3271
3442
  averagePurchaseAmount:
3272
3443
  type: number
3273
3444
  readOnly: true
3445
+ x-note: Firestore REST API v1 writes integerValue when whole (e.g. 10070),
3446
+ doubleValue when fractional (e.g. 10006.5). Admin SDK smooths this; REST
3447
+ clients must coerce (#11).
3274
3448
  description: (Read-only) Average purchase value across last 200 purchases
3275
3449
  (rolling, not time-windowed).
3276
3450
  monthlyRevenue:
3277
3451
  type: number
3278
3452
  readOnly: true
3453
+ x-note: Observed as integerValue on all sampled tenants (whole XOF amounts).
3454
+ Will be doubleValue if fractional. REST clients must coerce (#11).
3279
3455
  description: (Read-only) Total purchase value in the current calendar month
3280
3456
  (UTC).
3281
3457
  monthlyPurchasesCount:
@@ -3312,6 +3488,8 @@ components:
3312
3488
  todayCollectedAmount:
3313
3489
  type: number
3314
3490
  readOnly: true
3491
+ x-note: Observed as integerValue "0" on all sampled tenants. Will be doubleValue
3492
+ if fractional payments occur. REST clients must coerce (#11).
3315
3493
  description: (Read-only) Sum of totalAmount for bookings where PAYMENT_PAID_AT
3316
3494
  is today. Resets at midnight.
3317
3495
  todayRevenue:
@@ -3357,6 +3535,8 @@ components:
3357
3535
  averageRating:
3358
3536
  type: number
3359
3537
  readOnly: true
3538
+ x-note: Observed as integerValue "0" on all tenants (no reviews yet). Will
3539
+ be doubleValue once real ratings exist. REST clients must coerce (#11).
3360
3540
  description: (Read-only) Average rating from the last 200 reviews (rolling).
3361
3541
  Always full recalc.
3362
3542
  lowStockItemsCount:
@@ -3423,17 +3603,34 @@ components:
3423
3603
  maximum: 9007199254740991
3424
3604
  paymentsByMethod:
3425
3605
  readOnly: true
3426
- x-note: Always {} until the first real payment is recorded. Present on all
3427
- tenants once rewritten by current aggregator (#8).
3428
- description: (Read-only, Optional) Map of PaymentMethod total amount for
3429
- the current day. Empty map {} until first payment.
3606
+ x-note: Map keys use short codes in practice (OM, CASH, WAVE) OM is a
3607
+ non-canonical alias for ORANGE_MONEY emitted by the metrics writer (#21).
3608
+ Value shape { total, count } differs from MetricsCurrent.paymentsByMethod
3609
+ (bare number).
3610
+ description: '(Read-only, Optional) Payment breakdown by method for the
3611
+ day. Keys are PaymentMethod values (or legacy short code OM). Value is
3612
+ { total: XOF amount, count: number of payments }.'
3430
3613
  type:
3431
3614
  - object
3432
3615
  - 'null'
3433
3616
  propertyNames:
3434
3617
  type: string
3435
3618
  additionalProperties:
3436
- type: number
3619
+ type: object
3620
+ properties:
3621
+ total:
3622
+ type: number
3623
+ description: Sum of payment amounts for this method on the given day
3624
+ (XOF).
3625
+ count:
3626
+ type: integer
3627
+ minimum: -9007199254740991
3628
+ maximum: 9007199254740991
3629
+ description: Number of payments using this method on the given day.
3630
+ required:
3631
+ - total
3632
+ - count
3633
+ additionalProperties: false
3437
3634
  computedForDay:
3438
3635
  type: string
3439
3636
  readOnly: true
@@ -3476,9 +3673,17 @@ components:
3476
3673
  - generatedAt
3477
3674
  - date
3478
3675
  additionalProperties: false
3676
+ x-note: 'Zero-activity behavior (#9): the computeDailyCompanyMetrics cron (02:00
3677
+ UTC) does NOT write a snapshot for days with no activity. A missing document
3678
+ means either zero activity or the cron did not run — consumers cannot distinguish
3679
+ the two from the absence alone. To detect cron gaps, compare the latest document
3680
+ date with today; a gap larger than 1 day on an otherwise active tenant indicates
3681
+ a cron failure. Observed: 3 of 4 zahoui tenants had gaps; bingerville (active)
3682
+ had a document every day.'
3479
3683
  description: 'Daily metrics snapshot. Collection: companies/{companyId}/metrics_daily/{YYYY-MM-DD}.
3480
3684
  Same fields as MetricsCurrent plus `date`. Written by computeDailyCompanyMetrics
3481
- cron (02:00 UTC) and inline after full recalcs.'
3685
+ cron (02:00 UTC) when the company had activity that day; zero-activity days
3686
+ may produce no document (#9).'
3482
3687
  MetricsDailyCreate:
3483
3688
  allOf:
3484
3689
  - $ref: '#/components/schemas/MetricsDaily'
@@ -3510,6 +3715,9 @@ components:
3510
3715
  orderCompletionRate30d:
3511
3716
  type: number
3512
3717
  readOnly: true
3718
+ x-note: Firestore REST API v1 writes integerValue when the stored value
3719
+ is whole (e.g. 0), doubleValue when fractional (e.g. 82.17). Admin SDK
3720
+ smooths this to a JS number; REST clients must coerce the union (#11).
3513
3721
  description: (Read-only) Percentage of orders completed or delivered in
3514
3722
  the last 30 days. Always full recalc.
3515
3723
  todayPurchasesCount:
@@ -3526,11 +3734,16 @@ components:
3526
3734
  averagePurchaseAmount:
3527
3735
  type: number
3528
3736
  readOnly: true
3737
+ x-note: Firestore REST API v1 writes integerValue when whole (e.g. 10070),
3738
+ doubleValue when fractional (e.g. 10006.5). Admin SDK smooths this; REST
3739
+ clients must coerce (#11).
3529
3740
  description: (Read-only) Average purchase value across last 200 purchases
3530
3741
  (rolling, not time-windowed).
3531
3742
  monthlyRevenue:
3532
3743
  type: number
3533
3744
  readOnly: true
3745
+ x-note: Observed as integerValue on all sampled tenants (whole XOF amounts).
3746
+ Will be doubleValue if fractional. REST clients must coerce (#11).
3534
3747
  description: (Read-only) Total purchase value in the current calendar month
3535
3748
  (UTC).
3536
3749
  monthlyPurchasesCount:
@@ -3567,6 +3780,8 @@ components:
3567
3780
  todayCollectedAmount:
3568
3781
  type: number
3569
3782
  readOnly: true
3783
+ x-note: Observed as integerValue "0" on all sampled tenants. Will be doubleValue
3784
+ if fractional payments occur. REST clients must coerce (#11).
3570
3785
  description: (Read-only) Sum of totalAmount for bookings where PAYMENT_PAID_AT
3571
3786
  is today. Resets at midnight.
3572
3787
  todayRevenue:
@@ -3612,6 +3827,8 @@ components:
3612
3827
  averageRating:
3613
3828
  type: number
3614
3829
  readOnly: true
3830
+ x-note: Observed as integerValue "0" on all tenants (no reviews yet). Will
3831
+ be doubleValue once real ratings exist. REST clients must coerce (#11).
3615
3832
  description: (Read-only) Average rating from the last 200 reviews (rolling).
3616
3833
  Always full recalc.
3617
3834
  lowStockItemsCount:
@@ -3782,8 +3999,20 @@ components:
3782
3999
  description: Recipient email address. Present for email notifications.
3783
4000
  type: string
3784
4001
  phone:
3785
- description: Recipient phone number (E.164). Present for whatsapp/sms
3786
- notifications.
4002
+ description: Recipient phone number as passed by the sender (may
4003
+ be raw wa_id or E.164). Present for whatsapp/sms notifications.
4004
+ type: string
4005
+ contactE164:
4006
+ readOnly: true
4007
+ x-note: Canonical E.164 phone, normalized from `phone` by the
4008
+ backend writer. Use this for joins and search, not the raw `phone`
4009
+ field (#56). Absent on pre-migration docs.
4010
+ x-when: Populated by Cloud Functions on every new NotificationRecord
4011
+ for whatsapp/sms channels. CI normalization applied (8→10-digit
4012
+ 07/05/01 series).
4013
+ description: (Read-only) E.164-normalized phone (e.g. +2250777471485).
4014
+ Canonical join key across WhatsApp and notification collections
4015
+ (#56).
3787
4016
  type: string
3788
4017
  name:
3789
4018
  description: Recipient display name.
@@ -3804,8 +4033,20 @@ components:
3804
4033
  description: Recipient email address. Present for email notifications.
3805
4034
  type: string
3806
4035
  phone:
3807
- description: Recipient phone number (E.164). Present for whatsapp/sms
3808
- notifications.
4036
+ description: Recipient phone number as passed by the sender (may
4037
+ be raw wa_id or E.164). Present for whatsapp/sms notifications.
4038
+ type: string
4039
+ contactE164:
4040
+ readOnly: true
4041
+ x-note: Canonical E.164 phone, normalized from `phone` by the
4042
+ backend writer. Use this for joins and search, not the raw `phone`
4043
+ field (#56). Absent on pre-migration docs.
4044
+ x-when: Populated by Cloud Functions on every new NotificationRecord
4045
+ for whatsapp/sms channels. CI normalization applied (8→10-digit
4046
+ 07/05/01 series).
4047
+ description: (Read-only) E.164-normalized phone (e.g. +2250777471485).
4048
+ Canonical join key across WhatsApp and notification collections
4049
+ (#56).
3809
4050
  type: string
3810
4051
  name:
3811
4052
  description: Recipient display name.
@@ -3825,8 +4066,20 @@ components:
3825
4066
  description: Recipient email address. Present for email notifications.
3826
4067
  type: string
3827
4068
  phone:
3828
- description: Recipient phone number (E.164). Present for whatsapp/sms
3829
- notifications.
4069
+ description: Recipient phone number as passed by the sender (may
4070
+ be raw wa_id or E.164). Present for whatsapp/sms notifications.
4071
+ type: string
4072
+ contactE164:
4073
+ readOnly: true
4074
+ x-note: Canonical E.164 phone, normalized from `phone` by the
4075
+ backend writer. Use this for joins and search, not the raw `phone`
4076
+ field (#56). Absent on pre-migration docs.
4077
+ x-when: Populated by Cloud Functions on every new NotificationRecord
4078
+ for whatsapp/sms channels. CI normalization applied (8→10-digit
4079
+ 07/05/01 series).
4080
+ description: (Read-only) E.164-normalized phone (e.g. +2250777471485).
4081
+ Canonical join key across WhatsApp and notification collections
4082
+ (#56).
3830
4083
  type: string
3831
4084
  name:
3832
4085
  description: Recipient display name.
@@ -4061,7 +4314,10 @@ components:
4061
4314
  anyOf:
4062
4315
  - $ref: '#/components/schemas/PaymentMethod'
4063
4316
  - type: 'null'
4064
- description: Unified payment method set with African + global methods (D02).
4317
+ description: 'Unified payment method set with African + global methods (D02).
4318
+ Note: the metrics writer historically emits "OM" instead of "ORANGE_MONEY"
4319
+ as a paymentsByMethod map key — treat OM as deprecated; canonical value
4320
+ is ORANGE_MONEY (#21).'
4065
4321
  invoiceId:
4066
4322
  description: FK → Invoice document ID.
4067
4323
  type:
@@ -4659,6 +4915,147 @@ components:
4659
4915
  description: Write payload for partial update (PATCH) of a OutboundPaymentAllocation
4660
4916
  document. All fields optional. Fields marked `readOnly` or `x-immutable` must
4661
4917
  not be sent.
4918
+ PaymentWebhookDelivery:
4919
+ type: object
4920
+ properties:
4921
+ id:
4922
+ readOnly: true
4923
+ description: (Read-only) Firestore document ID, auto-generated.
4924
+ type:
4925
+ - string
4926
+ - 'null'
4927
+ company:
4928
+ type: string
4929
+ x-immutable: true
4930
+ description: (Immutable) Company document ID (e.g. "gerko_studios"). Resolved
4931
+ from the matched endpoint at delivery time.
4932
+ provider:
4933
+ type: string
4934
+ x-note: 'Observed value: "jeko". The inner payload.paymentMethod may differ
4935
+ (e.g. "wave") — provider here is the webhook sender, not the payment rail
4936
+ (#42).'
4937
+ description: Payment provider that sent this webhook (e.g. "jeko", "wave").
4938
+ eventType:
4939
+ type: string
4940
+ x-note: 'Observed value: "transaction.payment". Jeko docs say "transaction.completed"
4941
+ — full set per provider unconfirmed (#42). Use z.string() to avoid rejecting
4942
+ unseen values.'
4943
+ description: 'Provider-defined event type. Observed: "transaction.payment".
4944
+ Full set per provider TBD (#42).'
4945
+ status:
4946
+ type: string
4947
+ x-note: 'Observed values: "success", "error". Indicates whether the webhook
4948
+ was processed without errors.'
4949
+ description: 'Processing outcome. Observed values: "success" | "error".'
4950
+ verified:
4951
+ type: string
4952
+ x-note: 'Observed value: "verified". Indicates HMAC-SHA256 signature verification
4953
+ result. Full set of failure values unconfirmed (#42).'
4954
+ description: 'Signature verification result. Observed: "verified". Other
4955
+ values (e.g. "unverified", "error") may exist but are unconfirmed.'
4956
+ endpointStatus:
4957
+ type: string
4958
+ x-note: 'Observed value: "matched". Indicates whether the token resolved
4959
+ to a known PaymentWebhookEndpoint. Other values (e.g. "not_found", "inactive")
4960
+ unconfirmed (#42).'
4961
+ description: 'Endpoint resolution result. Observed: "matched". Other values
4962
+ unconfirmed (#42).'
4963
+ processed:
4964
+ type: boolean
4965
+ x-note: Set to true once the delivery has been reconciled to the AppPayment
4966
+ ledger (companies/{cid}/apps/{appId}/payments). Back-reference FK not
4967
+ stored on this doc — reconciliation is tracked on the AppPayment side.
4968
+ description: Whether this delivery has been reconciled to the AppPayment
4969
+ ledger.
4970
+ reference:
4971
+ type: string
4972
+ x-note: Equals payload.id (provider transaction ID). Used as dedup key —
4973
+ the backend checks this before processing (#42 ask 3).
4974
+ description: Provider transaction ID (= payload.id). Canonical dedup key.
4975
+ amount:
4976
+ type: number
4977
+ description: Payment amount, denormalized from payload.amount.amount (XOF).
4978
+ currency:
4979
+ type: string
4980
+ description: Currency code, denormalized from payload.amount.currency (e.g.
4981
+ "XOF").
4982
+ payload:
4983
+ type: object
4984
+ propertyNames:
4985
+ type: string
4986
+ additionalProperties: {}
4987
+ x-note: 'Parsed provider request body. Contains PII: counterpartIdentifier
4988
+ and counterpartLabel hold customer phone numbers. Retention/TTL policy
4989
+ TBD (#42 ask 5).'
4990
+ description: Full parsed provider payload. Shape varies by provider. Contains
4991
+ PII (customer phone). See x-note for retention policy status.
4992
+ rawBody:
4993
+ type: string
4994
+ x-note: Verbatim request body string used for HMAC-SHA256 signature verification.
4995
+ Contains same PII as payload. Retention/TTL policy TBD (#42 ask 5).
4996
+ description: Verbatim raw request body — used for HMAC-SHA256 verification.
4997
+ Contains PII.
4998
+ headers:
4999
+ x-note: Request headers including provider signature (e.g. "jeko-signature")
5000
+ and tracing headers. Sensitive — do not expose to clients.
5001
+ description: Incoming HTTP headers. Includes provider signature header and
5002
+ Sentry trace. Sensitive.
5003
+ type:
5004
+ - object
5005
+ - 'null'
5006
+ propertyNames:
5007
+ type: string
5008
+ additionalProperties:
5009
+ type: string
5010
+ receivedAt:
5011
+ $ref: '#/components/schemas/FirestoreTimestamp'
5012
+ description: When the webhook delivery was received by the backend.
5013
+ required:
5014
+ - company
5015
+ - provider
5016
+ - eventType
5017
+ - status
5018
+ - verified
5019
+ - endpointStatus
5020
+ - processed
5021
+ - reference
5022
+ - amount
5023
+ - currency
5024
+ - payload
5025
+ - rawBody
5026
+ - receivedAt
5027
+ additionalProperties: false
5028
+ x-internal: true
5029
+ description: 'PaymentWebhookDelivery (GH#42). Collection: payment_webhooks/{deliveryId}
5030
+ (top-level). One document per received provider callback. Contains raw payload
5031
+ + verification outcome. x-internal: written/read only by backend; dashboard
5032
+ reads via admin UI. PII in payload/rawBody — retention policy TBD.'
5033
+ PaymentWebhookDeliveryCreate:
5034
+ allOf:
5035
+ - $ref: '#/components/schemas/PaymentWebhookDelivery'
5036
+ description: Write payload for creating a new PaymentWebhookDelivery document.
5037
+ Fields marked `readOnly` are server-set and must not be included. Fields marked
5038
+ `x-immutable` may be set once at creation.
5039
+ required:
5040
+ - company
5041
+ - provider
5042
+ - eventType
5043
+ - status
5044
+ - verified
5045
+ - endpointStatus
5046
+ - processed
5047
+ - reference
5048
+ - amount
5049
+ - currency
5050
+ - payload
5051
+ - rawBody
5052
+ - receivedAt
5053
+ PaymentWebhookDeliveryUpdate:
5054
+ allOf:
5055
+ - $ref: '#/components/schemas/PaymentWebhookDelivery'
5056
+ description: Write payload for partial update (PATCH) of a PaymentWebhookDelivery
5057
+ document. All fields optional. Fields marked `readOnly` or `x-immutable` must
5058
+ not be sent.
4662
5059
  PaymentWebhookEndpoint:
4663
5060
  type: object
4664
5061
  properties:
@@ -5710,6 +6107,22 @@ components:
5710
6107
  type: boolean
5711
6108
  const: true
5712
6109
  additionalProperties: false
6110
+ contactE164:
6111
+ readOnly: true
6112
+ x-note: E.164-normalized form of `from` (wa_id). Canonical join key across
6113
+ WhatsappInboundMessage, WhatsappOutboundMessage, and NotificationRecord.
6114
+ Use this for conversation threading, search, and cross-collection joins
6115
+ — not the raw `from` wa_id (#56).
6116
+ x-when: 'Populated by whatsapp-server on every new inbound doc. Absent on
6117
+ pre-#56 docs until the backfill migration runs. CI normalization: wa_id
6118
+ 22577471485 → +2250777471485 (insert trunk 0 after country code for 8-digit
6119
+ numbers in the 07/05/01 series that predate the 2014 10-digit migration).'
6120
+ description: (Read-only) E.164-normalized sender phone (e.g. +2250777471485).
6121
+ Canonical join key (#56). Populated by the backend; absent on pre-migration
6122
+ docs.
6123
+ type:
6124
+ - string
6125
+ - 'null'
5713
6126
  required:
5714
6127
  - wabaId
5715
6128
  - waba
@@ -5929,6 +6342,22 @@ components:
5929
6342
  $ref: '#/components/schemas/FirestoreTimestamp'
5930
6343
  description: (Immutable) Enqueue timestamp, set by the dashboard at create.
5931
6344
  x-immutable: true
6345
+ contactE164:
6346
+ readOnly: true
6347
+ x-note: E.164-normalized form of `to` (wa_id). Canonical join key across
6348
+ WhatsappOutboundMessage, WhatsappInboundMessage, and NotificationRecord.
6349
+ Use this for conversation threading, search, and cross-collection joins
6350
+ — not the raw `to` wa_id (#56).
6351
+ x-when: 'Populated by whatsapp-server on every new outbound doc. Absent
6352
+ on pre-#56 docs until the backfill migration runs. CI normalization: wa_id
6353
+ 22577471485 → +2250777471485 (insert trunk 0 after country code for 8-digit
6354
+ numbers in the 07/05/01 series that predate the 2014 10-digit migration).'
6355
+ description: (Read-only) E.164-normalized recipient phone (e.g. +2250777471485).
6356
+ Canonical join key (#56). Populated by the backend; absent on pre-migration
6357
+ docs.
6358
+ type:
6359
+ - string
6360
+ - 'null'
5932
6361
  status:
5933
6362
  $ref: '#/components/schemas/OutboundMessageStatus'
5934
6363
  description: Delivery status. Created as `queued` by the dashboard; updated