/api/user/subscriptions/create-payment-method (POST)
Account information like email addresses is generated with faker-js it is not real user information.
await global.api.user.subscriptions.CreatePaymentMethod.post(req)Returns object
{
"paymentmethodid": "pm_1LEObsHHqepMFuCXyvhecH4d",
"object": "paymentmethod",
"accountid": "acct_f101ed737dc761d2",
"customerid": "cus_LwHA1TuiIt5S6t",
"stripeObject": {
"id": "pm_1LEObsHHqepMFuCXyvhecH4d",
"object": "payment_method",
"billing_details": {
"address": {
"city": "City",
"country": "US",
"line1": "A street address",
"line2": null,
"postal_code": "90120",
"state": "NY"
},
"email": null,
"name": "Harriet Homenick",
"phone": null
},
"card": {
"brand": "visa",
"checks": {
"address_line1_check": "pass",
"address_postal_code_check": "pass",
"cvc_check": "pass"
},
"country": "US",
"exp_month": 1,
"exp_year": 2023,
"fingerprint": "IRcdqfBUCskmPkNV",
"funding": "credit",
"generated_from": null,
"last4": "1111",
"networks": {
"available": [
"visa"
],
"preferred": null
},
"three_d_secure_usage": {
"supported": true
},
"wallet": null
},
"created": 1656123632,
"customer": "cus_LwHA1TuiIt5S6t",
"livemode": false,
"metadata": {},
"type": "card"
},
"appid": "tests_1656123632",
"createdAt": "2022-06-25T02:20:33.754Z",
"updatedAt": "2022-06-25T02:20:34.374Z"
}
Receives
API routes may receive parameters from the URL and POST supporting simple and multipart:
Field | Value | Required | Type |
---|---|---|---|
cvc | string | configurable as required | POST |
exp_month | string | configurable as required | POST |
exp_year | string | configurable as required | POST |
name | string | configurable as required | POST |
number | string | configurable as required | POST |
token | string | configurable as required | POST |
Exceptions
These exceptions are thrown (NodeJS) or returned as JSON (HTTP) if you provide incorrect data or do not meet the requirements:
Exception | Circumstances |
---|---|
invalid-account | ineligible accessing account |
invalid-customerid | missing querystring customerid |
invalid querystring customerid |
NodeJS source (view on github)
const subscriptions = require('../../../../../index.js')
const stripeCache = require('../../../../stripe-cache.js')
module.exports = {
post: async (req) => {
if (!req.query || !req.query.customerid) {
throw new Error('invalid-customerid')
}
const customer = await global.api.user.subscriptions.Customer.get(req)
if (!customer) {
throw new Error('invalid-customer')
}
if (!global.stripeJS) {
if (!req.body || !req.body.name || !req.body.name.length) {
throw new Error('invalid-name')
}
if (!req.body.number || !req.body.number.length) {
throw new Error('invalid-number')
}
if (!req.body.cvc || req.body.cvc.length !== 3) {
throw new Error('invalid-cvc')
}
try {
const intValue = parseInt(req.body.cvc, 10)
if (intValue.toString() !== req.body.cvc) {
throw new Error('invalid-cvc')
}
} catch (error) {
throw new Error('invalid-cvc')
}
if (!req.body.exp_month || !req.body.exp_month.length) {
throw new Error('invalid-exp_month')
}
try {
const intValue = parseInt(req.body.exp_month, 10)
if (intValue.toString() !== req.body.exp_month) {
throw new Error('invalid-exp_month')
}
if (intValue < 1 || intValue > 12) {
throw new Error('invalid-exp_month')
}
} catch (error) {
throw new Error('invalid-exp_month')
}
if (!req.body.exp_year || !req.body.exp_year.length) {
throw new Error('invalid-exp_year')
}
try {
const intValue = parseInt(req.body.exp_year, 10)
if (intValue.toString() !== req.body.exp_year) {
throw new Error('invalid-exp_year')
}
const now = parseInt(new Date().getFullYear().toString().substring(2), 10)
if (intValue < now || intValue > now + 10) {
throw new Error('invalid-exp_year')
}
} catch (error) {
throw new Error('invalid-exp_year')
}
} else if (global.stripeJS === 2 || global.stripeJS === 3) {
if (!req.body || !req.body.token || !req.body.token.length) {
throw new Error('invalid-token')
}
}
const cardInfo = {}
if (!global.stripeJS) {
cardInfo.number = req.body.number
cardInfo.cvc = req.body.cvc
cardInfo.exp_month = req.body.exp_month
cardInfo.exp_year = req.body.exp_year
} else if (global.stripeJS === 2 || global.stripeJS === 3) {
cardInfo.token = req.body.token
}
const billingInfo = {
name: req.body.name,
address: {}
}
for (const field of ['line1', 'line2', 'city', 'state', 'postal_code', 'country']) {
if (req.body[field] && req.body[field].length) {
billingInfo.address[field] = req.body[field]
}
}
const paymentMethodInfo = {
type: 'card',
card: cardInfo
}
if (global.stripeJS === false) {
paymentMethodInfo.billing_details = billingInfo
}
let paymentMethod = await stripeCache.execute('paymentMethods', 'create', paymentMethodInfo, req.stripeKey)
paymentMethod = await stripeCache.execute('paymentMethods', 'attach', paymentMethod.id, {
customer: req.query.customerid
}, req.stripeKey)
await subscriptions.Storage.PaymentMethod.create({
appid: req.appid || global.appid,
customerid: req.query.customerid,
paymentmethodid: paymentMethod.id,
accountid: req.account.accountid,
stripeObject: paymentMethod
})
await stripeCache.execute('setupIntents', 'create', {
customer: req.query.customerid,
payment_method: paymentMethod.id,
usage: 'off_session'
}, req.stripeKey)
if (req.body.default === 'true') {
const customerNow = await stripeCache.execute('customers', 'update', req.query.customerid, {
invoice_settings: {
default_payment_method: paymentMethod.id
}
}, req.stripeKey)
await subscriptions.Storage.Customer.update({
stripeObject: customerNow
}, {
where: {
customerid: req.query.customerid,
appid: req.appid || global.appid
}
})
}
req.query.paymentmethodid = paymentMethod.id
return global.api.user.subscriptions.PaymentMethod.get(req)
}
}
Test source (view on github)
/* eslint-env mocha */
const assert = require('assert')
const TestHelper = require('../../../../../test-helper.js')
describe('/api/user/subscriptions/create-payment-method', function () {
before(TestHelper.disableMetrics)
after(TestHelper.enableMetrics)
describe('exceptions', () => {
describe('invalid-customerid', () => {
it('missing querystring customerid', async () => {
global.stripeJS = false
const user = await TestHelper.createUser()
const req = TestHelper.createRequest('/api/user/subscriptions/create-payment-method')
req.account = user.account
req.session = user.session
let errorMessage
try {
await req.post()
} catch (error) {
errorMessage = error.message
}
assert.strictEqual(errorMessage, 'invalid-customerid')
})
it('invalid querystring customerid', async () => {
global.stripeJS = false
const user = await TestHelper.createUser()
const req = TestHelper.createRequest('/api/user/subscriptions/create-payment-method?customerid=invalid')
req.account = user.account
req.session = user.session
let errorMessage
try {
await req.post()
} catch (error) {
errorMessage = error.message
}
assert.strictEqual(errorMessage, 'invalid-customerid')
})
})
describe('invalid-account', () => {
it('ineligible accessing account', async () => {
const user = await TestHelper.createUser()
await TestHelper.createCustomer(user, {
email: user.profile.contactEmail
})
const user2 = await TestHelper.createUser()
const req = TestHelper.createRequest(`/api/user/subscriptions/create-payment-method?customerid=${user.customer.customerid}`)
req.account = user2.account
req.session = user2.session
req.body = {
name: user2.profile.fullName,
cvc: '111',
number: '4111111111111111',
exp_month: '1',
exp_year: (new Date().getFullYear() + 1).toString().substring(2),
line1: 'A street address',
city: 'City',
state: 'NY',
postal_code: '90120',
country: 'US',
default: 'true'
}
let errorMessage
try {
await req.post()
} catch (error) {
errorMessage = error.message
}
assert.strictEqual(errorMessage, 'invalid-account')
})
})
})
describe('receives', () => {
it('optionally-required posted name', async () => {
global.stripeJS = false
const user = await TestHelper.createUser()
await TestHelper.createCustomer(user, {
email: user.profile.contactEmail
})
const req = TestHelper.createRequest(`/api/user/subscriptions/create-payment-method?customerid=${user.customer.customerid}`)
req.account = user.account
req.session = user.session
req.body = {
email: user.profile.contactEmail,
description: 'Chase Sapphire',
name: '',
cvc: '111',
number: '4111111111111111',
exp_month: '1',
exp_year: (new Date().getFullYear() + 1).toString().substring(2)
}
let errorMessage
try {
await req.post()
} catch (error) {
errorMessage = error.message
}
assert.strictEqual(errorMessage, 'invalid-name')
})
it('optionally-required posted cvc', async () => {
global.stripeJS = false
const user = await TestHelper.createUser()
await TestHelper.createCustomer(user, {
email: user.profile.contactEmail
})
const req = TestHelper.createRequest(`/api/user/subscriptions/create-payment-method?customerid=${user.customer.customerid}`)
req.account = user.account
req.session = user.session
req.body = {
email: user.profile.contactEmail,
description: 'Chase Sapphire',
name: user.profile.fullName,
cvc: '0',
number: '4111111111111111',
exp_month: '1',
exp_year: (new Date().getFullYear() + 1).toString().substring(2)
}
let errorMessage
try {
await req.post()
} catch (error) {
errorMessage = error.message
}
assert.strictEqual(errorMessage, 'invalid-cvc')
})
it('optionally-required posted number', async () => {
global.stripeJS = false
const user = await TestHelper.createUser()
await TestHelper.createCustomer(user, {
email: user.profile.contactEmail
})
const req = TestHelper.createRequest(`/api/user/subscriptions/create-payment-method?customerid=${user.customer.customerid}`)
req.account = user.account
req.session = user.session
req.body = {
email: user.profile.contactEmail,
description: 'Chase Sapphire',
name: user.profile.fullName,
cvc: '123',
number: '',
exp_month: '1',
exp_year: (new Date().getFullYear() + 1).toString().substring(2)
}
let errorMessage
try {
await req.post()
} catch (error) {
errorMessage = error.message
}
assert.strictEqual(errorMessage, 'invalid-number')
})
it('optionally-required posted exp_month', async () => {
global.stripeJS = false
const user = await TestHelper.createUser()
await TestHelper.createCustomer(user, {
email: user.profile.contactEmail
})
const req = TestHelper.createRequest(`/api/user/subscriptions/create-payment-method?customerid=${user.customer.customerid}`)
req.account = user.account
req.session = user.session
req.body = {
email: user.profile.contactEmail,
description: 'Chase Sapphire',
name: user.profile.fullName,
cvc: '123',
number: '4111111111111111',
exp_month: '',
exp_year: (new Date().getFullYear() + 1).toString().substring(2)
}
let errorMessage
try {
await req.post()
} catch (error) {
errorMessage = error.message
}
assert.strictEqual(errorMessage, 'invalid-exp_month')
})
it('optionally-required posted exp_year', async () => {
global.stripeJS = false
const user = await TestHelper.createUser()
await TestHelper.createCustomer(user, {
email: user.profile.contactEmail
})
const req = TestHelper.createRequest(`/api/user/subscriptions/create-payment-method?customerid=${user.customer.customerid}`)
req.account = user.account
req.session = user.session
req.body = {
email: user.profile.contactEmail,
description: 'Chase Sapphire',
name: user.profile.fullName,
cvc: '123',
number: '4111111111111111',
exp_month: '1',
exp_year: ''
}
let errorMessage
try {
await req.post()
} catch (error) {
errorMessage = error.message
}
assert.strictEqual(errorMessage, 'invalid-exp_year')
})
it('optionally-required posted token', async () => {
global.stripeJS = 2
const user = await TestHelper.createUser()
await TestHelper.createCustomer(user, {
email: user.profile.contactEmail
})
const req = TestHelper.createRequest(`/api/user/subscriptions/create-payment-method?customerid=${user.customer.customerid}`)
req.account = user.account
req.session = user.session
req.body = {
email: user.profile.contactEmail,
description: 'Chase Sapphire',
name: user.profile.fullName,
token: ''
}
let errorMessage
try {
await req.post()
} catch (error) {
errorMessage = error.message
}
assert.strictEqual(errorMessage, 'invalid-token')
})
})
describe('returns', () => {
it('object', async () => {
global.stripeJS = false
const user = await TestHelper.createUser()
await TestHelper.createCustomer(user, {
email: user.profile.contactEmail
})
const req = TestHelper.createRequest(`/api/user/subscriptions/create-payment-method?customerid=${user.customer.customerid}`)
req.account = user.account
req.session = user.session
req.body = {
name: user.profile.fullName,
cvc: '111',
number: '4111111111111111',
exp_month: '1',
exp_year: (new Date().getFullYear() + 1).toString().substring(2),
line1: 'A street address',
city: 'City',
state: 'NY',
postal_code: '90120',
country: 'US',
default: 'true'
}
req.filename = __filename
req.saveResponse = true
const paymentMethod = await req.post()
assert.strictEqual(paymentMethod.object, 'paymentmethod')
})
})
describe('configuration', () => {
it('environment STRIPE_JS', async () => {
global.stripeJS = 2
const user = await TestHelper.createUser()
await TestHelper.createCustomer(user, {
email: user.profile.contactEmail
})
const req = TestHelper.createRequest(`/api/user/subscriptions/create-payment-method?customerid=${user.customer.customerid}`)
req.account = user.account
req.session = user.session
req.body = {
name: user.profile.fullName,
cvc: '111',
number: '4111111111111111',
exp_month: '1',
exp_year: (new Date().getFullYear() + 1).toString().substring(2),
line1: 'A street address',
city: 'City',
state: 'NY',
postal_code: '90120',
country: 'US',
default: 'true'
}
let errorMessage
try {
await req.post()
} catch (error) {
errorMessage = error.message
}
assert.strictEqual(errorMessage, 'invalid-token')
})
})
})