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