1 | |
2 | type Paypal = { |
3 | clientId: string; |
4 | clientSecret: string; |
5 | }; |
6 |
|
7 | async function getToken(auth: Paypal): Promise<string> { |
8 | const url = new URL(`https://api-m.paypal.com/v1/oauth2/token`); |
9 | const response = await fetch(url, { |
10 | method: "POST", |
11 | headers: { |
12 | Authorization: `Basic ${btoa(`${auth.clientId}:${auth.clientSecret}`)}`, |
13 | }, |
14 | body: new URLSearchParams({ |
15 | grant_type: "client_credentials", |
16 | }), |
17 | }); |
18 | if (!response.ok) { |
19 | const text = await response.text(); |
20 | throw new Error(`Could not get token: ${response.status} ${text}`); |
21 | } |
22 | const json = await response.json(); |
23 | return json.access_token; |
24 | } |
25 | |
26 | * Create subscription |
27 | * Creates a subscription. |
28 | */ |
29 | export async function main( |
30 | auth: Paypal, |
31 | Prefer: string, |
32 | PayPal_Request_Id: string, |
33 | body: { |
34 | plan_id: string; |
35 | start_time?: string; |
36 | quantity?: string; |
37 | shipping_amount?: { currency_code: string; value: string }; |
38 | subscriber?: { email_address?: string; payer_id?: string } & { |
39 | name?: { |
40 | prefix?: string; |
41 | given_name?: string; |
42 | surname?: string; |
43 | middle_name?: string; |
44 | suffix?: string; |
45 | alternate_full_name?: string; |
46 | full_name?: string; |
47 | }; |
48 | phone?: { |
49 | phone_type?: "FAX" | "HOME" | "MOBILE" | "OTHER" | "PAGER"; |
50 | phone_number: { |
51 | country_code: string; |
52 | national_number: string; |
53 | extension_number?: string; |
54 | }; |
55 | }; |
56 | birth_date?: string; |
57 | tax_info?: { tax_id: string; tax_id_type: "BR_CPF" | "BR_CNPJ" }; |
58 | address?: { |
59 | address_line_1?: string; |
60 | address_line_2?: string; |
61 | address_line_3?: string; |
62 | admin_area_4?: string; |
63 | admin_area_3?: string; |
64 | admin_area_2?: string; |
65 | admin_area_1?: string; |
66 | postal_code?: string; |
67 | country_code: string; |
68 | address_details?: { |
69 | street_number?: string; |
70 | street_name?: string; |
71 | street_type?: string; |
72 | delivery_service?: string; |
73 | building_name?: string; |
74 | sub_building?: string; |
75 | }; |
76 | }; |
77 | } & { |
78 | shipping_address?: { |
79 | name?: { |
80 | prefix?: string; |
81 | given_name?: string; |
82 | surname?: string; |
83 | middle_name?: string; |
84 | suffix?: string; |
85 | alternate_full_name?: string; |
86 | full_name?: string; |
87 | }; |
88 | type?: "SHIPPING" | "PICKUP_IN_PERSON"; |
89 | address?: { |
90 | address_line_1?: string; |
91 | address_line_2?: string; |
92 | address_line_3?: string; |
93 | admin_area_4?: string; |
94 | admin_area_3?: string; |
95 | admin_area_2?: string; |
96 | admin_area_1?: string; |
97 | postal_code?: string; |
98 | country_code: string; |
99 | address_details?: { |
100 | street_number?: string; |
101 | street_name?: string; |
102 | street_type?: string; |
103 | delivery_service?: string; |
104 | building_name?: string; |
105 | sub_building?: string; |
106 | }; |
107 | }; |
108 | }; |
109 | payment_source?: { |
110 | card?: { |
111 | id?: string; |
112 | name?: string; |
113 | number: string; |
114 | expiry: string; |
115 | security_code?: string; |
116 | last_digits?: string; |
117 | card_type?: |
118 | | "VISA" |
119 | | "MASTERCARD" |
120 | | "DISCOVER" |
121 | | "AMEX" |
122 | | "SOLO" |
123 | | "JCB" |
124 | | "STAR" |
125 | | "DELTA" |
126 | | "SWITCH" |
127 | | "MAESTRO" |
128 | | "CB_NATIONALE" |
129 | | "CONFIGOGA" |
130 | | "CONFIDIS" |
131 | | "ELECTRON" |
132 | | "CETELEM" |
133 | | "CHINA_UNION_PAY"; |
134 | billing_address?: { |
135 | address_line_1?: string; |
136 | address_line_2?: string; |
137 | address_line_3?: string; |
138 | admin_area_4?: string; |
139 | admin_area_3?: string; |
140 | admin_area_2?: string; |
141 | admin_area_1?: string; |
142 | postal_code?: string; |
143 | country_code: string; |
144 | address_details?: { |
145 | street_number?: string; |
146 | street_name?: string; |
147 | street_type?: string; |
148 | delivery_service?: string; |
149 | building_name?: string; |
150 | sub_building?: string; |
151 | }; |
152 | }; |
153 | }; |
154 | }; |
155 | }; |
156 | auto_renewal?: false | true; |
157 | application_context?: { |
158 | brand_name?: string; |
159 | locale?: string; |
160 | shipping_preference?: |
161 | | "GET_FROM_FILE" |
162 | | "NO_SHIPPING" |
163 | | "SET_PROVIDED_ADDRESS"; |
164 | user_action?: "CONTINUE" | "SUBSCRIBE_NOW"; |
165 | payment_method?: { |
166 | payer_selected?: string; |
167 | payee_preferred?: "UNRESTRICTED" | "IMMEDIATE_PAYMENT_REQUIRED"; |
168 | standard_entry_class_code?: "TEL" | "WEB" | "CCD" | "PPD"; |
169 | }; |
170 | return_url: string; |
171 | cancel_url: string; |
172 | }; |
173 | custom_id?: string; |
174 | plan?: { |
175 | billing_cycles?: { |
176 | pricing_scheme?: { |
177 | version?: number; |
178 | fixed_price?: { currency_code: string; value: string }; |
179 | pricing_model?: "VOLUME" | "TIERED"; |
180 | tiers?: { |
181 | starting_quantity: string; |
182 | ending_quantity?: string; |
183 | amount: { currency_code: string; value: string }; |
184 | }[]; |
185 | create_time?: string; |
186 | update_time?: string; |
187 | }; |
188 | sequence: number; |
189 | total_cycles?: number; |
190 | }[]; |
191 | payment_preferences?: { |
192 | auto_bill_outstanding?: false | true; |
193 | setup_fee?: { currency_code: string; value: string }; |
194 | setup_fee_failure_action?: "CONTINUE" | "CANCEL"; |
195 | payment_failure_threshold?: number; |
196 | }; |
197 | taxes?: { percentage?: string; inclusive?: false | true }; |
198 | }; |
199 | }, |
200 | ) { |
201 | const token = await getToken(auth); |
202 | const url = new URL(`https://api-m.paypal.com/v1/billing/subscriptions`); |
203 |
|
204 | const response = await fetch(url, { |
205 | method: "POST", |
206 | headers: { |
207 | Prefer: Prefer, |
208 | "PayPal-Request-Id": PayPal_Request_Id, |
209 | "Content-Type": "application/json", |
210 | Authorization: "Bearer " + token, |
211 | }, |
212 | body: JSON.stringify(body), |
213 | }); |
214 | if (!response.ok) { |
215 | const text = await response.text(); |
216 | throw new Error(`${response.status} ${text}`); |
217 | } |
218 | return await response.json(); |
219 | } |
220 |
|