1 | type Stripe = { |
2 | token: string; |
3 | }; |
4 | |
5 | * Post customers customer subscriptions subscription exposed id |
6 | * Updates an existing subscription on a customer to match the specified parameters. When changing plans or quantities, we will optionally prorate the price we charge next month to make up for any price changes. To preview how the proration will be calculated, use the upcoming invoice endpoint. |
7 | */ |
8 | export async function main( |
9 | auth: Stripe, |
10 | customer: string, |
11 | subscription_exposed_id: string, |
12 | body: { |
13 | add_invoice_items?: { |
14 | price?: string; |
15 | price_data?: { |
16 | currency: string; |
17 | product: string; |
18 | tax_behavior?: "exclusive" | "inclusive" | "unspecified"; |
19 | unit_amount?: number; |
20 | unit_amount_decimal?: string; |
21 | [k: string]: unknown; |
22 | }; |
23 | quantity?: number; |
24 | tax_rates?: string[] | ""; |
25 | [k: string]: unknown; |
26 | }[]; |
27 | application_fee_percent?: number; |
28 | automatic_tax?: { |
29 | enabled: boolean; |
30 | liability?: { |
31 | account?: string; |
32 | type: "account" | "self"; |
33 | [k: string]: unknown; |
34 | }; |
35 | [k: string]: unknown; |
36 | }; |
37 | billing_cycle_anchor?: "now" | "unchanged"; |
38 | billing_thresholds?: |
39 | | { |
40 | amount_gte?: number; |
41 | reset_billing_cycle_anchor?: boolean; |
42 | [k: string]: unknown; |
43 | } |
44 | | ""; |
45 | cancel_at?: number | ""; |
46 | cancel_at_period_end?: boolean; |
47 | cancellation_details?: { |
48 | comment?: string | ""; |
49 | feedback?: |
50 | | "" |
51 | | "customer_service" |
52 | | "low_quality" |
53 | | "missing_features" |
54 | | "other" |
55 | | "switched_service" |
56 | | "too_complex" |
57 | | "too_expensive" |
58 | | "unused"; |
59 | [k: string]: unknown; |
60 | }; |
61 | collection_method?: "charge_automatically" | "send_invoice"; |
62 | coupon?: string; |
63 | days_until_due?: number; |
64 | default_payment_method?: string; |
65 | default_source?: string | ""; |
66 | default_tax_rates?: string[] | ""; |
67 | expand?: string[]; |
68 | invoice_settings?: { |
69 | account_tax_ids?: string[] | ""; |
70 | issuer?: { |
71 | account?: string; |
72 | type: "account" | "self"; |
73 | [k: string]: unknown; |
74 | }; |
75 | [k: string]: unknown; |
76 | }; |
77 | items?: { |
78 | billing_thresholds?: { usage_gte: number; [k: string]: unknown } | ""; |
79 | clear_usage?: boolean; |
80 | deleted?: boolean; |
81 | id?: string; |
82 | metadata?: { [k: string]: string } | ""; |
83 | price?: string; |
84 | price_data?: { |
85 | currency: string; |
86 | product: string; |
87 | recurring: { |
88 | interval: "day" | "month" | "week" | "year"; |
89 | interval_count?: number; |
90 | [k: string]: unknown; |
91 | }; |
92 | tax_behavior?: "exclusive" | "inclusive" | "unspecified"; |
93 | unit_amount?: number; |
94 | unit_amount_decimal?: string; |
95 | [k: string]: unknown; |
96 | }; |
97 | quantity?: number; |
98 | tax_rates?: string[] | ""; |
99 | [k: string]: unknown; |
100 | }[]; |
101 | metadata?: { [k: string]: string } | ""; |
102 | off_session?: boolean; |
103 | pause_collection?: |
104 | | { |
105 | behavior: "keep_as_draft" | "mark_uncollectible" | "void"; |
106 | resumes_at?: number; |
107 | [k: string]: unknown; |
108 | } |
109 | | ""; |
110 | payment_behavior?: |
111 | | "allow_incomplete" |
112 | | "default_incomplete" |
113 | | "error_if_incomplete" |
114 | | "pending_if_incomplete"; |
115 | payment_settings?: { |
116 | payment_method_options?: { |
117 | acss_debit?: |
118 | | { |
119 | mandate_options?: { |
120 | transaction_type?: "business" | "personal"; |
121 | [k: string]: unknown; |
122 | }; |
123 | verification_method?: "automatic" | "instant" | "microdeposits"; |
124 | [k: string]: unknown; |
125 | } |
126 | | ""; |
127 | bancontact?: |
128 | | { |
129 | preferred_language?: "de" | "en" | "fr" | "nl"; |
130 | [k: string]: unknown; |
131 | } |
132 | | ""; |
133 | card?: |
134 | | { |
135 | mandate_options?: { |
136 | amount?: number; |
137 | amount_type?: "fixed" | "maximum"; |
138 | description?: string; |
139 | [k: string]: unknown; |
140 | }; |
141 | network?: |
142 | | "amex" |
143 | | "cartes_bancaires" |
144 | | "diners" |
145 | | "discover" |
146 | | "eftpos_au" |
147 | | "interac" |
148 | | "jcb" |
149 | | "mastercard" |
150 | | "unionpay" |
151 | | "unknown" |
152 | | "visa"; |
153 | request_three_d_secure?: "any" | "automatic" | "challenge"; |
154 | [k: string]: unknown; |
155 | } |
156 | | ""; |
157 | customer_balance?: |
158 | | { |
159 | bank_transfer?: { |
160 | eu_bank_transfer?: { country: string; [k: string]: unknown }; |
161 | type?: string; |
162 | [k: string]: unknown; |
163 | }; |
164 | funding_type?: string; |
165 | [k: string]: unknown; |
166 | } |
167 | | ""; |
168 | konbini?: { [k: string]: unknown } | ""; |
169 | us_bank_account?: |
170 | | { |
171 | financial_connections?: { |
172 | permissions?: ( |
173 | | "balances" |
174 | | "ownership" |
175 | | "payment_method" |
176 | | "transactions" |
177 | )[]; |
178 | prefetch?: ("balances" | "transactions")[]; |
179 | [k: string]: unknown; |
180 | }; |
181 | verification_method?: "automatic" | "instant" | "microdeposits"; |
182 | [k: string]: unknown; |
183 | } |
184 | | ""; |
185 | [k: string]: unknown; |
186 | }; |
187 | payment_method_types?: |
188 | | ( |
189 | | "ach_credit_transfer" |
190 | | "ach_debit" |
191 | | "acss_debit" |
192 | | "au_becs_debit" |
193 | | "bacs_debit" |
194 | | "bancontact" |
195 | | "boleto" |
196 | | "card" |
197 | | "cashapp" |
198 | | "customer_balance" |
199 | | "eps" |
200 | | "fpx" |
201 | | "giropay" |
202 | | "grabpay" |
203 | | "ideal" |
204 | | "konbini" |
205 | | "link" |
206 | | "p24" |
207 | | "paynow" |
208 | | "paypal" |
209 | | "promptpay" |
210 | | "sepa_debit" |
211 | | "sofort" |
212 | | "us_bank_account" |
213 | | "wechat_pay" |
214 | )[] |
215 | | ""; |
216 | save_default_payment_method?: "off" | "on_subscription"; |
217 | [k: string]: unknown; |
218 | }; |
219 | pending_invoice_item_interval?: |
220 | | { |
221 | interval: "day" | "month" | "week" | "year"; |
222 | interval_count?: number; |
223 | [k: string]: unknown; |
224 | } |
225 | | ""; |
226 | promotion_code?: string; |
227 | proration_behavior?: "always_invoice" | "create_prorations" | "none"; |
228 | proration_date?: number; |
229 | transfer_data?: |
230 | | { amount_percent?: number; destination: string; [k: string]: unknown } |
231 | | ""; |
232 | trial_end?: "now" | number; |
233 | trial_from_plan?: boolean; |
234 | trial_settings?: { |
235 | end_behavior: { |
236 | missing_payment_method: "cancel" | "create_invoice" | "pause"; |
237 | [k: string]: unknown; |
238 | }; |
239 | [k: string]: unknown; |
240 | }; |
241 | } |
242 | ) { |
243 | const url = new URL( |
244 | `https://api.stripe.com/v1/customers/${customer}/subscriptions/${subscription_exposed_id}` |
245 | ); |
246 |
|
247 | const response = await fetch(url, { |
248 | method: "POST", |
249 | headers: { |
250 | "Content-Type": "application/x-www-form-urlencoded", |
251 | Authorization: "Bearer " + auth.token, |
252 | }, |
253 | body: encodeParams(body), |
254 | }); |
255 | if (!response.ok) { |
256 | const text = await response.text(); |
257 | throw new Error(`${response.status} ${text}`); |
258 | } |
259 | return await response.json(); |
260 | } |
261 |
|
262 | function encodeParams(o: any) { |
263 | function iter(o: any, path: string) { |
264 | if (Array.isArray(o)) { |
265 | o.forEach(function (a) { |
266 | iter(a, path + "[]"); |
267 | }); |
268 | return; |
269 | } |
270 | if (o !== null && typeof o === "object") { |
271 | Object.keys(o).forEach(function (k) { |
272 | iter(o[k], path + "[" + k + "]"); |
273 | }); |
274 | return; |
275 | } |
276 | data.push(path + "=" + o); |
277 | } |
278 | const data: string[] = []; |
279 | Object.keys(o).forEach(function (k) { |
280 | if (o[k] !== undefined) { |
281 | iter(o[k], k); |
282 | } |
283 | }); |
284 | return new URLSearchParams(data.join("&")); |
285 | } |
286 |
|