0

Create Subscription

by
Published Oct 30, 2023

Subscribe a customer to one or more recurring prices. With `charge_automatically`, the customer needs a default payment method (or use `payment_behavior: default_incomplete` and confirm the first invoice's payment). `send_invoice` needs `days_until_due`. Set `idempotency_key` to make retries safe: Stripe returns the first result for a repeated key within 24 hours. `extra_params` passes any other documented field through as-is.

Script stripe Verified

The script

Submitted by hugo989 Typescript (fetch-only)
Verified 2 hours ago
1
//native
2

3
/**
4
 * Create Subscription
5
 * Subscribe a customer to one or more recurring prices. With `charge_automatically`, the customer needs a default payment method (or use `payment_behavior: default_incomplete` and confirm the first invoice's payment). `send_invoice` needs `days_until_due`. Set `idempotency_key` to make retries safe: Stripe returns the first result for a repeated key within 24 hours. `extra_params` passes any other documented field through as-is.
6
 */
7
export async function main(
8
  auth: RT.Stripe,
9
  customer: string,
10
  items: { price: string; quantity?: number }[],
11
  collection_method: "charge_automatically" | "send_invoice" | undefined,
12
  days_until_due: number | undefined,
13
  default_payment_method: string | undefined,
14
  payment_behavior:
15
    | "allow_incomplete"
16
    | "default_incomplete"
17
    | "error_if_incomplete"
18
    | "pending_if_incomplete"
19
    | undefined,
20
  trial_period_days: number | undefined,
21
  description: string | undefined,
22
  metadata: { [key: string]: string } | undefined,
23
  idempotency_key: string | undefined,
24
  extra_params: { [key: string]: any } | undefined
25
) {
26
  const response = await fetch(`https://api.stripe.com/v1/subscriptions`, {
27
    method: "POST",
28
    headers: {
29
      Authorization: `Bearer ${auth.token}`,
30
      "Content-Type": "application/x-www-form-urlencoded",
31
      Accept: "application/json",
32
      "Stripe-Version": "2025-03-31.basil",
33
      ...(idempotency_key ? { "Idempotency-Key": idempotency_key } : {}),
34
    },
35
    body: toForm({
36
      customer,
37
      items,
38
      collection_method,
39
      days_until_due,
40
      default_payment_method,
41
      payment_behavior,
42
      trial_period_days,
43
      description,
44
      metadata,
45
      ...extra_params,
46
    }),
47
  })
48

49
  if (!response.ok) {
50
    throw new Error(`${response.status} ${await response.text()}`)
51
  }
52

53
  return await response.json()
54
}
55

56
// Stripe takes form-encoded params with bracketed nesting: metadata[key]=v, items[0][price]=p
57
function toForm(
58
  params: { [key: string]: any },
59
  prefix = "",
60
  out = new URLSearchParams()
61
) {
62
  for (const [key, value] of Object.entries(params)) {
63
    if (value == null || value === "") continue
64
    const name = prefix ? `${prefix}[${key}]` : key
65
    if (typeof value === "object") toForm(value, name, out)
66
    else out.append(name, String(value))
67
  }
68
  return out
69
}
70

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