platform-types 1.10.699 → 1.10.701

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.
@@ -1,40 +1,8 @@
1
1
  declare global {
2
- type MpRefundRequest = ({
2
+ type MpRefundRequest = {
3
3
  amount?: number;
4
4
  reason?: string;
5
- mode?: never;
6
- } | {
7
- mode: 'resume';
8
- amount?: never;
9
- reason?: never;
10
- }) & TerminalElevationAuthorization;
11
- /** Exact provider outcome without a local monetary refund stamp. */
12
- type MpRefundProviderOutcomeResponse = {
13
- message: string;
14
- data: {
15
- paymentId: string;
16
- refundId: string;
17
- amount: number;
18
- status: 'in_process' | 'rejected';
19
- recordedLocally: false;
20
- /** False for initial POST; true for history-only recovery. */
21
- recovered: boolean;
22
- };
23
- };
24
- type MpRefundResumeResponse = {
25
- message: string;
26
- data: {
27
- paymentId: string;
28
- refundId: string;
29
- amount: number | null;
30
- status: string;
31
- type: 'partial';
32
- reconciled: boolean;
33
- reconcileReason?: string;
34
- recordedLocally: true;
35
- recovered: true;
36
- };
37
- } | MpRefundProviderOutcomeResponse;
5
+ } & TerminalElevationAuthorization;
38
6
  /**
39
7
  * Device fetched from `GET /point/integration-api/devices` (BE → FE so the
40
8
  * admin can pick which physical device receives a payment intent).
@@ -78,49 +46,33 @@ declare global {
78
46
  }
79
47
  interface MpPointIntentRequest {
80
48
  deviceId: string;
81
- /** Order portion in ARS major units; tip is charged in addition. */
49
+ /** Charge in ARS major units. */
82
50
  amount: number;
83
51
  currency: 'ARS';
84
52
  externalReference: string;
85
53
  ticketNumber?: string;
86
54
  printOnTerminal?: boolean;
87
- /** Positive, cent-exact ARS major units, no greater than amount. Recipient defaults to cashier. */
88
- tip?: {
89
- amount: number;
90
- recipientUserId?: string;
91
- };
92
55
  }
93
56
  interface MpPointIntentResponse {
94
57
  message: string;
95
58
  data: {
96
59
  intentId: string | null;
97
60
  deviceId: string;
98
- /** Gross provider charge in ARS major units. */
61
+ /** Charge in ARS major units. */
99
62
  amount: number;
100
63
  currency: 'ARS';
101
- /** Resolved caller reference, before the server-owned tip carrier. */
64
+ /** Resolved caller reference. */
102
65
  externalReference: string;
103
66
  isNew: boolean;
104
- /** Present only when the charge includes a tip. */
105
- orderAmount?: number;
106
- tip?: {
107
- amount: number;
108
- recipientUserId: string;
109
- };
110
67
  };
111
68
  }
112
69
  interface MpDynamicQrRequest {
113
- /** Order portion in ARS major units; tip is charged in addition. */
70
+ /** Charge in ARS major units. */
114
71
  amount: number;
115
72
  currency: 'ARS';
116
73
  externalReference?: string;
117
74
  customerId?: string;
118
75
  expirationMinutes?: number;
119
- /** Positive, cent-exact ARS major units, no greater than amount. Requires an ORD reference. */
120
- tip?: {
121
- amount: number;
122
- recipientUserId?: string;
123
- };
124
76
  }
125
77
  interface MpDynamicQrResponse {
126
78
  qrData: string;
@@ -129,57 +81,30 @@ declare global {
129
81
  externalReference: string;
130
82
  customerId?: string;
131
83
  amount: number;
132
- /** Present only when the charge includes a tip; no recipient identity. */
133
- orderAmount?: number;
134
- tipAmount?: number;
135
84
  currency: string;
136
85
  expiresAt: number;
137
86
  createdAt: number;
138
87
  isNew: boolean;
139
- /**
140
- * Server clock (Unix ms) when this response was built. Present on the tipped
141
- * create and replay; never persisted, so a replay carries the replay's instant.
142
- * Estimate the client clock offset from this, not from `createdAt` (the
143
- * reservation instant, taken before the POS lookup and the provider call).
144
- */
145
- serverNow?: number;
146
88
  }
147
89
  /**
148
- * `data` of `409 MP_DYN_QR_IN_PROGRESS`. `scope: 'attempt'` = this
149
- * Idempotency-Key's own attempt is in flight; `'order'` = another identity
150
- * holds the order's QR fence. `since` = the blocking attempt's reservation
151
- * instant (absent only on a fence written before it was stamped). `expiresAt`
152
- * only on `state: 'ready'` (an unexpired tipped QR), the instant the fence
153
- * frees; `reserved`/`contacting` carry none.
90
+ * `data` of `409 MP_DYN_QR_IN_PROGRESS`: another attempt holds the order's QR
91
+ * fence. `serverNow` = the refusal's own instant; `since` = the blocking
92
+ * attempt's reservation instant (absent only on a fence written before it was
93
+ * stamped).
154
94
  */
155
95
  interface MpDynamicQrInProgressDetails {
156
96
  serverNow: number;
157
- scope: 'attempt' | 'order';
158
- state: 'reserved' | 'contacting' | 'ready';
97
+ scope: 'order';
98
+ state: 'reserved' | 'contacting';
159
99
  since?: number;
160
- expiresAt?: number;
161
- }
162
- /** `data` of `409 MP_DYN_QR_EXPIRED`: the same key's saved QR expired at `expiresAt`. */
163
- interface MpDynamicQrExpiredDetails {
164
- serverNow: number;
165
- expiresAt: number;
166
- }
167
- /** `data` of `409 MP_DYN_QR_REJECTED`: the same key's attempt ended with no live charge. */
168
- interface MpDynamicQrRejectedDetails {
169
- serverNow: number;
170
100
  }
171
101
  /**
172
102
  * `data` of `GET /mercadopago/qr/dynamic?orderId=` — the re-sync read of the order's
173
- * dynamic QR. Never carries the Idempotency-Key, owner, fingerprint or tip recipient.
174
- * `ready` = an unexpired tipped QR (`qr.isNew` is always false); `pending` = an attempt
103
+ * dynamic QR. Never carries the attempt's key or owner. `pending` = an attempt
175
104
  * holds the order's fence (`since` = its reservation instant; no `qrData`); `none` =
176
105
  * nothing blocks the order.
177
106
  */
178
107
  type MpDynamicQrStateResponse = {
179
- state: 'ready';
180
- qr: MpDynamicQrResponse;
181
- serverNow: number;
182
- } | {
183
108
  state: 'pending';
184
109
  phase: 'reserved' | 'contacting';
185
110
  since?: number;
@@ -254,13 +179,11 @@ declare global {
254
179
  }
255
180
  /**
256
181
  * Dynamic QR initiation refusals, by status:
257
- * - 400 malformed request (`VALIDATION_FAILED`, `TIP_EXCEEDS_ORDER`, `TIP_ORDER_REQUIRED`), or an
258
- * order whose paid sum cannot be converted for want of a usable rate (`FX_CONVERSION_UNAVAILABLE`);
259
- * - 403 permission, plan or support session (`CAPABILITY_REQUIRED`, `ROLE_FORBIDDEN`,
260
- * `PLAN_UPGRADE_REQUIRED`, `IMPERSONATION_READONLY`);
261
- * - 404 missing order or worker (`TIP_ORDER_NOT_FOUND`, `TIP_RECIPIENT_NOT_FOUND`; the POST never
262
- * answers `ORDER_NOT_FOUND`, only the re-sync read below does);
263
- * - 409 order state, account, attempt or allocation conflicts (every other order/tip/attempt code);
182
+ * - 400 malformed request (`VALIDATION_FAILED`, an unknown body key included);
183
+ * - 403 permission or plan (`CAPABILITY_REQUIRED`, `ROLE_FORBIDDEN`,
184
+ * `PLAN_UPGRADE_REQUIRED`);
185
+ * - 409 order state or a held order fence (`ORDER_CANCELLED`, `MP_DYN_QR_IN_PROGRESS`); the POST
186
+ * never answers `ORDER_NOT_FOUND`, only the re-sync read below does;
264
187
  * - 412 connection or configuration (`MP_NOT_CONNECTED`, `MP_TOKEN_EXPIRED`, `MP_USER_ID_MISSING`,
265
188
  * `MP_NO_STORE_ON_ACCOUNT`);
266
189
  * - 502 a definite POS or QR rejection (`MP_DYN_POS_CREATE_FAILED`, `MP_POS_INVALID`,
@@ -270,28 +193,14 @@ declare global {
270
193
  * (`GET /mercadopago/qr/dynamic?orderId=`) uses `VALIDATION_FAILED`, `PLAN_UPGRADE_REQUIRED`,
271
194
  * `CAPABILITY_REQUIRED`, `ORDER_NOT_FOUND` and `ORDER_CANCELLED` from this list.
272
195
  *
273
- * Per Idempotency-Key on the tipped path: `MP_DYN_QR_IN_PROGRESS` = in flight
274
- * (keep the key, poll); `MP_DYN_QR_REJECTED` = ended with no live charge (a
275
- * fresh key is safe); `MP_DYN_QR_EXPIRED` = its QR expired (permanent for that
276
- * key). A `contacting` attempt (MercadoPago may have been called) stays blocked
277
- * indefinitely; a `reserved` one (provably never contacted) is released once it
278
- * outlives the Lambda timeout. A fresh tipped reservation on an order already
279
- * fully paid (till tenders plus linked payments cover its total, as its
280
- * `financialStatus` derives) answers `PAYMENT_ALREADY_RECEIVED`; a part-paid
281
- * order (a split) still mints the remainder. When a till tender or linked payment
282
- * is in a currency the store holds no usable rate for, the paid sum is unknown, not
283
- * paid: it answers `400 FX_CONVERSION_UNAVAILABLE` (configure the rate in Monedas,
284
- * then retry with the same key).
285
- * `MP_DYN_QR_INVALID` is untipped-only: on the tipped path a malformed 2xx is
286
- * `MP_DYN_QR_UNCONFIRMED`. The retired `{ orderId }`-only body answers
287
- * `VALIDATION_FAILED`. `INVALID_ORDER_STATE`, `ORDER_FX_RATE_UNAVAILABLE` and
288
- * `ORDER_FX_AMOUNT_TOO_SMALL` were that body's alone and are no longer emitted;
289
- * they stay listed so an existing client switch still compiles.
196
+ * An order-bound charge holds the order's QR fence while it mints, and another charge for the
197
+ * same order meanwhile answers `MP_DYN_QR_IN_PROGRESS`. A `contacting` attempt (MercadoPago may
198
+ * have been called) stays blocked indefinitely; a `reserved` one (provably never contacted) is
199
+ * released once it outlives the Lambda timeout. A QR MercadoPago returned whose attempt could not
200
+ * be recorded answers `MP_DYN_QR_UNCONFIRMED`; a malformed 2xx answers `MP_DYN_QR_INVALID`.
201
+ * The retired `{ orderId }`-only body answers `VALIDATION_FAILED`. `INVALID_ORDER_STATE`,
202
+ * `ORDER_FX_RATE_UNAVAILABLE` and `ORDER_FX_AMOUNT_TOO_SMALL` were that body's alone.
290
203
  */
291
- export declare const MP_DYNAMIC_QR_ERROR_CODES: readonly ["VALIDATION_FAILED", "MP_NOT_CONNECTED", "MP_TOKEN_EXPIRED", "MP_USER_ID_MISSING", "MP_NO_STORE_ON_ACCOUNT", "MP_DYN_POS_CREATE_FAILED", "MP_POS_INVALID", "MP_DYN_QR_CREATE_FAILED", "MP_DYN_QR_INVALID", "PLATFORM_INTEGRATION_DISABLED", "PLAN_UPGRADE_REQUIRED", "ORDER_CANCELLED", "INVALID_ORDER_STATE", "PAYMENT_ALREADY_RECEIVED", "ORDER_NOT_FOUND", "ORDER_FX_RATE_UNAVAILABLE", "ORDER_FX_AMOUNT_TOO_SMALL", "CAPABILITY_REQUIRED", "ROLE_FORBIDDEN", "IMPERSONATION_READONLY", "TIP_EXCEEDS_ORDER", "TIP_RECIPIENT_NOT_FOUND", "TIP_ACCOUNT_UNVERIFIED", "TIP_SHARED_ACCOUNT_FORBIDDEN", "TIP_ORDER_REQUIRED", "TIP_ORDER_NOT_FOUND", "TIP_OPERATION_CONFLICT", "TIP_PAYMENT_NOT_FOUND", "MP_DYN_QR_IN_PROGRESS", "MP_DYN_QR_EXPIRED", "MP_DYN_QR_UNCONFIRMED", "MP_DYN_QR_REJECTED", "FX_CONVERSION_UNAVAILABLE"];
204
+ export declare const MP_DYNAMIC_QR_ERROR_CODES: readonly ["VALIDATION_FAILED", "MP_NOT_CONNECTED", "MP_TOKEN_EXPIRED", "MP_USER_ID_MISSING", "MP_NO_STORE_ON_ACCOUNT", "MP_DYN_POS_CREATE_FAILED", "MP_POS_INVALID", "MP_DYN_QR_CREATE_FAILED", "MP_DYN_QR_INVALID", "PLATFORM_INTEGRATION_DISABLED", "PLAN_UPGRADE_REQUIRED", "ORDER_CANCELLED", "INVALID_ORDER_STATE", "ORDER_NOT_FOUND", "ORDER_FX_RATE_UNAVAILABLE", "ORDER_FX_AMOUNT_TOO_SMALL", "CAPABILITY_REQUIRED", "ROLE_FORBIDDEN", "MP_DYN_QR_IN_PROGRESS", "MP_DYN_QR_UNCONFIRMED"];
292
205
  export type MpDynamicQrErrorCode = (typeof MP_DYNAMIC_QR_ERROR_CODES)[number];
293
- export declare const MP_POINT_TIP_ERROR_CODES: readonly ["TIP_EXCEEDS_ORDER", "VALIDATION_FAILED", "CAPABILITY_REQUIRED", "ROLE_FORBIDDEN", "PLAN_UPGRADE_REQUIRED", "TIP_RECIPIENT_NOT_FOUND", "TIP_ACCOUNT_UNVERIFIED", "TIP_SHARED_ACCOUNT_FORBIDDEN", "TIP_ORDER_REQUIRED", "TIP_ORDER_NOT_FOUND", "TIP_OPERATION_CONFLICT", "TIP_PAYMENT_MISMATCH", "TIP_PAYMENT_NOT_FOUND", "TIP_REFUND_EXCEEDS_ORDER"];
294
- export type MpPointTipErrorCode = (typeof MP_POINT_TIP_ERROR_CODES)[number];
295
- export declare const MP_REFUND_RECOVERY_ERROR_CODES: readonly ["VALIDATION_FAILED", "MISSING_PAYMENT_ID", "MP_REFUND_RECOVERY_NOT_FOUND", "MP_REFUND_RECOVERY_MISMATCH", "MP_REFUND_IN_PROGRESS", "MP_NOT_CONNECTED", "MP_REFUND_PROVIDER_UNAVAILABLE"];
296
- export type MpRefundRecoveryErrorCode = (typeof MP_REFUND_RECOVERY_ERROR_CODES)[number];
297
206
  export {};
@@ -1,12 +1,10 @@
1
1
  /**
2
2
  * Dynamic QR initiation refusals, by status:
3
- * - 400 malformed request (`VALIDATION_FAILED`, `TIP_EXCEEDS_ORDER`, `TIP_ORDER_REQUIRED`), or an
4
- * order whose paid sum cannot be converted for want of a usable rate (`FX_CONVERSION_UNAVAILABLE`);
5
- * - 403 permission, plan or support session (`CAPABILITY_REQUIRED`, `ROLE_FORBIDDEN`,
6
- * `PLAN_UPGRADE_REQUIRED`, `IMPERSONATION_READONLY`);
7
- * - 404 missing order or worker (`TIP_ORDER_NOT_FOUND`, `TIP_RECIPIENT_NOT_FOUND`; the POST never
8
- * answers `ORDER_NOT_FOUND`, only the re-sync read below does);
9
- * - 409 order state, account, attempt or allocation conflicts (every other order/tip/attempt code);
3
+ * - 400 malformed request (`VALIDATION_FAILED`, an unknown body key included);
4
+ * - 403 permission or plan (`CAPABILITY_REQUIRED`, `ROLE_FORBIDDEN`,
5
+ * `PLAN_UPGRADE_REQUIRED`);
6
+ * - 409 order state or a held order fence (`ORDER_CANCELLED`, `MP_DYN_QR_IN_PROGRESS`); the POST
7
+ * never answers `ORDER_NOT_FOUND`, only the re-sync read below does;
10
8
  * - 412 connection or configuration (`MP_NOT_CONNECTED`, `MP_TOKEN_EXPIRED`, `MP_USER_ID_MISSING`,
11
9
  * `MP_NO_STORE_ON_ACCOUNT`);
12
10
  * - 502 a definite POS or QR rejection (`MP_DYN_POS_CREATE_FAILED`, `MP_POS_INVALID`,
@@ -16,23 +14,13 @@
16
14
  * (`GET /mercadopago/qr/dynamic?orderId=`) uses `VALIDATION_FAILED`, `PLAN_UPGRADE_REQUIRED`,
17
15
  * `CAPABILITY_REQUIRED`, `ORDER_NOT_FOUND` and `ORDER_CANCELLED` from this list.
18
16
  *
19
- * Per Idempotency-Key on the tipped path: `MP_DYN_QR_IN_PROGRESS` = in flight
20
- * (keep the key, poll); `MP_DYN_QR_REJECTED` = ended with no live charge (a
21
- * fresh key is safe); `MP_DYN_QR_EXPIRED` = its QR expired (permanent for that
22
- * key). A `contacting` attempt (MercadoPago may have been called) stays blocked
23
- * indefinitely; a `reserved` one (provably never contacted) is released once it
24
- * outlives the Lambda timeout. A fresh tipped reservation on an order already
25
- * fully paid (till tenders plus linked payments cover its total, as its
26
- * `financialStatus` derives) answers `PAYMENT_ALREADY_RECEIVED`; a part-paid
27
- * order (a split) still mints the remainder. When a till tender or linked payment
28
- * is in a currency the store holds no usable rate for, the paid sum is unknown, not
29
- * paid: it answers `400 FX_CONVERSION_UNAVAILABLE` (configure the rate in Monedas,
30
- * then retry with the same key).
31
- * `MP_DYN_QR_INVALID` is untipped-only: on the tipped path a malformed 2xx is
32
- * `MP_DYN_QR_UNCONFIRMED`. The retired `{ orderId }`-only body answers
33
- * `VALIDATION_FAILED`. `INVALID_ORDER_STATE`, `ORDER_FX_RATE_UNAVAILABLE` and
34
- * `ORDER_FX_AMOUNT_TOO_SMALL` were that body's alone and are no longer emitted;
35
- * they stay listed so an existing client switch still compiles.
17
+ * An order-bound charge holds the order's QR fence while it mints, and another charge for the
18
+ * same order meanwhile answers `MP_DYN_QR_IN_PROGRESS`. A `contacting` attempt (MercadoPago may
19
+ * have been called) stays blocked indefinitely; a `reserved` one (provably never contacted) is
20
+ * released once it outlives the Lambda timeout. A QR MercadoPago returned whose attempt could not
21
+ * be recorded answers `MP_DYN_QR_UNCONFIRMED`; a malformed 2xx answers `MP_DYN_QR_INVALID`.
22
+ * The retired `{ orderId }`-only body answers `VALIDATION_FAILED`. `INVALID_ORDER_STATE`,
23
+ * `ORDER_FX_RATE_UNAVAILABLE` and `ORDER_FX_AMOUNT_TOO_SMALL` were that body's alone.
36
24
  */
37
25
  export const MP_DYNAMIC_QR_ERROR_CODES = [
38
26
  'VALIDATION_FAILED',
@@ -48,49 +36,11 @@ export const MP_DYNAMIC_QR_ERROR_CODES = [
48
36
  'PLAN_UPGRADE_REQUIRED',
49
37
  'ORDER_CANCELLED',
50
38
  'INVALID_ORDER_STATE',
51
- 'PAYMENT_ALREADY_RECEIVED',
52
39
  'ORDER_NOT_FOUND',
53
40
  'ORDER_FX_RATE_UNAVAILABLE',
54
41
  'ORDER_FX_AMOUNT_TOO_SMALL',
55
42
  'CAPABILITY_REQUIRED',
56
43
  'ROLE_FORBIDDEN',
57
- 'IMPERSONATION_READONLY',
58
- 'TIP_EXCEEDS_ORDER',
59
- 'TIP_RECIPIENT_NOT_FOUND',
60
- 'TIP_ACCOUNT_UNVERIFIED',
61
- 'TIP_SHARED_ACCOUNT_FORBIDDEN',
62
- 'TIP_ORDER_REQUIRED',
63
- 'TIP_ORDER_NOT_FOUND',
64
- 'TIP_OPERATION_CONFLICT',
65
- 'TIP_PAYMENT_NOT_FOUND',
66
44
  'MP_DYN_QR_IN_PROGRESS',
67
- 'MP_DYN_QR_EXPIRED',
68
45
  'MP_DYN_QR_UNCONFIRMED',
69
- 'MP_DYN_QR_REJECTED',
70
- 'FX_CONVERSION_UNAVAILABLE',
71
- ];
72
- export const MP_POINT_TIP_ERROR_CODES = [
73
- 'TIP_EXCEEDS_ORDER',
74
- 'VALIDATION_FAILED',
75
- 'CAPABILITY_REQUIRED',
76
- 'ROLE_FORBIDDEN',
77
- 'PLAN_UPGRADE_REQUIRED',
78
- 'TIP_RECIPIENT_NOT_FOUND',
79
- 'TIP_ACCOUNT_UNVERIFIED',
80
- 'TIP_SHARED_ACCOUNT_FORBIDDEN',
81
- 'TIP_ORDER_REQUIRED',
82
- 'TIP_ORDER_NOT_FOUND',
83
- 'TIP_OPERATION_CONFLICT',
84
- 'TIP_PAYMENT_MISMATCH',
85
- 'TIP_PAYMENT_NOT_FOUND',
86
- 'TIP_REFUND_EXCEEDS_ORDER',
87
- ];
88
- export const MP_REFUND_RECOVERY_ERROR_CODES = [
89
- 'VALIDATION_FAILED',
90
- 'MISSING_PAYMENT_ID',
91
- 'MP_REFUND_RECOVERY_NOT_FOUND',
92
- 'MP_REFUND_RECOVERY_MISMATCH',
93
- 'MP_REFUND_IN_PROGRESS',
94
- 'MP_NOT_CONNECTED',
95
- 'MP_REFUND_PROVIDER_UNAVAILABLE',
96
46
  ];
package/dist/payment.d.ts CHANGED
@@ -1,12 +1,8 @@
1
1
  declare global {
2
- /** POST /stripe: goods and tip use integer cents in the same currency. */
2
+ /** POST /stripe: `amount` is integer cents in `currency`. */
3
3
  interface StripeCreatePaymentIntentRequest {
4
4
  currency?: 'USD' | 'EUR';
5
5
  amount: number;
6
- tip?: {
7
- amount: number;
8
- recipientUserId?: string;
9
- };
10
6
  email?: string;
11
7
  orderId?: string;
12
8
  invoiceId?: string;
@@ -16,12 +12,8 @@ declare global {
16
12
  message: string;
17
13
  clientSecret: string | null;
18
14
  }
19
- /**
20
- * POST /stripe 4xx `error` codes from the request validation and the tip path.
21
- * `STRIPE_TIP_ALREADY_PAID` (409) answers a replayed tipped create whose PaymentIntent
22
- * already succeeded — no client secret is returned.
23
- */
24
- type StripeCreatePaymentIntentErrorCode = 'VALIDATION_FAILED' | 'IMPERSONATION_READONLY' | 'CAPABILITY_REQUIRED' | 'PLAN_UPGRADE_REQUIRED' | 'ORDER_CANCELLED' | 'TIP_EXCEEDS_ORDER' | 'TIP_RECIPIENT_NOT_FOUND' | 'TIP_ORDER_REQUIRED' | 'TIP_ORDER_NOT_FOUND' | 'TIP_OPERATION_CONFLICT' | 'TIP_PAYMENT_MISMATCH' | 'TIP_PAYMENT_NOT_FOUND' | 'STRIPE_TIP_IN_PROGRESS' | 'STRIPE_TIP_ALREADY_PAID';
15
+ /** POST /stripe 4xx `error` codes. */
16
+ type StripeCreatePaymentIntentErrorCode = 'VALIDATION_FAILED' | 'ORDER_CANCELLED';
25
17
  /** Informational provider state; never a received-money row or settlement. */
26
18
  interface MpPaymentObservation {
27
19
  paymentId: string;
@@ -55,12 +47,6 @@ declare global {
55
47
  paymentId: string;
56
48
  orderId?: string;
57
49
  }
58
- /** Server-owned split of a provider payment; amounts share its currency. */
59
- interface PaymentTipMetadata {
60
- orderAmount: number;
61
- tipAmount: number;
62
- tipOperationId: string;
63
- }
64
50
  /**
65
51
  * WebSocket broadcast payload for the `payment_received` action, fired when a
66
52
  * "money received" event is persisted (MP webhook, Stripe webhook, or MP
@@ -69,8 +55,6 @@ declare global {
69
55
  */
70
56
  type PaymentReceivedSource = 'mp' | 'stripe' | 'mp_movement';
71
57
  interface PaymentReceivedWsPayload {
72
- /** Safe allocation figures; worker identity remains private to the tip ledger. */
73
- paymentTip?: PaymentTipMetadata;
74
58
  source: PaymentReceivedSource;
75
59
  paymentId: string;
76
60
  total: number;
@@ -89,7 +73,6 @@ declare global {
89
73
  * server-side so the FE doesn't N+1 fetch.
90
74
  */
91
75
  interface PaymentReceived {
92
- paymentTip?: PaymentTipMetadata;
93
76
  paymentId: string;
94
77
  source: PaymentReceivedSource;
95
78
  total: number;
@@ -115,12 +115,8 @@ export interface ResetCashOpResult {
115
115
  shiftsDeleted: number;
116
116
  shiftEventsDeleted: number;
117
117
  openDrawersReleased: number;
118
- /** The tip ledger under the same store: balances, replay anchors and entries. */
119
- tipBalancesDeleted: number;
120
- tipOperationsDeleted: number;
121
- tipEntriesDeleted: number;
122
- /** Immutable provider tip allocations removed before the ledger. Absent on older responses. */
123
- tipAllocationsDeleted?: number;
118
+ /** The store's MercadoPago dynamic-QR fence and attempt rows. */
119
+ qrAttemptsDeleted: number;
124
120
  /** `false` → the time budget ran out; re-send the body with `cursor`. */
125
121
  complete: boolean;
126
122
  /** Present only when `complete` is `false`. */
package/dist/report.d.ts CHANGED
@@ -1073,9 +1073,6 @@ export declare const REPORT_WAREHOUSE_NONE = "none";
1073
1073
  * - `change` — a `change` event: cash handed back while settling a sale.
1074
1074
  * - `refund` — a `refund` event: a refund movement recorded on a drawer, or the
1075
1075
  * cash a sales seña refund or a customer order return gives back.
1076
- * - `tip` — a `tip` event, and the reversal of one.
1077
- * - `tip-payout` — a `tip-payout` event (cash paid to a worker against their
1078
- * tip balance), and the reversal of one.
1079
1076
  * - `account` — a `cash-in`/`cash-out` carrying `accountId`: the cash side of a
1080
1077
  * customer-account payment, and its reversal.
1081
1078
  * - `cash-book` — a `cash-in`/`cash-out` carrying `cashId` and no `accountId`:
@@ -1094,7 +1091,7 @@ export declare const REPORT_WAREHOUSE_NONE = "none";
1094
1091
  * A compensation event (`compensation` set) falls in its original's source by
1095
1092
  * the same rule, so a reversal nets its original inside one source.
1096
1093
  */
1097
- export declare const CASH_FLOW_SOURCES: readonly ["sales", "change", "refund", "tip", "tip-payout", "account", "cash-book", "service-order-deposit", "manual", "other", "legacy-cash-book"];
1094
+ export declare const CASH_FLOW_SOURCES: readonly ["sales", "change", "refund", "account", "cash-book", "service-order-deposit", "manual", "other", "legacy-cash-book"];
1098
1095
  /**
1099
1096
  * Why a cash-flow day is not ledger-complete:
1100
1097
  *
package/dist/report.js CHANGED
@@ -20,9 +20,6 @@ export const REPORT_WAREHOUSE_NONE = 'none';
20
20
  * - `change` — a `change` event: cash handed back while settling a sale.
21
21
  * - `refund` — a `refund` event: a refund movement recorded on a drawer, or the
22
22
  * cash a sales seña refund or a customer order return gives back.
23
- * - `tip` — a `tip` event, and the reversal of one.
24
- * - `tip-payout` — a `tip-payout` event (cash paid to a worker against their
25
- * tip balance), and the reversal of one.
26
23
  * - `account` — a `cash-in`/`cash-out` carrying `accountId`: the cash side of a
27
24
  * customer-account payment, and its reversal.
28
25
  * - `cash-book` — a `cash-in`/`cash-out` carrying `cashId` and no `accountId`:
@@ -45,8 +42,6 @@ export const CASH_FLOW_SOURCES = [
45
42
  'sales',
46
43
  'change',
47
44
  'refund',
48
- 'tip',
49
- 'tip-payout',
50
45
  'account',
51
46
  'cash-book',
52
47
  'service-order-deposit',
@@ -62,9 +62,10 @@ declare global {
62
62
  source?: 'plan' | 'override' | 'trial';
63
63
  }
64
64
  /**
65
- * All gated features. Add new keys here when a new feature becomes gateable;
66
- * every existing plan in `FEATURE_MATRIX` must then declare the new key
67
- * (TypeScript enforces this via `Record<FeatureKey, Entitlement>`).
65
+ * All gated features. Add new keys here when a new feature becomes gateable,
66
+ * and to the `FEATURE_KEYS` tuple below (`UncoveredFeatureKeys` fails
67
+ * `typecheck` naming the key until you do); the api's `PLAN_FEATURES` matrix
68
+ * must then grant it on every tier (typed total over `PlanTier` × `FeatureKey`).
68
69
  *
69
70
  * ⚠️ **`Record<FeatureKey, …>` is NOT the only construction a new member
70
71
  * breaks, and searching for it alone will tell you a consumer is unaffected
@@ -148,28 +149,84 @@ declare global {
148
149
  * booleans.
149
150
  */
150
151
  type PlanFeatureStatus = 'live' | 'planned' | 'future' | 'service';
152
+ /** Singular/plural es-AR noun for a numeric/metered feature's count (e.g. `{ one: 'usuario', other: 'usuarios' }`). */
153
+ type PlanFeatureUnit = {
154
+ one: string;
155
+ other: string;
156
+ };
157
+ /**
158
+ * The window a limit counts over: `month` — a metered counter that resets
159
+ * monthly (e.g. orders); `active` — a numeric cap on rows that exist right
160
+ * now (e.g. products, users, depósitos — disabling one frees a slot).
161
+ */
162
+ type PlanFeaturePeriod = 'month' | 'active';
151
163
  /**
152
- * A single feature row in a Plan's `features[]` array. Matches the
153
- * BE wire format from `GET /subscription/plans` exactly — boolean
154
- * features carry `enabled`, numeric/metered carry `limit` (-1 =
155
- * unlimited).
164
+ * Section a feature row renders under on a pricing table. Each key's label
165
+ * and sort position travel as a {@link PlanFeatureGroup} in
166
+ * `PlanCatalogue.groups`, so a consumer never hard-codes either.
156
167
  */
157
- interface PlanFeature {
168
+ type PlanFeatureGroupKey = 'limits' | 'billing' | 'channels' | 'operations' | 'growth' | 'enterprise';
169
+ interface PlanFeatureGroup {
170
+ key: PlanFeatureGroupKey;
171
+ /** User-facing Spanish heading. */
172
+ label: string;
173
+ /** Sort position among groups (ascending). */
174
+ order: number;
175
+ }
176
+ /** Fields every feature row carries, whatever its `type`. */
177
+ interface PlanFeatureBase {
158
178
  key: FeatureKey;
159
- type: EntitlementType;
160
179
  status: PlanFeatureStatus;
180
+ /** Short user-facing Spanish name (the row's title on a pricing table). */
181
+ label: string;
161
182
  /** User-facing Spanish description. */
162
183
  description: string;
163
- /** Set on `boolean` features; `null` on numeric/metered. */
164
- enabled: boolean | null;
165
- /** Set on `numeric`/`metered` features; `null` on boolean. -1 = unlimited. */
166
- limit: number | null;
184
+ group: PlanFeatureGroupKey;
185
+ /** Sort position within `group` (ascending). `features[]` arrives already sorted by group order, then this. */
186
+ order: number;
187
+ /** `null` on boolean keys. */
188
+ unit: PlanFeatureUnit | null;
189
+ /** `null` on boolean keys. */
190
+ period: PlanFeaturePeriod | null;
191
+ /**
192
+ * The grant rendered server-side as an es-AR noun phrase, ready to print:
193
+ * `Ilimitado` for `-1`, `1 usuario`, `Hasta 2.000 pedidos por mes`,
194
+ * `Incluido` / `No incluido` for a boolean. Display copy only — compare
195
+ * grants through `enabled` / `limit`, never by parsing this.
196
+ */
197
+ valueText: string;
167
198
  }
168
199
  /**
169
- * A sellable plan in the catalog. Aligned with the BE wire format from
170
- * `GET /subscription/plans`. Source of truth lives in
171
- * DynamoDB (`PLAN#{tier}` partition), administered via `POST /sa/plans`
172
- * + `PATCH /sa/plans/{tier}`.
200
+ * A single feature row in a Plan's `features[]` array, discriminated on
201
+ * `type`: a boolean row carries `enabled` and no `limit` key; a
202
+ * numeric/metered row carries `limit` and no `enabled` key. `limit: -1` =
203
+ * unlimited.
204
+ */
205
+ type PlanFeature = (PlanFeatureBase & {
206
+ type: 'boolean';
207
+ enabled: boolean;
208
+ }) | (PlanFeatureBase & {
209
+ type: 'numeric' | 'metered';
210
+ limit: number;
211
+ });
212
+ /**
213
+ * How a billing cycle of a plan can be bought:
214
+ *
215
+ * - `self` — self-serve checkout: the cycle has a charged price and the
216
+ * plan has a `currency`.
217
+ * - `sales` — the plan charges some cycle, but not this one self-serve
218
+ * (no price on it, or no `currency`); route to "Contactar ventas".
219
+ * - `none` — neither cycle is charged (the free tier); nothing to buy.
220
+ */
221
+ type PlanCheckoutMode = 'self' | 'sales' | 'none';
222
+ /**
223
+ * A sellable plan in the catalog, exactly as `GET /subscription/plans` and
224
+ * `GET /public/plans` emit it — both build it with the same catalogue
225
+ * builder, so the two endpoints return identical plans. The template fields
226
+ * (copy, prices, flags) live in DynamoDB (`PLAN#{tier}` / `SK: PLAN`),
227
+ * administered via `POST /platform/billing/plans` +
228
+ * `PATCH /platform/billing/plans/{tier}`; `features` are code, rendered at
229
+ * response time.
173
230
  *
174
231
  * Prices are integers in the `currency` smallest unit (centavos for ARS,
175
232
  * cents for USD). `null` = "Contactar ventas" (AVANZADO annual at launch
@@ -228,20 +285,51 @@ declare global {
228
285
  */
229
286
  color: string | null;
230
287
  /**
231
- * Per-feature configuration. Every `FeatureKey` appears exactly once.
232
- * Boolean features carry `enabled`; numeric/metered carry `limit`.
288
+ * Per-feature configuration. Every `FeatureKey` appears exactly once,
289
+ * whatever its `status` — a `planned` / `future` key is sent too, so
290
+ * filter on `status` to decide what to advertise. Sorted by group order,
291
+ * then `order`. Boolean features carry `enabled`; numeric/metered carry
292
+ * `limit`.
233
293
  */
234
294
  features: PlanFeature[];
235
295
  /**
236
296
  * Marketing-curated short bullets for the pricing card. Display order =
237
297
  * array order; up to 6 entries, 80 chars each. Always present — empty array
238
298
  * when unset (FE synthesizes a list from `features[]`). Lets marketing tweak
239
- * copy via `/sa/plans` without a redeploy; replaces the FE-only `BULLET_LIST_BY_TIER`.
299
+ * copy via `PATCH /platform/billing/plans/{tier}` without a redeploy;
300
+ * replaces the FE-only `BULLET_LIST_BY_TIER`.
240
301
  */
241
302
  bullets: string[];
303
+ /**
304
+ * Keys worth calling out on this tier's card: highlight-eligible keys with
305
+ * status `live` or `service` whose grant improves on the next lower
306
+ * ACTIVE tier (by `displayOrder`; an `isActive: false` tier is skipped,
307
+ * as pricing pages hide it). The lowest active tier lists its own
308
+ * eligible keys. A `planned` / `future` key never appears. Each is a
309
+ * `features[]` key.
310
+ */
311
+ highlights: FeatureKey[];
312
+ /** How each billing cycle can be bought — see {@link PlanCheckoutMode}. */
313
+ checkout: {
314
+ monthly: PlanCheckoutMode;
315
+ annual: PlanCheckoutMode;
316
+ };
317
+ /** Whether a subscription on this tier can be cancelled: `true` exactly when at least one cycle is charged. */
318
+ cancellable: boolean;
319
+ }
320
+ /**
321
+ * `data` of `GET /public/plans` and `GET /subscription/plans` — both return
322
+ * the same `{ plans, groups }`: the plans plus the feature groups their rows
323
+ * render under.
324
+ */
325
+ interface PlanCatalogue {
326
+ plans: Plan[];
327
+ /** Every group a `features[].group` can name, with its label and sort position. */
328
+ groups: PlanFeatureGroup[];
242
329
  }
243
330
  /**
244
- * One audit row per SUPER_ADMIN-driven plan mutation, returned by
331
+ * One audit row per MANAGER-driven plan mutation (`POST` / `PATCH
332
+ * /platform/billing/plans`, `asManager`), returned by
245
333
  * `GET /platform/billing/plans/{tier}/audit`. The store-subscription audit
246
334
  * shares this storage shape but is read as `SubscriptionAuditEntry`.
247
335
  * `before`/`after` carry only the fields that changed (diff slice).
@@ -648,3 +736,28 @@ declare global {
648
736
  }
649
737
  export type BillingProviderName = SubscriptionProvider;
650
738
  export type InvoiceSummary = globalThis.InvoiceSummary;
739
+ /** Every plan tier, in rank order (lowest first). */
740
+ export declare const PLAN_TIERS: readonly ["basico", "emprendedor", "profesional", "avanzado"];
741
+ /**
742
+ * Every gated feature key.
743
+ *
744
+ * ⚠️ Adding a member here is not the whole change, and `typecheck` is what
745
+ * stops it shipping half-done. In the api, a new key needs a grant in **every
746
+ * tier** of `PLAN_FEATURES` (`stacks/services/planFeatureMatrix.ts`): that
747
+ * constant is typed total over every `PlanTier` × `FeatureKey` cell, so a tier
748
+ * missing the new key's grant, or a grant of the wrong shape for the key's
749
+ * declared `type`, fails `typecheck` at the `PLAN_FEATURES` declaration
750
+ * itself. It also widens the api's per-store override key schema, so a new key
751
+ * immediately becomes a valid override target.
752
+ *
753
+ * ⚠️ **A new member also obliges an api PLATFORM-STACK deploy.** Entitlements
754
+ * resolve inside the Lambda authorizer, built in `PlatformStack`. Deploying only
755
+ * the handler stacks leaves a STALE authorizer running the previous matrix: the
756
+ * key is absent from the resolved map, where a boolean gate refuses but a
757
+ * metered / lifetime cap PASSES THROUGH — a new cap silently unbounded.
758
+ * Checklist: `docs/PLANS_AND_ENTITLEMENTS.md` in the api repo.
759
+ */
760
+ export declare const FEATURE_KEYS: readonly ["afipInvoicing", "suppliers", "advancedReports", "cashManagement", "importExport", "domesticPayments", "stripePayments", "whatsappCommerce", "aiFeatures", "mobileApp", "customBranding", "customDomain", "prioritySupport", "advancedPricing", "marketplaceChannels", "storefront", "loyalty", "marketing", "mandatory2fa", "maxUsers", "maxProducts", "maxCustomers", "maxWarehouses", "priceListsMax", "webhooks", "maxOrdersMonth", "maxInvoicesMonth", "whatsappMessages"];
761
+ type AssertNoUncoveredFeatureKey<T extends never> = T;
762
+ export type UncoveredFeatureKeys = AssertNoUncoveredFeatureKey<Exclude<FeatureKey, (typeof FEATURE_KEYS)[number]>>;
763
+ export {};