@ingenx-io/valets-schema-mcp-server 0.2.5 → 0.2.7
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.
- package/data/docs/collections/firestore-paths.md +20 -0
- package/data/docs/enums/app-status.md +1 -1
- package/data/docs/enums/attention-status.md +1 -1
- package/data/docs/enums/booking-status.md +1 -1
- package/data/docs/enums/contract-status.md +24 -0
- package/data/docs/enums/customer-payment-status.md +2 -2
- package/data/docs/enums/customer-payment-target-type.md +2 -2
- package/data/docs/enums/delivery-type.md +2 -2
- package/data/docs/enums/deployment-link-type.md +2 -2
- package/data/docs/enums/event-status.md +2 -2
- package/data/docs/enums/expense-payment-status.md +24 -0
- package/data/docs/enums/fulfillment-status.md +2 -2
- package/data/docs/enums/loyalty-transaction-type.md +2 -2
- package/data/docs/enums/milestone-status.md +23 -0
- package/data/docs/enums/notification-channel.md +2 -2
- package/data/docs/enums/notification-entity-type.md +2 -2
- package/data/docs/enums/notification-status.md +2 -2
- package/data/docs/enums/order-status.md +2 -2
- package/data/docs/enums/outbound-message-format.md +2 -2
- package/data/docs/enums/outbound-message-purpose.md +2 -2
- package/data/docs/enums/outbound-message-status.md +2 -2
- package/data/docs/enums/payment-method.md +4 -3
- package/data/docs/enums/payment-proof-status.md +2 -2
- package/data/docs/enums/payment-status.md +2 -2
- package/data/docs/enums/pending-issue.md +2 -2
- package/data/docs/enums/return-status.md +2 -2
- package/data/docs/enums/session-status.md +2 -2
- package/data/docs/enums/site-status.md +2 -2
- package/data/docs/enums/stocktake-frequency.md +2 -2
- package/data/docs/enums/stocktake-item-status.md +2 -2
- package/data/docs/enums/stocktake-status.md +2 -2
- package/data/docs/enums/ticket-status.md +2 -2
- package/data/docs/enums/waba-label.md +3 -3
- package/data/docs/enums/whatsapp-button-sub-type.md +2 -2
- package/data/docs/enums/whatsapp-template-component.md +2 -2
- package/data/docs/enums/whatsapp-template-status.md +2 -2
- package/data/docs/index.md +15 -6
- package/data/docs/models/allowed-user.md +1 -1
- package/data/docs/models/analytics-backfill.md +1 -1
- package/data/docs/models/analytics-daily.md +1 -1
- package/data/docs/models/analytics-event.md +1 -1
- package/data/docs/models/analytics-hourly.md +1 -1
- package/data/docs/models/app-payment.md +1 -1
- package/data/docs/models/app.md +45 -21
- package/data/docs/models/booking-version.md +1 -1
- package/data/docs/models/booking.md +1 -1
- package/data/docs/models/contract.md +454 -0
- package/data/docs/models/customer-payment-allocation.md +2 -2
- package/data/docs/models/customer-payment.md +23 -22
- package/data/docs/models/customer.md +2 -2
- package/data/docs/models/event.md +2 -2
- package/data/docs/models/expense.md +434 -0
- package/data/docs/models/loyalty-config.md +2 -2
- package/data/docs/models/loyalty-reward.md +2 -2
- package/data/docs/models/loyalty-status.md +2 -2
- package/data/docs/models/loyalty-transaction.md +2 -2
- package/data/docs/models/magic-link-request.md +2 -2
- package/data/docs/models/metrics-current.md +22 -2
- package/data/docs/models/metrics-daily.md +92 -41
- package/data/docs/models/metrics-monthly.md +22 -2
- package/data/docs/models/notification-record.md +2 -2
- package/data/docs/models/order-item.md +2 -2
- package/data/docs/models/order.md +291 -270
- package/data/docs/models/outbound-payment-allocation.md +195 -0
- package/data/docs/models/outbound-payment.md +319 -0
- package/data/docs/models/payment-webhook-delivery.md +321 -0
- package/data/docs/models/payment-webhook-endpoint.md +191 -0
- package/data/docs/models/sale.md +2 -2
- package/data/docs/models/site-payment.md +2 -2
- package/data/docs/models/site.md +2 -2
- package/data/docs/models/stocktake-item.md +2 -2
- package/data/docs/models/stocktake.md +2 -2
- package/data/docs/models/ticket.md +2 -2
- package/data/docs/models/user.md +2 -2
- package/data/docs/models/whatsapp-inbound-message.md +6 -2
- package/data/docs/models/whatsapp-outbound-lifecycle-event.md +2 -2
- package/data/docs/models/whatsapp-outbound-message.md +39 -23
- package/data/docs/models/whatsapp-template.md +6 -2
- package/data/static/llms.txt +242 -10
- package/data/static/openapi.yaml +826 -23
- package/data/static/schemas.json +877 -71
- package/package.json +1 -1
package/data/static/schemas.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
3
|
"description": "@valets/schema \u2014 consolidated schema bundle",
|
|
4
|
-
"generated": "2026-05-
|
|
4
|
+
"generated": "2026-05-30T13:57:29.446011+00:00",
|
|
5
5
|
"schemas": {
|
|
6
6
|
"allowed-user": {
|
|
7
7
|
"type": "object",
|
|
@@ -745,16 +745,23 @@
|
|
|
745
745
|
]
|
|
746
746
|
},
|
|
747
747
|
"status": {
|
|
748
|
-
"
|
|
749
|
-
|
|
750
|
-
|
|
748
|
+
"anyOf": [
|
|
749
|
+
{
|
|
750
|
+
"$ref": "#/definitions/app-status"
|
|
751
|
+
},
|
|
752
|
+
{
|
|
753
|
+
"type": "null"
|
|
754
|
+
}
|
|
755
|
+
],
|
|
756
|
+
"x-note": "Real Firestore documents may be missing this field on pre-backfill records (#26). Treat absent as ACTIVE. A backfill script will populate status=ACTIVE on all existing documents; once confirmed, this field will be promoted to required.",
|
|
757
|
+
"x-when": "Written by operators via dashboard or by server triggers (expiration). Clients must not use server-side `where(status == ACTIVE)` until backfill is complete \u2014 filter client-side instead, treating absent as ACTIVE.",
|
|
758
|
+
"description": "Lifecycle status (D41/D44). Optional pending backfill of pre-existing records (#26) \u2014 treat absent as ACTIVE. Clients filter by ACTIVE.",
|
|
751
759
|
"x-see": {
|
|
752
760
|
"decisions": [
|
|
753
761
|
"D41",
|
|
754
762
|
"D44"
|
|
755
763
|
]
|
|
756
|
-
}
|
|
757
|
-
"x-when": "Written by operators via dashboard or by server triggers (expiration). Clients filter by ACTIVE."
|
|
764
|
+
}
|
|
758
765
|
},
|
|
759
766
|
"deploymentLinks": {
|
|
760
767
|
"type": "array",
|
|
@@ -915,7 +922,6 @@
|
|
|
915
922
|
"required": [
|
|
916
923
|
"companyId",
|
|
917
924
|
"name",
|
|
918
|
-
"status",
|
|
919
925
|
"deploymentLinks",
|
|
920
926
|
"createdBy",
|
|
921
927
|
"analyticsEnabled"
|
|
@@ -1919,6 +1925,192 @@
|
|
|
1919
1925
|
"snapshot": {}
|
|
1920
1926
|
}
|
|
1921
1927
|
},
|
|
1928
|
+
"contract": {
|
|
1929
|
+
"type": "object",
|
|
1930
|
+
"properties": {
|
|
1931
|
+
"id": {
|
|
1932
|
+
"readOnly": true,
|
|
1933
|
+
"description": "(Read-only) Firestore document ID, auto-generated.",
|
|
1934
|
+
"type": [
|
|
1935
|
+
"string",
|
|
1936
|
+
"null"
|
|
1937
|
+
]
|
|
1938
|
+
},
|
|
1939
|
+
"companyId": {
|
|
1940
|
+
"type": "string",
|
|
1941
|
+
"x-immutable": true,
|
|
1942
|
+
"description": "(Immutable) FK \u2192 Company document ID."
|
|
1943
|
+
},
|
|
1944
|
+
"payeeId": {
|
|
1945
|
+
"type": "string",
|
|
1946
|
+
"x-immutable": true,
|
|
1947
|
+
"description": "(Immutable) FK \u2192 Payee document ID. Full Payee model tracked in #20."
|
|
1948
|
+
},
|
|
1949
|
+
"title": {
|
|
1950
|
+
"type": "string",
|
|
1951
|
+
"description": "Contract title or reference name shown in dashboards."
|
|
1952
|
+
},
|
|
1953
|
+
"description": {
|
|
1954
|
+
"description": "Optional freeform description of the contract scope.",
|
|
1955
|
+
"type": [
|
|
1956
|
+
"string",
|
|
1957
|
+
"null"
|
|
1958
|
+
]
|
|
1959
|
+
},
|
|
1960
|
+
"status": {
|
|
1961
|
+
"$ref": "#/definitions/contract-status",
|
|
1962
|
+
"description": "Contract lifecycle status (#14). Query by ACTIVE \u2014 do not use an isActive boolean."
|
|
1963
|
+
},
|
|
1964
|
+
"currency": {
|
|
1965
|
+
"type": "string",
|
|
1966
|
+
"const": "XOF",
|
|
1967
|
+
"description": "Currency code. Locked to XOF (#18). Multi-currency support requires a deliberate schema version bump."
|
|
1968
|
+
},
|
|
1969
|
+
"totalAmount": {
|
|
1970
|
+
"type": "number",
|
|
1971
|
+
"description": "Total contract value (XOF)."
|
|
1972
|
+
},
|
|
1973
|
+
"startDate": {
|
|
1974
|
+
"type": "string",
|
|
1975
|
+
"description": "Contract start date (ISO 8601 YYYY-MM-DD)."
|
|
1976
|
+
},
|
|
1977
|
+
"endDate": {
|
|
1978
|
+
"description": "Contract end date (ISO 8601 YYYY-MM-DD). Absent for open-ended contracts.",
|
|
1979
|
+
"type": [
|
|
1980
|
+
"string",
|
|
1981
|
+
"null"
|
|
1982
|
+
]
|
|
1983
|
+
},
|
|
1984
|
+
"milestones": {
|
|
1985
|
+
"description": "Ordered list of payment milestones. Embedded in the contract document (#17).",
|
|
1986
|
+
"type": [
|
|
1987
|
+
"array",
|
|
1988
|
+
"null"
|
|
1989
|
+
],
|
|
1990
|
+
"items": {
|
|
1991
|
+
"type": "object",
|
|
1992
|
+
"properties": {
|
|
1993
|
+
"id": {
|
|
1994
|
+
"type": "string",
|
|
1995
|
+
"description": "Client-generated milestone ID (UUID or slug). Unique within the contract."
|
|
1996
|
+
},
|
|
1997
|
+
"title": {
|
|
1998
|
+
"type": "string",
|
|
1999
|
+
"description": "Milestone description or deliverable name."
|
|
2000
|
+
},
|
|
2001
|
+
"amount": {
|
|
2002
|
+
"type": "number",
|
|
2003
|
+
"description": "Amount due at this milestone (XOF)."
|
|
2004
|
+
},
|
|
2005
|
+
"dueDate": {
|
|
2006
|
+
"description": "ISO 8601 date string (YYYY-MM-DD) when the milestone is due. OVERDUE is derived at read time from dueDate \u2014 not stored.",
|
|
2007
|
+
"type": "string"
|
|
2008
|
+
},
|
|
2009
|
+
"status": {
|
|
2010
|
+
"$ref": "#/definitions/milestone-status",
|
|
2011
|
+
"x-note": "Existing Firestore documents may have lowercase values (pending, invoiced, paid) from before this enum was introduced (#17). Normalize on read or via migration script.",
|
|
2012
|
+
"description": "Milestone payment status (#17). OVERDUE is derived at read time from dueDate, not stored."
|
|
2013
|
+
},
|
|
2014
|
+
"invoicedAt": {
|
|
2015
|
+
"$ref": "#/definitions/firestore-timestamp",
|
|
2016
|
+
"description": "When the invoice was issued for this milestone."
|
|
2017
|
+
},
|
|
2018
|
+
"paidAt": {
|
|
2019
|
+
"$ref": "#/definitions/firestore-timestamp",
|
|
2020
|
+
"description": "When payment was received for this milestone."
|
|
2021
|
+
},
|
|
2022
|
+
"notes": {
|
|
2023
|
+
"description": "Optional notes for this milestone.",
|
|
2024
|
+
"type": "string"
|
|
2025
|
+
}
|
|
2026
|
+
},
|
|
2027
|
+
"required": [
|
|
2028
|
+
"id",
|
|
2029
|
+
"title",
|
|
2030
|
+
"amount",
|
|
2031
|
+
"status"
|
|
2032
|
+
],
|
|
2033
|
+
"additionalProperties": false,
|
|
2034
|
+
"description": "ContractMilestone \u2014 embedded sub-object on Contract (#17). Not a separate collection."
|
|
2035
|
+
}
|
|
2036
|
+
},
|
|
2037
|
+
"notes": {
|
|
2038
|
+
"description": "Optional internal notes.",
|
|
2039
|
+
"type": [
|
|
2040
|
+
"string",
|
|
2041
|
+
"null"
|
|
2042
|
+
]
|
|
2043
|
+
},
|
|
2044
|
+
"createdBy": {
|
|
2045
|
+
"type": "string",
|
|
2046
|
+
"x-immutable": true,
|
|
2047
|
+
"description": "(Immutable) FK \u2192 User/staff UID who created the contract."
|
|
2048
|
+
},
|
|
2049
|
+
"createdAt": {
|
|
2050
|
+
"anyOf": [
|
|
2051
|
+
{
|
|
2052
|
+
"$ref": "#/definitions/firestore-timestamp"
|
|
2053
|
+
},
|
|
2054
|
+
{
|
|
2055
|
+
"type": "null"
|
|
2056
|
+
}
|
|
2057
|
+
],
|
|
2058
|
+
"readOnly": true,
|
|
2059
|
+
"description": "(Read-only) Server-generated creation timestamp."
|
|
2060
|
+
},
|
|
2061
|
+
"updatedAt": {
|
|
2062
|
+
"anyOf": [
|
|
2063
|
+
{
|
|
2064
|
+
"$ref": "#/definitions/firestore-timestamp"
|
|
2065
|
+
},
|
|
2066
|
+
{
|
|
2067
|
+
"type": "null"
|
|
2068
|
+
}
|
|
2069
|
+
],
|
|
2070
|
+
"readOnly": true,
|
|
2071
|
+
"description": "(Read-only) Server-generated update timestamp."
|
|
2072
|
+
}
|
|
2073
|
+
},
|
|
2074
|
+
"required": [
|
|
2075
|
+
"companyId",
|
|
2076
|
+
"payeeId",
|
|
2077
|
+
"title",
|
|
2078
|
+
"status",
|
|
2079
|
+
"currency",
|
|
2080
|
+
"totalAmount",
|
|
2081
|
+
"startDate",
|
|
2082
|
+
"createdBy"
|
|
2083
|
+
],
|
|
2084
|
+
"additionalProperties": false,
|
|
2085
|
+
"description": "Contract model (GH#14/#17/#18). Collection: companies/{companyId}/contracts/{contractId}. Service/supplier contract between a company and a Payee. No isActive field \u2014 query by status. Currency locked to XOF. Milestones use MilestoneStatus enum (no stored OVERDUE).",
|
|
2086
|
+
"example": {
|
|
2087
|
+
"id": null,
|
|
2088
|
+
"companyId": "comp_xyz789",
|
|
2089
|
+
"payeeId": "pay_ref123",
|
|
2090
|
+
"title": "title",
|
|
2091
|
+
"description": null,
|
|
2092
|
+
"status": "status",
|
|
2093
|
+
"currency": "XOF",
|
|
2094
|
+
"totalAmount": 45000,
|
|
2095
|
+
"startDate": "2026-02-15",
|
|
2096
|
+
"endDate": null,
|
|
2097
|
+
"milestones": null,
|
|
2098
|
+
"notes": null,
|
|
2099
|
+
"createdBy": "staff_k0f1",
|
|
2100
|
+
"createdAt": "createdAt",
|
|
2101
|
+
"updatedAt": "updatedAt"
|
|
2102
|
+
}
|
|
2103
|
+
},
|
|
2104
|
+
"contract-status": {
|
|
2105
|
+
"type": "string",
|
|
2106
|
+
"enum": [
|
|
2107
|
+
"DRAFT",
|
|
2108
|
+
"ACTIVE",
|
|
2109
|
+
"COMPLETED",
|
|
2110
|
+
"TERMINATED"
|
|
2111
|
+
],
|
|
2112
|
+
"description": "Lifecycle status of a Contract. DRAFT = not yet signed. ACTIVE = in force. COMPLETED = all milestones paid and obligations met. TERMINATED = ended early by either party."
|
|
2113
|
+
},
|
|
1922
2114
|
"customer": {
|
|
1923
2115
|
"type": "object",
|
|
1924
2116
|
"properties": {
|
|
@@ -2142,7 +2334,7 @@
|
|
|
2142
2334
|
},
|
|
2143
2335
|
"paymentMethod": {
|
|
2144
2336
|
"$ref": "#/definitions/payment-method",
|
|
2145
|
-
"description": "Unified payment method set with African + global methods (D02)."
|
|
2337
|
+
"description": "Unified payment method set with African + global methods (D02). Note: the metrics writer historically emits \"OM\" instead of \"ORANGE_MONEY\" as a paymentsByMethod map key \u2014 treat OM as deprecated; canonical value is ORANGE_MONEY (#21)."
|
|
2146
2338
|
},
|
|
2147
2339
|
"referenceNumber": {
|
|
2148
2340
|
"type": "string",
|
|
@@ -2540,95 +2732,116 @@
|
|
|
2540
2732
|
],
|
|
2541
2733
|
"description": "Ticketed event lifecycle (D32). Mobile-only today; Dashboard in Wave 4."
|
|
2542
2734
|
},
|
|
2543
|
-
"
|
|
2544
|
-
"type": "string",
|
|
2545
|
-
"enum": [
|
|
2546
|
-
"PREPARING",
|
|
2547
|
-
"PARTIALLY_SHIPPED",
|
|
2548
|
-
"SHIPPED",
|
|
2549
|
-
"IN_TRANSIT",
|
|
2550
|
-
"DELIVERED",
|
|
2551
|
-
"PICKED_UP"
|
|
2552
|
-
],
|
|
2553
|
-
"description": "Delivery/fulfillment lifecycle (D34). Optional \u2014 null for in-person orders."
|
|
2554
|
-
},
|
|
2555
|
-
"loyalty-config": {
|
|
2735
|
+
"expense": {
|
|
2556
2736
|
"type": "object",
|
|
2557
2737
|
"properties": {
|
|
2558
2738
|
"id": {
|
|
2559
2739
|
"readOnly": true,
|
|
2560
|
-
"description": "(Read-only) Firestore document ID
|
|
2740
|
+
"description": "(Read-only) Firestore document ID, auto-generated.",
|
|
2561
2741
|
"type": [
|
|
2562
2742
|
"string",
|
|
2563
2743
|
"null"
|
|
2564
2744
|
]
|
|
2565
2745
|
},
|
|
2566
|
-
"
|
|
2567
|
-
"type": "
|
|
2746
|
+
"companyId": {
|
|
2747
|
+
"type": "string",
|
|
2748
|
+
"x-immutable": true,
|
|
2749
|
+
"description": "(Immutable) FK \u2192 Company document ID."
|
|
2568
2750
|
},
|
|
2569
|
-
"
|
|
2751
|
+
"title": {
|
|
2570
2752
|
"type": "string",
|
|
2571
|
-
"
|
|
2572
|
-
"SPENDING",
|
|
2573
|
-
"PRODUCT",
|
|
2574
|
-
"VISIT"
|
|
2575
|
-
],
|
|
2576
|
-
"description": "How points are earned: SPENDING (per currency spent), PRODUCT (per product purchased), or VISIT (per visit). SCREAMING_SNAKE per D04."
|
|
2753
|
+
"description": "Human-readable expense title (e.g. \"Loyer mars 2026\", \"Facture EAU\")."
|
|
2577
2754
|
},
|
|
2578
|
-
"
|
|
2579
|
-
"description": "
|
|
2580
|
-
"deprecated": true,
|
|
2755
|
+
"description": {
|
|
2756
|
+
"description": "Optional longer description or notes.",
|
|
2581
2757
|
"type": [
|
|
2582
|
-
"
|
|
2758
|
+
"string",
|
|
2583
2759
|
"null"
|
|
2584
2760
|
]
|
|
2585
2761
|
},
|
|
2586
|
-
"
|
|
2587
|
-
"
|
|
2762
|
+
"amount": {
|
|
2763
|
+
"type": "number",
|
|
2764
|
+
"description": "Total expense amount (XOF)."
|
|
2765
|
+
},
|
|
2766
|
+
"currency": {
|
|
2767
|
+
"type": "string",
|
|
2768
|
+
"const": "XOF",
|
|
2769
|
+
"description": "Currency code. Locked to XOF."
|
|
2770
|
+
},
|
|
2771
|
+
"dueDate": {
|
|
2772
|
+
"anyOf": [
|
|
2773
|
+
{
|
|
2774
|
+
"$ref": "#/definitions/firestore-timestamp"
|
|
2775
|
+
},
|
|
2776
|
+
{
|
|
2777
|
+
"type": "null"
|
|
2778
|
+
}
|
|
2779
|
+
],
|
|
2780
|
+
"description": "When the expense is due. Used to compute OVERDUE state at read time (not stored in paymentStatus)."
|
|
2781
|
+
},
|
|
2782
|
+
"paymentStatus": {
|
|
2783
|
+
"$ref": "#/definitions/expense-payment-status",
|
|
2784
|
+
"x-note": "OVERDUE is intentionally excluded \u2014 it is never stored in Firestore. Compute it at read time: expense.paymentStatus !== PAID && expense.dueDate < now() (#13). Helper: isExpenseOverdue(expense: Expense): boolean.",
|
|
2785
|
+
"description": "Current payment status. OVERDUE is never stored \u2014 derive from dueDate at read time (#13)."
|
|
2786
|
+
},
|
|
2787
|
+
"amountDue": {
|
|
2788
|
+
"x-note": "Authoritative for simple (non-allocation) expenses. Legacy field maintained for backward compatibility when no OutboundPaymentAllocation records exist (#12).",
|
|
2789
|
+
"description": "Amount still owed. Authoritative when no OutboundPaymentAllocation records exist for this expense.",
|
|
2588
2790
|
"type": [
|
|
2589
2791
|
"number",
|
|
2590
2792
|
"null"
|
|
2591
2793
|
]
|
|
2592
2794
|
},
|
|
2593
|
-
"
|
|
2594
|
-
"description": "
|
|
2795
|
+
"amountPaid": {
|
|
2796
|
+
"description": "Amount paid to date (simple tracking, no allocations).",
|
|
2595
2797
|
"type": [
|
|
2596
2798
|
"number",
|
|
2597
2799
|
"null"
|
|
2598
2800
|
]
|
|
2599
2801
|
},
|
|
2600
|
-
"
|
|
2601
|
-
"
|
|
2802
|
+
"allocatedAmount": {
|
|
2803
|
+
"readOnly": true,
|
|
2804
|
+
"x-note": "Server-set \u2014 computed from OutboundPaymentAllocation records. Clients must never write this field (#12).",
|
|
2805
|
+
"description": "(Read-only) Total amount allocated via OutboundPaymentAllocation records. Authoritative when allocations exist.",
|
|
2602
2806
|
"type": [
|
|
2603
|
-
"
|
|
2807
|
+
"number",
|
|
2604
2808
|
"null"
|
|
2605
|
-
]
|
|
2606
|
-
"minimum": -9007199254740991,
|
|
2607
|
-
"maximum": 9007199254740991
|
|
2809
|
+
]
|
|
2608
2810
|
},
|
|
2609
|
-
"
|
|
2610
|
-
"
|
|
2811
|
+
"balance": {
|
|
2812
|
+
"readOnly": true,
|
|
2813
|
+
"x-note": "Server-set \u2014 computed as amount - allocatedAmount. Authoritative remaining amount when allocations exist. Prefer this over amountDue when OutboundPaymentAllocation records are present (#12).",
|
|
2814
|
+
"description": "(Read-only) Remaining balance: amount minus allocatedAmount. Authoritative when OutboundPaymentAllocation records exist.",
|
|
2611
2815
|
"type": [
|
|
2612
|
-
"
|
|
2816
|
+
"number",
|
|
2613
2817
|
"null"
|
|
2614
|
-
]
|
|
2615
|
-
"minimum": -9007199254740991,
|
|
2616
|
-
"maximum": 9007199254740991
|
|
2818
|
+
]
|
|
2617
2819
|
},
|
|
2618
|
-
"
|
|
2619
|
-
"description": "[Deprecated alias: pointsExpiryMonths \u2014 renamed and converted months*30 to days by MIG-06]",
|
|
2620
|
-
"deprecated": true,
|
|
2820
|
+
"paidDate": {
|
|
2621
2821
|
"anyOf": [
|
|
2622
2822
|
{
|
|
2623
|
-
"
|
|
2624
|
-
"minimum": -9007199254740991,
|
|
2625
|
-
"maximum": 9007199254740991
|
|
2823
|
+
"$ref": "#/definitions/firestore-timestamp"
|
|
2626
2824
|
},
|
|
2627
2825
|
{
|
|
2628
2826
|
"type": "null"
|
|
2629
2827
|
}
|
|
2828
|
+
],
|
|
2829
|
+
"x-when": "Set when paymentStatus transitions to PAID (fully settled). Null for partially paid or unpaid expenses. For multi-payment history, read OutboundPaymentAllocation records (#19).",
|
|
2830
|
+
"description": "When the expense was fully settled (paymentStatus = PAID). Null otherwise."
|
|
2831
|
+
},
|
|
2832
|
+
"paymentReference": {
|
|
2833
|
+
"x-note": "Reference for the most recent payment transaction (check number, wire ID, Wave ref, etc.). Overwritten on each payment. For full payment history read OutboundPaymentAllocation records (#19).",
|
|
2834
|
+
"description": "Most recent payment transaction reference. Overwritten on each payment; not a full history.",
|
|
2835
|
+
"type": [
|
|
2836
|
+
"string",
|
|
2837
|
+
"null"
|
|
2630
2838
|
]
|
|
2631
2839
|
},
|
|
2840
|
+
"createdBy": {
|
|
2841
|
+
"type": "string",
|
|
2842
|
+
"x-immutable": true,
|
|
2843
|
+
"description": "(Immutable) FK \u2192 User/staff UID who created this expense record."
|
|
2844
|
+
},
|
|
2632
2845
|
"createdAt": {
|
|
2633
2846
|
"anyOf": [
|
|
2634
2847
|
{
|
|
@@ -2651,18 +2864,173 @@
|
|
|
2651
2864
|
}
|
|
2652
2865
|
],
|
|
2653
2866
|
"readOnly": true,
|
|
2654
|
-
"description": "(Read-only) Server-generated update timestamp."
|
|
2867
|
+
"description": "(Read-only) Server-generated last-update timestamp."
|
|
2655
2868
|
}
|
|
2656
2869
|
},
|
|
2657
2870
|
"required": [
|
|
2658
|
-
"
|
|
2659
|
-
"
|
|
2871
|
+
"companyId",
|
|
2872
|
+
"title",
|
|
2873
|
+
"amount",
|
|
2874
|
+
"currency",
|
|
2875
|
+
"paymentStatus",
|
|
2876
|
+
"createdBy"
|
|
2660
2877
|
],
|
|
2661
2878
|
"additionalProperties": false,
|
|
2662
|
-
"description": "
|
|
2879
|
+
"description": "Expense (GH#12/#13/#19 partial). Collection: companies/{companyId}/expenses/{expenseId}. Dual balance tracking: amountPaid/amountDue for simple expenses; allocatedAmount/balance (server-set) for allocation-settled expenses. OVERDUE excluded from stored enum \u2014 derive at read time. Full domain (Payee FK, Contract FK) in #20.",
|
|
2663
2880
|
"example": {
|
|
2664
2881
|
"id": null,
|
|
2665
|
-
"
|
|
2882
|
+
"companyId": "comp_xyz789",
|
|
2883
|
+
"title": "title",
|
|
2884
|
+
"description": null,
|
|
2885
|
+
"amount": 45000,
|
|
2886
|
+
"currency": "XOF",
|
|
2887
|
+
"dueDate": "dueDate",
|
|
2888
|
+
"paymentStatus": "paymentStatus",
|
|
2889
|
+
"amountDue": null,
|
|
2890
|
+
"amountPaid": null,
|
|
2891
|
+
"allocatedAmount": null,
|
|
2892
|
+
"balance": null,
|
|
2893
|
+
"paidDate": "pai_ref123",
|
|
2894
|
+
"paymentReference": null,
|
|
2895
|
+
"createdBy": "staff_k0f1",
|
|
2896
|
+
"createdAt": "createdAt",
|
|
2897
|
+
"updatedAt": "updatedAt"
|
|
2898
|
+
}
|
|
2899
|
+
},
|
|
2900
|
+
"expense-payment-status": {
|
|
2901
|
+
"type": "string",
|
|
2902
|
+
"enum": [
|
|
2903
|
+
"PENDING",
|
|
2904
|
+
"PARTIALLY_PAID",
|
|
2905
|
+
"PAID",
|
|
2906
|
+
"FAILED"
|
|
2907
|
+
],
|
|
2908
|
+
"x-note": "OVERDUE is intentionally excluded \u2014 it is never stored in Firestore. Compute it at read time: expense.paymentStatus !== PAID && expense.dueDate < now() (#13). Helper: isExpenseOverdue(expense: Expense): boolean.",
|
|
2909
|
+
"description": "Payment status of an Expense. Stored enum \u2014 OVERDUE is not stored, it is derived at read time from dueDate (#13)."
|
|
2910
|
+
},
|
|
2911
|
+
"fulfillment-status": {
|
|
2912
|
+
"type": "string",
|
|
2913
|
+
"enum": [
|
|
2914
|
+
"PREPARING",
|
|
2915
|
+
"PARTIALLY_SHIPPED",
|
|
2916
|
+
"SHIPPED",
|
|
2917
|
+
"IN_TRANSIT",
|
|
2918
|
+
"DELIVERED",
|
|
2919
|
+
"PICKED_UP"
|
|
2920
|
+
],
|
|
2921
|
+
"description": "Delivery/fulfillment lifecycle (D34). Optional \u2014 null for in-person orders."
|
|
2922
|
+
},
|
|
2923
|
+
"loyalty-config": {
|
|
2924
|
+
"type": "object",
|
|
2925
|
+
"properties": {
|
|
2926
|
+
"id": {
|
|
2927
|
+
"readOnly": true,
|
|
2928
|
+
"description": "(Read-only) Firestore document ID. Singleton doc \u2014 typically \"config\".",
|
|
2929
|
+
"type": [
|
|
2930
|
+
"string",
|
|
2931
|
+
"null"
|
|
2932
|
+
]
|
|
2933
|
+
},
|
|
2934
|
+
"isEnabled": {
|
|
2935
|
+
"type": "boolean"
|
|
2936
|
+
},
|
|
2937
|
+
"pointSystem": {
|
|
2938
|
+
"type": "string",
|
|
2939
|
+
"enum": [
|
|
2940
|
+
"SPENDING",
|
|
2941
|
+
"PRODUCT",
|
|
2942
|
+
"VISIT"
|
|
2943
|
+
],
|
|
2944
|
+
"description": "How points are earned: SPENDING (per currency spent), PRODUCT (per product purchased), or VISIT (per visit). SCREAMING_SNAKE per D04."
|
|
2945
|
+
},
|
|
2946
|
+
"pointsPerCurrency": {
|
|
2947
|
+
"description": "[Deprecated alias: pointsPerCurrencyUnit \u2014 renamed by MIG-06]",
|
|
2948
|
+
"deprecated": true,
|
|
2949
|
+
"type": [
|
|
2950
|
+
"number",
|
|
2951
|
+
"null"
|
|
2952
|
+
]
|
|
2953
|
+
},
|
|
2954
|
+
"pointsPerVisit": {
|
|
2955
|
+
"description": "Points earned per visit (when pointSystem is visit).",
|
|
2956
|
+
"type": [
|
|
2957
|
+
"number",
|
|
2958
|
+
"null"
|
|
2959
|
+
]
|
|
2960
|
+
},
|
|
2961
|
+
"pointValue": {
|
|
2962
|
+
"description": "Monetary value of one point for redemption.",
|
|
2963
|
+
"type": [
|
|
2964
|
+
"number",
|
|
2965
|
+
"null"
|
|
2966
|
+
]
|
|
2967
|
+
},
|
|
2968
|
+
"minimumRedeemPoints": {
|
|
2969
|
+
"description": "Minimum points balance required before redemption is allowed.",
|
|
2970
|
+
"type": [
|
|
2971
|
+
"integer",
|
|
2972
|
+
"null"
|
|
2973
|
+
],
|
|
2974
|
+
"minimum": -9007199254740991,
|
|
2975
|
+
"maximum": 9007199254740991
|
|
2976
|
+
},
|
|
2977
|
+
"welcomeBonusPoints": {
|
|
2978
|
+
"description": "One-time points bonus for new loyalty enrollees.",
|
|
2979
|
+
"type": [
|
|
2980
|
+
"integer",
|
|
2981
|
+
"null"
|
|
2982
|
+
],
|
|
2983
|
+
"minimum": -9007199254740991,
|
|
2984
|
+
"maximum": 9007199254740991
|
|
2985
|
+
},
|
|
2986
|
+
"pointsExpirationDays": {
|
|
2987
|
+
"description": "[Deprecated alias: pointsExpiryMonths \u2014 renamed and converted months*30 to days by MIG-06]",
|
|
2988
|
+
"deprecated": true,
|
|
2989
|
+
"anyOf": [
|
|
2990
|
+
{
|
|
2991
|
+
"type": "integer",
|
|
2992
|
+
"minimum": -9007199254740991,
|
|
2993
|
+
"maximum": 9007199254740991
|
|
2994
|
+
},
|
|
2995
|
+
{
|
|
2996
|
+
"type": "null"
|
|
2997
|
+
}
|
|
2998
|
+
]
|
|
2999
|
+
},
|
|
3000
|
+
"createdAt": {
|
|
3001
|
+
"anyOf": [
|
|
3002
|
+
{
|
|
3003
|
+
"$ref": "#/definitions/firestore-timestamp"
|
|
3004
|
+
},
|
|
3005
|
+
{
|
|
3006
|
+
"type": "null"
|
|
3007
|
+
}
|
|
3008
|
+
],
|
|
3009
|
+
"readOnly": true,
|
|
3010
|
+
"description": "(Read-only) Server-generated creation timestamp."
|
|
3011
|
+
},
|
|
3012
|
+
"updatedAt": {
|
|
3013
|
+
"anyOf": [
|
|
3014
|
+
{
|
|
3015
|
+
"$ref": "#/definitions/firestore-timestamp"
|
|
3016
|
+
},
|
|
3017
|
+
{
|
|
3018
|
+
"type": "null"
|
|
3019
|
+
}
|
|
3020
|
+
],
|
|
3021
|
+
"readOnly": true,
|
|
3022
|
+
"description": "(Read-only) Server-generated update timestamp."
|
|
3023
|
+
}
|
|
3024
|
+
},
|
|
3025
|
+
"required": [
|
|
3026
|
+
"isEnabled",
|
|
3027
|
+
"pointSystem"
|
|
3028
|
+
],
|
|
3029
|
+
"additionalProperties": false,
|
|
3030
|
+
"description": "LoyaltyConfig model (D21). Collection: companies/{companyId}/loyaltySettings/config. 1 doc per company. Uses canonical field names per D21 (MIG-06 renames legacy aliases).",
|
|
3031
|
+
"example": {
|
|
3032
|
+
"id": null,
|
|
3033
|
+
"isEnabled": true,
|
|
2666
3034
|
"pointSystem": "SPENDING",
|
|
2667
3035
|
"pointsPerCurrency": null,
|
|
2668
3036
|
"pointsPerVisit": null,
|
|
@@ -3170,6 +3538,7 @@
|
|
|
3170
3538
|
"orderCompletionRate30d": {
|
|
3171
3539
|
"type": "number",
|
|
3172
3540
|
"readOnly": true,
|
|
3541
|
+
"x-note": "Firestore REST API v1 writes integerValue when the stored value is whole (e.g. 0), doubleValue when fractional (e.g. 82.17). Admin SDK smooths this to a JS number; REST clients must coerce the union (#11).",
|
|
3173
3542
|
"description": "(Read-only) Percentage of orders completed or delivered in the last 30 days. Always full recalc."
|
|
3174
3543
|
},
|
|
3175
3544
|
"todayPurchasesCount": {
|
|
@@ -3187,11 +3556,13 @@
|
|
|
3187
3556
|
"averagePurchaseAmount": {
|
|
3188
3557
|
"type": "number",
|
|
3189
3558
|
"readOnly": true,
|
|
3559
|
+
"x-note": "Firestore REST API v1 writes integerValue when whole (e.g. 10070), doubleValue when fractional (e.g. 10006.5). Admin SDK smooths this; REST clients must coerce (#11).",
|
|
3190
3560
|
"description": "(Read-only) Average purchase value across last 200 purchases (rolling, not time-windowed)."
|
|
3191
3561
|
},
|
|
3192
3562
|
"monthlyRevenue": {
|
|
3193
3563
|
"type": "number",
|
|
3194
3564
|
"readOnly": true,
|
|
3565
|
+
"x-note": "Observed as integerValue on all sampled tenants (whole XOF amounts). Will be doubleValue if fractional. REST clients must coerce (#11).",
|
|
3195
3566
|
"description": "(Read-only) Total purchase value in the current calendar month (UTC)."
|
|
3196
3567
|
},
|
|
3197
3568
|
"monthlyPurchasesCount": {
|
|
@@ -3228,6 +3599,7 @@
|
|
|
3228
3599
|
"todayCollectedAmount": {
|
|
3229
3600
|
"type": "number",
|
|
3230
3601
|
"readOnly": true,
|
|
3602
|
+
"x-note": "Observed as integerValue \"0\" on all sampled tenants. Will be doubleValue if fractional payments occur. REST clients must coerce (#11).",
|
|
3231
3603
|
"description": "(Read-only) Sum of totalAmount for bookings where PAYMENT_PAID_AT is today. Resets at midnight."
|
|
3232
3604
|
},
|
|
3233
3605
|
"todayRevenue": {
|
|
@@ -3273,6 +3645,7 @@
|
|
|
3273
3645
|
"averageRating": {
|
|
3274
3646
|
"type": "number",
|
|
3275
3647
|
"readOnly": true,
|
|
3648
|
+
"x-note": "Observed as integerValue \"0\" on all tenants (no reviews yet). Will be doubleValue once real ratings exist. REST clients must coerce (#11).",
|
|
3276
3649
|
"description": "(Read-only) Average rating from the last 200 reviews (rolling). Always full recalc."
|
|
3277
3650
|
},
|
|
3278
3651
|
"lowStockItemsCount": {
|
|
@@ -3446,6 +3819,7 @@
|
|
|
3446
3819
|
"orderCompletionRate30d": {
|
|
3447
3820
|
"type": "number",
|
|
3448
3821
|
"readOnly": true,
|
|
3822
|
+
"x-note": "Firestore REST API v1 writes integerValue when the stored value is whole (e.g. 0), doubleValue when fractional (e.g. 82.17). Admin SDK smooths this to a JS number; REST clients must coerce the union (#11).",
|
|
3449
3823
|
"description": "(Read-only) Percentage of orders completed or delivered in the last 30 days. Always full recalc."
|
|
3450
3824
|
},
|
|
3451
3825
|
"todayPurchasesCount": {
|
|
@@ -3463,11 +3837,13 @@
|
|
|
3463
3837
|
"averagePurchaseAmount": {
|
|
3464
3838
|
"type": "number",
|
|
3465
3839
|
"readOnly": true,
|
|
3840
|
+
"x-note": "Firestore REST API v1 writes integerValue when whole (e.g. 10070), doubleValue when fractional (e.g. 10006.5). Admin SDK smooths this; REST clients must coerce (#11).",
|
|
3466
3841
|
"description": "(Read-only) Average purchase value across last 200 purchases (rolling, not time-windowed)."
|
|
3467
3842
|
},
|
|
3468
3843
|
"monthlyRevenue": {
|
|
3469
3844
|
"type": "number",
|
|
3470
3845
|
"readOnly": true,
|
|
3846
|
+
"x-note": "Observed as integerValue on all sampled tenants (whole XOF amounts). Will be doubleValue if fractional. REST clients must coerce (#11).",
|
|
3471
3847
|
"description": "(Read-only) Total purchase value in the current calendar month (UTC)."
|
|
3472
3848
|
},
|
|
3473
3849
|
"monthlyPurchasesCount": {
|
|
@@ -3504,6 +3880,7 @@
|
|
|
3504
3880
|
"todayCollectedAmount": {
|
|
3505
3881
|
"type": "number",
|
|
3506
3882
|
"readOnly": true,
|
|
3883
|
+
"x-note": "Observed as integerValue \"0\" on all sampled tenants. Will be doubleValue if fractional payments occur. REST clients must coerce (#11).",
|
|
3507
3884
|
"description": "(Read-only) Sum of totalAmount for bookings where PAYMENT_PAID_AT is today. Resets at midnight."
|
|
3508
3885
|
},
|
|
3509
3886
|
"todayRevenue": {
|
|
@@ -3549,6 +3926,7 @@
|
|
|
3549
3926
|
"averageRating": {
|
|
3550
3927
|
"type": "number",
|
|
3551
3928
|
"readOnly": true,
|
|
3929
|
+
"x-note": "Observed as integerValue \"0\" on all tenants (no reviews yet). Will be doubleValue once real ratings exist. REST clients must coerce (#11).",
|
|
3552
3930
|
"description": "(Read-only) Average rating from the last 200 reviews (rolling). Always full recalc."
|
|
3553
3931
|
},
|
|
3554
3932
|
"lowStockItemsCount": {
|
|
@@ -3616,8 +3994,8 @@
|
|
|
3616
3994
|
},
|
|
3617
3995
|
"paymentsByMethod": {
|
|
3618
3996
|
"readOnly": true,
|
|
3619
|
-
"x-note": "
|
|
3620
|
-
"description": "(Read-only, Optional)
|
|
3997
|
+
"x-note": "Map keys use short codes in practice (OM, CASH, WAVE) \u2014 OM is a non-canonical alias for ORANGE_MONEY emitted by the metrics writer (#21). Value shape { total, count } differs from MetricsCurrent.paymentsByMethod (bare number).",
|
|
3998
|
+
"description": "(Read-only, Optional) Payment breakdown by method for the day. Keys are PaymentMethod values (or legacy short code OM). Value is { total: XOF amount, count: number of payments }.",
|
|
3621
3999
|
"type": [
|
|
3622
4000
|
"object",
|
|
3623
4001
|
"null"
|
|
@@ -3626,7 +4004,24 @@
|
|
|
3626
4004
|
"type": "string"
|
|
3627
4005
|
},
|
|
3628
4006
|
"additionalProperties": {
|
|
3629
|
-
"type": "
|
|
4007
|
+
"type": "object",
|
|
4008
|
+
"properties": {
|
|
4009
|
+
"total": {
|
|
4010
|
+
"type": "number",
|
|
4011
|
+
"description": "Sum of payment amounts for this method on the given day (XOF)."
|
|
4012
|
+
},
|
|
4013
|
+
"count": {
|
|
4014
|
+
"type": "integer",
|
|
4015
|
+
"minimum": -9007199254740991,
|
|
4016
|
+
"maximum": 9007199254740991,
|
|
4017
|
+
"description": "Number of payments using this method on the given day."
|
|
4018
|
+
}
|
|
4019
|
+
},
|
|
4020
|
+
"required": [
|
|
4021
|
+
"total",
|
|
4022
|
+
"count"
|
|
4023
|
+
],
|
|
4024
|
+
"additionalProperties": false
|
|
3630
4025
|
}
|
|
3631
4026
|
},
|
|
3632
4027
|
"computedForDay": {
|
|
@@ -3674,7 +4069,8 @@
|
|
|
3674
4069
|
"date"
|
|
3675
4070
|
],
|
|
3676
4071
|
"additionalProperties": false,
|
|
3677
|
-
"
|
|
4072
|
+
"x-note": "Zero-activity behavior (#9): the computeDailyCompanyMetrics cron (02:00 UTC) does NOT write a snapshot for days with no activity. A missing document means either zero activity or the cron did not run \u2014 consumers cannot distinguish the two from the absence alone. To detect cron gaps, compare the latest document date with today; a gap larger than 1 day on an otherwise active tenant indicates a cron failure. Observed: 3 of 4 zahoui tenants had gaps; bingerville (active) had a document every day.",
|
|
4073
|
+
"description": "Daily metrics snapshot. Collection: companies/{companyId}/metrics_daily/{YYYY-MM-DD}. Same fields as MetricsCurrent plus `date`. Written by computeDailyCompanyMetrics cron (02:00 UTC) when the company had activity that day; zero-activity days may produce no document (#9).",
|
|
3678
4074
|
"example": {
|
|
3679
4075
|
"todayOrdersCount": 2,
|
|
3680
4076
|
"pendingOrdersCount": 2,
|
|
@@ -3729,6 +4125,7 @@
|
|
|
3729
4125
|
"orderCompletionRate30d": {
|
|
3730
4126
|
"type": "number",
|
|
3731
4127
|
"readOnly": true,
|
|
4128
|
+
"x-note": "Firestore REST API v1 writes integerValue when the stored value is whole (e.g. 0), doubleValue when fractional (e.g. 82.17). Admin SDK smooths this to a JS number; REST clients must coerce the union (#11).",
|
|
3732
4129
|
"description": "(Read-only) Percentage of orders completed or delivered in the last 30 days. Always full recalc."
|
|
3733
4130
|
},
|
|
3734
4131
|
"todayPurchasesCount": {
|
|
@@ -3746,11 +4143,13 @@
|
|
|
3746
4143
|
"averagePurchaseAmount": {
|
|
3747
4144
|
"type": "number",
|
|
3748
4145
|
"readOnly": true,
|
|
4146
|
+
"x-note": "Firestore REST API v1 writes integerValue when whole (e.g. 10070), doubleValue when fractional (e.g. 10006.5). Admin SDK smooths this; REST clients must coerce (#11).",
|
|
3749
4147
|
"description": "(Read-only) Average purchase value across last 200 purchases (rolling, not time-windowed)."
|
|
3750
4148
|
},
|
|
3751
4149
|
"monthlyRevenue": {
|
|
3752
4150
|
"type": "number",
|
|
3753
4151
|
"readOnly": true,
|
|
4152
|
+
"x-note": "Observed as integerValue on all sampled tenants (whole XOF amounts). Will be doubleValue if fractional. REST clients must coerce (#11).",
|
|
3754
4153
|
"description": "(Read-only) Total purchase value in the current calendar month (UTC)."
|
|
3755
4154
|
},
|
|
3756
4155
|
"monthlyPurchasesCount": {
|
|
@@ -3787,6 +4186,7 @@
|
|
|
3787
4186
|
"todayCollectedAmount": {
|
|
3788
4187
|
"type": "number",
|
|
3789
4188
|
"readOnly": true,
|
|
4189
|
+
"x-note": "Observed as integerValue \"0\" on all sampled tenants. Will be doubleValue if fractional payments occur. REST clients must coerce (#11).",
|
|
3790
4190
|
"description": "(Read-only) Sum of totalAmount for bookings where PAYMENT_PAID_AT is today. Resets at midnight."
|
|
3791
4191
|
},
|
|
3792
4192
|
"todayRevenue": {
|
|
@@ -3832,6 +4232,7 @@
|
|
|
3832
4232
|
"averageRating": {
|
|
3833
4233
|
"type": "number",
|
|
3834
4234
|
"readOnly": true,
|
|
4235
|
+
"x-note": "Observed as integerValue \"0\" on all tenants (no reviews yet). Will be doubleValue once real ratings exist. REST clients must coerce (#11).",
|
|
3835
4236
|
"description": "(Read-only) Average rating from the last 200 reviews (rolling). Always full recalc."
|
|
3836
4237
|
},
|
|
3837
4238
|
"lowStockItemsCount": {
|
|
@@ -3992,6 +4393,16 @@
|
|
|
3992
4393
|
"month": "month"
|
|
3993
4394
|
}
|
|
3994
4395
|
},
|
|
4396
|
+
"milestone-status": {
|
|
4397
|
+
"type": "string",
|
|
4398
|
+
"enum": [
|
|
4399
|
+
"PENDING",
|
|
4400
|
+
"INVOICED",
|
|
4401
|
+
"PAID"
|
|
4402
|
+
],
|
|
4403
|
+
"x-note": "OVERDUE is intentionally excluded \u2014 due-date derivation should be computed at read time from dueDate, not stored. Stored OVERDUE would require a cron to keep it consistent. Existing lowercase values (pending, invoiced, paid) from pre-schema documents need normalization on read or via migration (#17).",
|
|
4404
|
+
"description": "Status of a ContractMilestone (#17). PENDING = created, not yet invoiced. INVOICED = invoice issued, awaiting payment. PAID = payment received."
|
|
4405
|
+
},
|
|
3995
4406
|
"notification-channel": {
|
|
3996
4407
|
"type": "string",
|
|
3997
4408
|
"enum": [
|
|
@@ -4288,6 +4699,15 @@
|
|
|
4288
4699
|
"readOnly": true,
|
|
4289
4700
|
"description": "(Read-only) Server-generated order number."
|
|
4290
4701
|
},
|
|
4702
|
+
"followUpUrl": {
|
|
4703
|
+
"x-note": "Standardized casing is followUpUrl (not followUpURL). Mobile legacy code reads both casings for backward compat but writes followUpUrl going forward (#6).",
|
|
4704
|
+
"x-when": "Used by mobile to generate QR codes on printed receipts. If absent, the mobile app derives a deterministic fallback: https://zahoui.web.app/reviews?orderNumber={orderNumber}.",
|
|
4705
|
+
"description": "Optional URL for receipt QR code / post-order follow-up. Canonical casing: followUpUrl (#6).",
|
|
4706
|
+
"type": [
|
|
4707
|
+
"string",
|
|
4708
|
+
"null"
|
|
4709
|
+
]
|
|
4710
|
+
},
|
|
4291
4711
|
"status": {
|
|
4292
4712
|
"$ref": "#/definitions/order-status",
|
|
4293
4713
|
"description": "Core lifecycle status (D34, MIG-11). See OrderStatus enum for the legacy value migration mapping.",
|
|
@@ -4457,7 +4877,7 @@
|
|
|
4457
4877
|
"type": "null"
|
|
4458
4878
|
}
|
|
4459
4879
|
],
|
|
4460
|
-
"description": "Unified payment method set with African + global methods (D02)."
|
|
4880
|
+
"description": "Unified payment method set with African + global methods (D02). Note: the metrics writer historically emits \"OM\" instead of \"ORANGE_MONEY\" as a paymentsByMethod map key \u2014 treat OM as deprecated; canonical value is ORANGE_MONEY (#21)."
|
|
4461
4881
|
},
|
|
4462
4882
|
"invoiceId": {
|
|
4463
4883
|
"description": "FK \u2192 Invoice document ID.",
|
|
@@ -4874,6 +5294,7 @@
|
|
|
4874
5294
|
"companyId": "comp_xyz789",
|
|
4875
5295
|
"appId": null,
|
|
4876
5296
|
"orderNumber": "ORD-2026-0042",
|
|
5297
|
+
"followUpUrl": null,
|
|
4877
5298
|
"status": "status",
|
|
4878
5299
|
"paymentStatus": "paymentStatus",
|
|
4879
5300
|
"fulfillmentStatus": "fulfillmentStatus",
|
|
@@ -5196,6 +5617,191 @@
|
|
|
5196
5617
|
],
|
|
5197
5618
|
"description": "Outbound WhatsApp message delivery status. Lifecycle: queued \u2192 sent \u2192 delivered \u2192 read, or queued \u2192 failed. The dashboard creates the message with status `queued`; the whatsapp-server backend owns every transition after, updating in place from Meta delivery callbacks (GH#43)."
|
|
5198
5619
|
},
|
|
5620
|
+
"outbound-payment": {
|
|
5621
|
+
"type": "object",
|
|
5622
|
+
"properties": {
|
|
5623
|
+
"id": {
|
|
5624
|
+
"readOnly": true,
|
|
5625
|
+
"description": "(Read-only) Firestore document ID, auto-generated.",
|
|
5626
|
+
"type": [
|
|
5627
|
+
"string",
|
|
5628
|
+
"null"
|
|
5629
|
+
]
|
|
5630
|
+
},
|
|
5631
|
+
"companyId": {
|
|
5632
|
+
"type": "string",
|
|
5633
|
+
"x-immutable": true,
|
|
5634
|
+
"description": "(Immutable) FK \u2192 Company document ID."
|
|
5635
|
+
},
|
|
5636
|
+
"payeeId": {
|
|
5637
|
+
"type": "string",
|
|
5638
|
+
"x-immutable": true,
|
|
5639
|
+
"description": "(Immutable) FK \u2192 Payee document ID. Full Payee model tracked in #20."
|
|
5640
|
+
},
|
|
5641
|
+
"contractId": {
|
|
5642
|
+
"x-immutable": true,
|
|
5643
|
+
"description": "(Immutable, Optional) FK \u2192 Contract document ID. Absent for ad-hoc payments outside a formal contract.",
|
|
5644
|
+
"type": [
|
|
5645
|
+
"string",
|
|
5646
|
+
"null"
|
|
5647
|
+
]
|
|
5648
|
+
},
|
|
5649
|
+
"amount": {
|
|
5650
|
+
"type": "number",
|
|
5651
|
+
"description": "Amount paid (XOF)."
|
|
5652
|
+
},
|
|
5653
|
+
"currency": {
|
|
5654
|
+
"type": "string",
|
|
5655
|
+
"const": "XOF",
|
|
5656
|
+
"description": "Currency code. Locked to XOF \u2014 consistent with Contract and CustomerPayment."
|
|
5657
|
+
},
|
|
5658
|
+
"method": {
|
|
5659
|
+
"$ref": "#/definitions/payment-method",
|
|
5660
|
+
"description": "Payment method used (e.g. BANK_TRANSFER, MOBILE_MONEY, CHECK)."
|
|
5661
|
+
},
|
|
5662
|
+
"reference": {
|
|
5663
|
+
"description": "Optional payment reference \u2014 bank transaction number, check number, Wave ref, etc.",
|
|
5664
|
+
"type": [
|
|
5665
|
+
"string",
|
|
5666
|
+
"null"
|
|
5667
|
+
]
|
|
5668
|
+
},
|
|
5669
|
+
"paidAt": {
|
|
5670
|
+
"$ref": "#/definitions/firestore-timestamp",
|
|
5671
|
+
"description": "When the payment was made."
|
|
5672
|
+
},
|
|
5673
|
+
"notes": {
|
|
5674
|
+
"description": "Optional internal notes.",
|
|
5675
|
+
"type": [
|
|
5676
|
+
"string",
|
|
5677
|
+
"null"
|
|
5678
|
+
]
|
|
5679
|
+
},
|
|
5680
|
+
"createdBy": {
|
|
5681
|
+
"type": "string",
|
|
5682
|
+
"x-immutable": true,
|
|
5683
|
+
"description": "(Immutable) FK \u2192 User/staff UID who recorded the payment."
|
|
5684
|
+
},
|
|
5685
|
+
"createdAt": {
|
|
5686
|
+
"anyOf": [
|
|
5687
|
+
{
|
|
5688
|
+
"$ref": "#/definitions/firestore-timestamp"
|
|
5689
|
+
},
|
|
5690
|
+
{
|
|
5691
|
+
"type": "null"
|
|
5692
|
+
}
|
|
5693
|
+
],
|
|
5694
|
+
"readOnly": true,
|
|
5695
|
+
"description": "(Read-only) Server-generated creation timestamp."
|
|
5696
|
+
},
|
|
5697
|
+
"updatedAt": {
|
|
5698
|
+
"anyOf": [
|
|
5699
|
+
{
|
|
5700
|
+
"$ref": "#/definitions/firestore-timestamp"
|
|
5701
|
+
},
|
|
5702
|
+
{
|
|
5703
|
+
"type": "null"
|
|
5704
|
+
}
|
|
5705
|
+
],
|
|
5706
|
+
"readOnly": true,
|
|
5707
|
+
"description": "(Read-only) Server-generated update timestamp."
|
|
5708
|
+
}
|
|
5709
|
+
},
|
|
5710
|
+
"required": [
|
|
5711
|
+
"companyId",
|
|
5712
|
+
"payeeId",
|
|
5713
|
+
"amount",
|
|
5714
|
+
"currency",
|
|
5715
|
+
"method",
|
|
5716
|
+
"paidAt",
|
|
5717
|
+
"createdBy"
|
|
5718
|
+
],
|
|
5719
|
+
"additionalProperties": false,
|
|
5720
|
+
"description": "OutboundPayment (GH#15). Collection: companies/{companyId}/outboundPayments/{paymentId}. Single outbound transfer to a Payee. Canonical name chosen over SupplierPayment/VendorPayment \u2014 direction-based, agnostic of payee type. Currency locked to XOF.",
|
|
5721
|
+
"example": {
|
|
5722
|
+
"id": null,
|
|
5723
|
+
"companyId": "comp_xyz789",
|
|
5724
|
+
"payeeId": "pay_ref123",
|
|
5725
|
+
"contractId": null,
|
|
5726
|
+
"amount": 45000,
|
|
5727
|
+
"currency": "XOF",
|
|
5728
|
+
"method": "method",
|
|
5729
|
+
"reference": null,
|
|
5730
|
+
"paidAt": "pai_ref123",
|
|
5731
|
+
"notes": null,
|
|
5732
|
+
"createdBy": "staff_k0f1",
|
|
5733
|
+
"createdAt": "createdAt",
|
|
5734
|
+
"updatedAt": "updatedAt"
|
|
5735
|
+
}
|
|
5736
|
+
},
|
|
5737
|
+
"outbound-payment-allocation": {
|
|
5738
|
+
"type": "object",
|
|
5739
|
+
"properties": {
|
|
5740
|
+
"id": {
|
|
5741
|
+
"readOnly": true,
|
|
5742
|
+
"description": "(Read-only) Firestore document ID, auto-generated.",
|
|
5743
|
+
"type": [
|
|
5744
|
+
"string",
|
|
5745
|
+
"null"
|
|
5746
|
+
]
|
|
5747
|
+
},
|
|
5748
|
+
"outboundPaymentId": {
|
|
5749
|
+
"type": "string",
|
|
5750
|
+
"x-immutable": true,
|
|
5751
|
+
"description": "(Immutable) FK \u2192 OutboundPayment document ID (parent)."
|
|
5752
|
+
},
|
|
5753
|
+
"expenseId": {
|
|
5754
|
+
"type": "string",
|
|
5755
|
+
"x-immutable": true,
|
|
5756
|
+
"description": "(Immutable) FK \u2192 Expense document ID. Full Expense model tracked in #20."
|
|
5757
|
+
},
|
|
5758
|
+
"companyId": {
|
|
5759
|
+
"type": "string",
|
|
5760
|
+
"x-immutable": true,
|
|
5761
|
+
"description": "(Immutable) FK \u2192 Company document ID. Denormalized for collection-group queries."
|
|
5762
|
+
},
|
|
5763
|
+
"amount": {
|
|
5764
|
+
"type": "number",
|
|
5765
|
+
"description": "Amount of this payment allocated to the referenced expense (XOF)."
|
|
5766
|
+
},
|
|
5767
|
+
"notes": {
|
|
5768
|
+
"description": "Optional notes about this allocation.",
|
|
5769
|
+
"type": [
|
|
5770
|
+
"string",
|
|
5771
|
+
"null"
|
|
5772
|
+
]
|
|
5773
|
+
},
|
|
5774
|
+
"allocatedAt": {
|
|
5775
|
+
"anyOf": [
|
|
5776
|
+
{
|
|
5777
|
+
"$ref": "#/definitions/firestore-timestamp"
|
|
5778
|
+
},
|
|
5779
|
+
{
|
|
5780
|
+
"type": "null"
|
|
5781
|
+
}
|
|
5782
|
+
],
|
|
5783
|
+
"readOnly": true,
|
|
5784
|
+
"description": "(Read-only) When this allocation was recorded."
|
|
5785
|
+
}
|
|
5786
|
+
},
|
|
5787
|
+
"required": [
|
|
5788
|
+
"outboundPaymentId",
|
|
5789
|
+
"expenseId",
|
|
5790
|
+
"companyId",
|
|
5791
|
+
"amount"
|
|
5792
|
+
],
|
|
5793
|
+
"additionalProperties": false,
|
|
5794
|
+
"description": "OutboundPaymentAllocation (GH#15). Subcollection: companies/{companyId}/outboundPayments/{paymentId}/allocations/{allocationId}. Links an OutboundPayment to an Expense. Supports partial and multi-expense allocations.",
|
|
5795
|
+
"example": {
|
|
5796
|
+
"id": null,
|
|
5797
|
+
"outboundPaymentId": "out_ref123",
|
|
5798
|
+
"expenseId": "exp_ref123",
|
|
5799
|
+
"companyId": "comp_xyz789",
|
|
5800
|
+
"amount": 45000,
|
|
5801
|
+
"notes": null,
|
|
5802
|
+
"allocatedAt": "allocatedAt"
|
|
5803
|
+
}
|
|
5804
|
+
},
|
|
5199
5805
|
"payment-method": {
|
|
5200
5806
|
"type": "string",
|
|
5201
5807
|
"enum": [
|
|
@@ -5208,9 +5814,10 @@
|
|
|
5208
5814
|
"BANK_TRANSFER",
|
|
5209
5815
|
"PAYPAL",
|
|
5210
5816
|
"STRIPE",
|
|
5211
|
-
"OTHER"
|
|
5817
|
+
"OTHER",
|
|
5818
|
+
"OM"
|
|
5212
5819
|
],
|
|
5213
|
-
"description": "Unified payment method set with African + global methods (D02)."
|
|
5820
|
+
"description": "Unified payment method set with African + global methods (D02). Note: the metrics writer historically emits \"OM\" instead of \"ORANGE_MONEY\" as a paymentsByMethod map key \u2014 treat OM as deprecated; canonical value is ORANGE_MONEY (#21)."
|
|
5214
5821
|
},
|
|
5215
5822
|
"payment-proof-status": {
|
|
5216
5823
|
"type": "string",
|
|
@@ -5234,6 +5841,198 @@
|
|
|
5234
5841
|
],
|
|
5235
5842
|
"description": "Payment lifecycle status (D01 amended). Used by Order, Sale/Purchase, Booking."
|
|
5236
5843
|
},
|
|
5844
|
+
"payment-webhook-delivery": {
|
|
5845
|
+
"type": "object",
|
|
5846
|
+
"properties": {
|
|
5847
|
+
"id": {
|
|
5848
|
+
"readOnly": true,
|
|
5849
|
+
"description": "(Read-only) Firestore document ID, auto-generated.",
|
|
5850
|
+
"type": [
|
|
5851
|
+
"string",
|
|
5852
|
+
"null"
|
|
5853
|
+
]
|
|
5854
|
+
},
|
|
5855
|
+
"company": {
|
|
5856
|
+
"type": "string",
|
|
5857
|
+
"x-immutable": true,
|
|
5858
|
+
"description": "(Immutable) Company document ID (e.g. \"gerko_studios\"). Resolved from the matched endpoint at delivery time."
|
|
5859
|
+
},
|
|
5860
|
+
"provider": {
|
|
5861
|
+
"type": "string",
|
|
5862
|
+
"x-note": "Observed value: \"jeko\". The inner payload.paymentMethod may differ (e.g. \"wave\") \u2014 provider here is the webhook sender, not the payment rail (#42).",
|
|
5863
|
+
"description": "Payment provider that sent this webhook (e.g. \"jeko\", \"wave\")."
|
|
5864
|
+
},
|
|
5865
|
+
"eventType": {
|
|
5866
|
+
"type": "string",
|
|
5867
|
+
"x-note": "Observed value: \"transaction.payment\". Jeko docs say \"transaction.completed\" \u2014 full set per provider unconfirmed (#42). Use z.string() to avoid rejecting unseen values.",
|
|
5868
|
+
"description": "Provider-defined event type. Observed: \"transaction.payment\". Full set per provider TBD (#42)."
|
|
5869
|
+
},
|
|
5870
|
+
"status": {
|
|
5871
|
+
"type": "string",
|
|
5872
|
+
"x-note": "Observed values: \"success\", \"error\". Indicates whether the webhook was processed without errors.",
|
|
5873
|
+
"description": "Processing outcome. Observed values: \"success\" | \"error\"."
|
|
5874
|
+
},
|
|
5875
|
+
"verified": {
|
|
5876
|
+
"type": "string",
|
|
5877
|
+
"x-note": "Observed value: \"verified\". Indicates HMAC-SHA256 signature verification result. Full set of failure values unconfirmed (#42).",
|
|
5878
|
+
"description": "Signature verification result. Observed: \"verified\". Other values (e.g. \"unverified\", \"error\") may exist but are unconfirmed."
|
|
5879
|
+
},
|
|
5880
|
+
"endpointStatus": {
|
|
5881
|
+
"type": "string",
|
|
5882
|
+
"x-note": "Observed value: \"matched\". Indicates whether the token resolved to a known PaymentWebhookEndpoint. Other values (e.g. \"not_found\", \"inactive\") unconfirmed (#42).",
|
|
5883
|
+
"description": "Endpoint resolution result. Observed: \"matched\". Other values unconfirmed (#42)."
|
|
5884
|
+
},
|
|
5885
|
+
"processed": {
|
|
5886
|
+
"type": "boolean",
|
|
5887
|
+
"x-note": "Set to true once the delivery has been reconciled to the AppPayment ledger (companies/{cid}/apps/{appId}/payments). Back-reference FK not stored on this doc \u2014 reconciliation is tracked on the AppPayment side.",
|
|
5888
|
+
"description": "Whether this delivery has been reconciled to the AppPayment ledger."
|
|
5889
|
+
},
|
|
5890
|
+
"reference": {
|
|
5891
|
+
"type": "string",
|
|
5892
|
+
"x-note": "Equals payload.id (provider transaction ID). Used as dedup key \u2014 the backend checks this before processing (#42 ask 3).",
|
|
5893
|
+
"description": "Provider transaction ID (= payload.id). Canonical dedup key."
|
|
5894
|
+
},
|
|
5895
|
+
"amount": {
|
|
5896
|
+
"type": "number",
|
|
5897
|
+
"description": "Payment amount, denormalized from payload.amount.amount (XOF)."
|
|
5898
|
+
},
|
|
5899
|
+
"currency": {
|
|
5900
|
+
"type": "string",
|
|
5901
|
+
"description": "Currency code, denormalized from payload.amount.currency (e.g. \"XOF\")."
|
|
5902
|
+
},
|
|
5903
|
+
"payload": {
|
|
5904
|
+
"type": "object",
|
|
5905
|
+
"propertyNames": {
|
|
5906
|
+
"type": "string"
|
|
5907
|
+
},
|
|
5908
|
+
"additionalProperties": {},
|
|
5909
|
+
"x-note": "Parsed provider request body. Contains PII: counterpartIdentifier and counterpartLabel hold customer phone numbers. Retention/TTL policy TBD (#42 ask 5).",
|
|
5910
|
+
"description": "Full parsed provider payload. Shape varies by provider. Contains PII (customer phone). See x-note for retention policy status."
|
|
5911
|
+
},
|
|
5912
|
+
"rawBody": {
|
|
5913
|
+
"type": "string",
|
|
5914
|
+
"x-note": "Verbatim request body string used for HMAC-SHA256 signature verification. Contains same PII as payload. Retention/TTL policy TBD (#42 ask 5).",
|
|
5915
|
+
"description": "Verbatim raw request body \u2014 used for HMAC-SHA256 verification. Contains PII."
|
|
5916
|
+
},
|
|
5917
|
+
"headers": {
|
|
5918
|
+
"x-note": "Request headers including provider signature (e.g. \"jeko-signature\") and tracing headers. Sensitive \u2014 do not expose to clients.",
|
|
5919
|
+
"description": "Incoming HTTP headers. Includes provider signature header and Sentry trace. Sensitive.",
|
|
5920
|
+
"type": [
|
|
5921
|
+
"object",
|
|
5922
|
+
"null"
|
|
5923
|
+
],
|
|
5924
|
+
"propertyNames": {
|
|
5925
|
+
"type": "string"
|
|
5926
|
+
},
|
|
5927
|
+
"additionalProperties": {
|
|
5928
|
+
"type": "string"
|
|
5929
|
+
}
|
|
5930
|
+
},
|
|
5931
|
+
"receivedAt": {
|
|
5932
|
+
"$ref": "#/definitions/firestore-timestamp",
|
|
5933
|
+
"description": "When the webhook delivery was received by the backend."
|
|
5934
|
+
}
|
|
5935
|
+
},
|
|
5936
|
+
"required": [
|
|
5937
|
+
"company",
|
|
5938
|
+
"provider",
|
|
5939
|
+
"eventType",
|
|
5940
|
+
"status",
|
|
5941
|
+
"verified",
|
|
5942
|
+
"endpointStatus",
|
|
5943
|
+
"processed",
|
|
5944
|
+
"reference",
|
|
5945
|
+
"amount",
|
|
5946
|
+
"currency",
|
|
5947
|
+
"payload",
|
|
5948
|
+
"rawBody",
|
|
5949
|
+
"receivedAt"
|
|
5950
|
+
],
|
|
5951
|
+
"additionalProperties": false,
|
|
5952
|
+
"x-internal": true,
|
|
5953
|
+
"description": "PaymentWebhookDelivery (GH#42). Collection: payment_webhooks/{deliveryId} (top-level). One document per received provider callback. Contains raw payload + verification outcome. x-internal: written/read only by backend; dashboard reads via admin UI. PII in payload/rawBody \u2014 retention policy TBD.",
|
|
5954
|
+
"example": {
|
|
5955
|
+
"id": null,
|
|
5956
|
+
"company": "company",
|
|
5957
|
+
"provider": "pro_ref123",
|
|
5958
|
+
"eventType": "eventType",
|
|
5959
|
+
"status": "status",
|
|
5960
|
+
"verified": "verified",
|
|
5961
|
+
"endpointStatus": "endpointStatus",
|
|
5962
|
+
"processed": true,
|
|
5963
|
+
"reference": "reference",
|
|
5964
|
+
"amount": 45000,
|
|
5965
|
+
"currency": "XOF",
|
|
5966
|
+
"payload": {},
|
|
5967
|
+
"rawBody": "rawBody",
|
|
5968
|
+
"headers": null,
|
|
5969
|
+
"receivedAt": "receivedAt"
|
|
5970
|
+
}
|
|
5971
|
+
},
|
|
5972
|
+
"payment-webhook-endpoint": {
|
|
5973
|
+
"type": "object",
|
|
5974
|
+
"properties": {
|
|
5975
|
+
"token": {
|
|
5976
|
+
"type": "string",
|
|
5977
|
+
"x-immutable": true,
|
|
5978
|
+
"description": "(Immutable) base64url-encoded 24-byte random token. Also the Firestore document ID and the URL path segment."
|
|
5979
|
+
},
|
|
5980
|
+
"company": {
|
|
5981
|
+
"type": "string",
|
|
5982
|
+
"x-immutable": true,
|
|
5983
|
+
"description": "(Immutable) Company slug (e.g. gerko_studios). Identifies the tenant that owns this endpoint."
|
|
5984
|
+
},
|
|
5985
|
+
"provider": {
|
|
5986
|
+
"type": "string",
|
|
5987
|
+
"enum": [
|
|
5988
|
+
"wave",
|
|
5989
|
+
"jeko"
|
|
5990
|
+
],
|
|
5991
|
+
"x-immutable": true,
|
|
5992
|
+
"description": "(Immutable) Payment provider whose webhooks this endpoint accepts."
|
|
5993
|
+
},
|
|
5994
|
+
"secret": {
|
|
5995
|
+
"type": "string",
|
|
5996
|
+
"x-note": "Provider-specific webhook signing secret. Used to verify HMAC-SHA256 signatures on inbound payloads. Never expose to clients.",
|
|
5997
|
+
"readOnly": true,
|
|
5998
|
+
"description": "Webhook signing secret for HMAC verification. Backend-only \u2014 never returned to dashboard or mobile clients."
|
|
5999
|
+
},
|
|
6000
|
+
"active": {
|
|
6001
|
+
"type": "boolean",
|
|
6002
|
+
"description": "Whether this endpoint is currently active. Inactive endpoints reject incoming webhooks."
|
|
6003
|
+
},
|
|
6004
|
+
"createdAt": {
|
|
6005
|
+
"anyOf": [
|
|
6006
|
+
{
|
|
6007
|
+
"$ref": "#/definitions/firestore-timestamp"
|
|
6008
|
+
},
|
|
6009
|
+
{
|
|
6010
|
+
"type": "null"
|
|
6011
|
+
}
|
|
6012
|
+
],
|
|
6013
|
+
"readOnly": true,
|
|
6014
|
+
"description": "(Read-only) When this endpoint was provisioned."
|
|
6015
|
+
}
|
|
6016
|
+
},
|
|
6017
|
+
"required": [
|
|
6018
|
+
"token",
|
|
6019
|
+
"company",
|
|
6020
|
+
"provider",
|
|
6021
|
+
"secret",
|
|
6022
|
+
"active"
|
|
6023
|
+
],
|
|
6024
|
+
"additionalProperties": false,
|
|
6025
|
+
"x-internal": true,
|
|
6026
|
+
"description": "PaymentWebhookEndpoint (GH#41). Collection: payment_webhook_endpoints/{token}. Top-level, not tenant-scoped. Provisioned by superadmin; used by the backend to verify inbound payment webhooks from Wave and Jeko. The delivery log collection (raw webhook payloads + verification outcomes) is tracked in GH#41 \u2014 shape TBD.",
|
|
6027
|
+
"example": {
|
|
6028
|
+
"token": "token",
|
|
6029
|
+
"company": "company",
|
|
6030
|
+
"provider": "wave",
|
|
6031
|
+
"secret": "secret",
|
|
6032
|
+
"active": true,
|
|
6033
|
+
"createdAt": "createdAt"
|
|
6034
|
+
}
|
|
6035
|
+
},
|
|
5237
6036
|
"pending-issue": {
|
|
5238
6037
|
"type": "string",
|
|
5239
6038
|
"enum": [
|
|
@@ -6431,7 +7230,8 @@
|
|
|
6431
7230
|
"cmz",
|
|
6432
7231
|
"val"
|
|
6433
7232
|
],
|
|
6434
|
-
"
|
|
7233
|
+
"x-note": "cmz = \"IngenX - Chez Miss Zahoui\", phone number ID 446424085225188, used for chez_miss_zahoui_* companies. val = \"IngenX - Valets\", phone number ID 425582173979125, used for all other companies. Templates are approved at WABA level \u2014 if cmz and val share a WABA ID, all templates are available to both. Routing logic: functions/src/orders/order.ts#isSender2Company. See messaging/whatsapp-platform-constraints (#50).",
|
|
7234
|
+
"description": "WABA label identifying which Meta Business Account sent/received the message. cmz = Chez Miss Zahoui sender; val = Valets sender. See WhatsApp platform constraints doc (#50)."
|
|
6435
7235
|
},
|
|
6436
7236
|
"whatsapp-button-sub-type": {
|
|
6437
7237
|
"type": "string",
|
|
@@ -6459,6 +7259,7 @@
|
|
|
6459
7259
|
},
|
|
6460
7260
|
"waba": {
|
|
6461
7261
|
"$ref": "#/definitions/waba-label",
|
|
7262
|
+
"x-note": "cmz = \"IngenX - Chez Miss Zahoui\", phone number ID 446424085225188, used for chez_miss_zahoui_* companies. val = \"IngenX - Valets\", phone number ID 425582173979125, used for all other companies. Templates are approved at WABA level \u2014 if cmz and val share a WABA ID, all templates are available to both. Routing logic: functions/src/orders/order.ts#isSender2Company. See messaging/whatsapp-platform-constraints (#50).",
|
|
6462
7263
|
"description": "(Immutable) Human-readable WABA label (cmz | val). See WabaLabel enum.",
|
|
6463
7264
|
"x-immutable": true
|
|
6464
7265
|
},
|
|
@@ -6716,10 +7517,13 @@
|
|
|
6716
7517
|
"to": {
|
|
6717
7518
|
"type": "string",
|
|
6718
7519
|
"x-immutable": true,
|
|
6719
|
-
"
|
|
7520
|
+
"x-note": "This is the Meta wa_id (digits only, no leading +), NOT a literal E.164 string. Meta normalizes phone numbers in non-obvious ways (e.g. +2250777471485 \u2192 wa_id 22577471485, dropping the trunk zero). The only reliable source is Meta's contacts[].wa_id from the send response \u2014 do not derive from E.164 by stripping + alone. The dashboard conversational sends and the whatsapp-server OTP path both use the wa_id form. Confirmed in prod: ING-368.",
|
|
7521
|
+
"x-when": "Set at enqueue time to the recipient's Meta wa_id. Use inbound WhatsappInboundMessage.from (also wa_id) as the join key for the conversation thread.",
|
|
7522
|
+
"description": "(Immutable) Recipient Meta wa_id \u2014 digits only, no leading + (e.g. 22577471485). Equal to the inbound `from` for the same conversation. NOT literal E.164; see x-note (#54)."
|
|
6720
7523
|
},
|
|
6721
7524
|
"waba": {
|
|
6722
7525
|
"$ref": "#/definitions/waba-label",
|
|
7526
|
+
"x-note": "cmz = \"IngenX - Chez Miss Zahoui\", phone number ID 446424085225188, used for chez_miss_zahoui_* companies. val = \"IngenX - Valets\", phone number ID 425582173979125, used for all other companies. Templates are approved at WABA level \u2014 if cmz and val share a WABA ID, all templates are available to both. Routing logic: functions/src/orders/order.ts#isSender2Company. See messaging/whatsapp-platform-constraints (#50).",
|
|
6723
7527
|
"description": "(Immutable) WABA that will send the message. Mirrors inbound `waba`.",
|
|
6724
7528
|
"x-immutable": true
|
|
6725
7529
|
},
|
|
@@ -6826,6 +7630,7 @@
|
|
|
6826
7630
|
},
|
|
6827
7631
|
"wamid": {
|
|
6828
7632
|
"readOnly": true,
|
|
7633
|
+
"x-note": "Useful for audit and dedup. Does NOT enable reply-threading for template messages \u2014 Meta silently ignores context.message_id on templates. Threading only works for kind=text within the 24-hour service window (#50).",
|
|
6829
7634
|
"description": "(Read-only) WhatsApp message ID returned by Meta once the backend sends. Absent while queued or on failure.",
|
|
6830
7635
|
"type": [
|
|
6831
7636
|
"string",
|
|
@@ -6936,6 +7741,7 @@
|
|
|
6936
7741
|
},
|
|
6937
7742
|
"waba": {
|
|
6938
7743
|
"$ref": "#/definitions/waba-label",
|
|
7744
|
+
"x-note": "cmz = \"IngenX - Chez Miss Zahoui\", phone number ID 446424085225188, used for chez_miss_zahoui_* companies. val = \"IngenX - Valets\", phone number ID 425582173979125, used for all other companies. Templates are approved at WABA level \u2014 if cmz and val share a WABA ID, all templates are available to both. Routing logic: functions/src/orders/order.ts#isSender2Company. See messaging/whatsapp-platform-constraints (#50).",
|
|
6939
7745
|
"description": "(Read-only) WABA label this template is approved on. Templates are WABA-scoped. Mirrors WhatsappOutboundMessage.waba.",
|
|
6940
7746
|
"readOnly": true
|
|
6941
7747
|
},
|