Stripe Subscriptions module API explorer

/api/user/subscriptions/charges (GET)

Account information like email addresses is generated with faker-js it is not real user information.

await global.api.user.subscriptions.Charges.get(req)

Returns array

[
  {
    "chargeid": "ch_3LEOalHHqepMFuCX1KT212nJ",
    "accountid": "acct_48c941c88d1f3f2c",
    "subscriptionid": "sub_1LEOalHHqepMFuCXhjzVrVRc",
    "customerid": "cus_LwH8EgBQ3sEogt",
    "paymentmethodid": null,
    "invoiceid": "in_1LEOalHHqepMFuCXp6D8T58B",
    "refundRequested": null,
    "refundReason": null,
    "refundDenied": null,
    "refundDeniedReason": null,
    "object": "charge",
    "stripeObject": {
      "id": "ch_3LEOalHHqepMFuCX1KT212nJ",
      "object": "charge",
      "amount": 3000,
      "amount_captured": 3000,
      "amount_refunded": 0,
      "application": null,
      "application_fee": null,
      "application_fee_amount": null,
      "balance_transaction": "txn_3LEOalHHqepMFuCX1weUhOoG",
      "billing_details": {
        "address": {
          "city": "New York",
          "country": "US",
          "line1": "285 Fulton St",
          "line2": "Apt 893",
          "postal_code": "10007",
          "state": "NY"
        },
        "email": null,
        "name": "Rafael Zemlak",
        "phone": null
      },
      "calculated_statement_descriptor": "PRODUCT255 DESCRIPTION",
      "captured": true,
      "created": 1656123563,
      "currency": "usd",
      "customer": "cus_LwH8EgBQ3sEogt",
      "description": "Subscription creation",
      "destination": null,
      "dispute": null,
      "disputed": false,
      "failure_balance_transaction": null,
      "failure_code": null,
      "failure_message": null,
      "fraud_details": {},
      "invoice": "in_1LEOalHHqepMFuCXp6D8T58B",
      "livemode": false,
      "metadata": {},
      "on_behalf_of": null,
      "order": null,
      "outcome": {
        "network_status": "approved_by_network",
        "reason": null,
        "risk_level": "normal",
        "risk_score": 41,
        "seller_message": "Payment complete.",
        "type": "authorized"
      },
      "paid": true,
      "payment_intent": "pi_3LEOalHHqepMFuCX1ki420kH",
      "payment_method": "pm_1LEOaTHHqepMFuCXSnftDFS6",
      "payment_method_details": {
        "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",
          "installments": null,
          "last4": "1111",
          "mandate": null,
          "network": "visa",
          "three_d_secure": null,
          "wallet": null
        },
        "type": "card"
      },
      "receipt_email": null,
      "receipt_number": null,
      "receipt_url": "https://pay.stripe.com/receipts/acct_1KhiP8HHqepMFuCX/ch_3LEOalHHqepMFuCX1KT212nJ/rcpt_LwH9hiSCxETXTNu0tlZeNQCmttnVQ3u",
      "refunded": false,
      "refunds": {
        "object": "list",
        "data": [],
        "has_more": false,
        "total_count": 0,
        "url": "/v1/charges/ch_3LEOalHHqepMFuCX1KT212nJ/refunds"
      },
      "review": null,
      "shipping": null,
      "source": null,
      "source_transfer": null,
      "statement_descriptor": "product255 description",
      "statement_descriptor_suffix": null,
      "status": "succeeded",
      "transfer_data": null,
      "transfer_group": null
    },
    "appid": "tests_1656123544",
    "createdAt": "2022-06-25T02:19:26.770Z",
    "updatedAt": "2022-06-25T02:19:27.220Z"
  },
  {
    "chargeid": "ch_3LEOagHHqepMFuCX0dxM42Ei",
    "accountid": "acct_48c941c88d1f3f2c",
    "subscriptionid": "sub_1LEOagHHqepMFuCX2gFtY335",
    "customerid": "cus_LwH8EgBQ3sEogt",
    "paymentmethodid": null,
    "invoiceid": "in_1LEOagHHqepMFuCXWia64PBb",
    "refundRequested": null,
    "refundReason": null,
    "refundDenied": null,
    "refundDeniedReason": null,
    "object": "charge",
    "stripeObject": {
      "id": "ch_3LEOagHHqepMFuCX0dxM42Ei",
      "object": "charge",
      "amount": 3000,
      "amount_captured": 3000,
      "amount_refunded": 0,
      "application": null,
      "application_fee": null,
      "application_fee_amount": null,
      "balance_transaction": "txn_3LEOagHHqepMFuCX0rFfYdJC",
      "billing_details": {
        "address": {
          "city": "New York",
          "country": "US",
          "line1": "285 Fulton St",
          "line2": "Apt 893",
          "postal_code": "10007",
          "state": "NY"
        },
        "email": null,
        "name": "Rafael Zemlak",
        "phone": null
      },
      "calculated_statement_descriptor": "PRODUCT255 DESCRIPTION",
      "captured": true,
      "created": 1656123559,
      "currency": "usd",
      "customer": "cus_LwH8EgBQ3sEogt",
      "description": "Subscription creation",
      "destination": null,
      "dispute": null,
      "disputed": false,
      "failure_balance_transaction": null,
      "failure_code": null,
      "failure_message": null,
      "fraud_details": {},
      "invoice": "in_1LEOagHHqepMFuCXWia64PBb",
      "livemode": false,
      "metadata": {},
      "on_behalf_of": null,
      "order": null,
      "outcome": {
        "network_status": "approved_by_network",
        "reason": null,
        "risk_level": "normal",
        "risk_score": 46,
        "seller_message": "Payment complete.",
        "type": "authorized"
      },
      "paid": true,
      "payment_intent": "pi_3LEOagHHqepMFuCX0xSZVXaa",
      "payment_method": "pm_1LEOaTHHqepMFuCXSnftDFS6",
      "payment_method_details": {
        "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",
          "installments": null,
          "last4": "1111",
          "mandate": null,
          "network": "visa",
          "three_d_secure": null,
          "wallet": null
        },
        "type": "card"
      },
      "receipt_email": null,
      "receipt_number": null,
      "receipt_url": "https://pay.stripe.com/receipts/invoices/CAcaFwoVYWNjdF8xS2hpUDhISHFlcE1GdUNYKKnh2ZUGMgbgU4LpciM6LBbA2u3r4Y3kPTL9LUIoC_ap6t7Z7siuhlox1HuWobUgW1luaZJKhBeZEUtO?s=ap",
      "refunded": false,
      "refunds": {
        "object": "list",
        "data": [],
        "has_more": false,
        "total_count": 0,
        "url": "/v1/charges/ch_3LEOagHHqepMFuCX0dxM42Ei/refunds"
      },
      "review": null,
      "shipping": null,
      "source": null,
      "source_transfer": null,
      "statement_descriptor": "product255 description",
      "statement_descriptor_suffix": null,
      "status": "succeeded",
      "transfer_data": null,
      "transfer_group": null
    },
    "appid": "tests_1656123544",
    "createdAt": "2022-06-25T02:19:21.752Z",
    "updatedAt": "2022-06-25T02:19:21.984Z"
  },
  {
    "chargeid": "ch_3LEOacHHqepMFuCX1gySD2WN",
    "accountid": "acct_48c941c88d1f3f2c",
    "subscriptionid": "sub_1LEOabHHqepMFuCXZjholg2Z",
    "customerid": "cus_LwH8EgBQ3sEogt",
    "paymentmethodid": null,
    "invoiceid": "in_1LEOabHHqepMFuCXU2aYSXIR",
    "refundRequested": null,
    "refundReason": null,
    "refundDenied": null,
    "refundDeniedReason": null,
    "object": "charge",
    "stripeObject": {
      "id": "ch_3LEOacHHqepMFuCX1gySD2WN",
      "object": "charge",
      "amount": 3000,
      "amount_captured": 3000,
      "amount_refunded": 0,
      "application": null,
      "application_fee": null,
      "application_fee_amount": null,
      "balance_transaction": "txn_3LEOacHHqepMFuCX1WgFP7rq",
      "billing_details": {
        "address": {
          "city": "New York",
          "country": "US",
          "line1": "285 Fulton St",
          "line2": "Apt 893",
          "postal_code": "10007",
          "state": "NY"
        },
        "email": null,
        "name": "Rafael Zemlak",
        "phone": null
      },
      "calculated_statement_descriptor": "PRODUCT255 DESCRIPTION",
      "captured": true,
      "created": 1656123554,
      "currency": "usd",
      "customer": "cus_LwH8EgBQ3sEogt",
      "description": "Subscription creation",
      "destination": null,
      "dispute": null,
      "disputed": false,
      "failure_balance_transaction": null,
      "failure_code": null,
      "failure_message": null,
      "fraud_details": {},
      "invoice": "in_1LEOabHHqepMFuCXU2aYSXIR",
      "livemode": false,
      "metadata": {},
      "on_behalf_of": null,
      "order": null,
      "outcome": {
        "network_status": "approved_by_network",
        "reason": null,
        "risk_level": "normal",
        "risk_score": 42,
        "seller_message": "Payment complete.",
        "type": "authorized"
      },
      "paid": true,
      "payment_intent": "pi_3LEOacHHqepMFuCX1zmoSfWF",
      "payment_method": "pm_1LEOaTHHqepMFuCXSnftDFS6",
      "payment_method_details": {
        "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",
          "installments": null,
          "last4": "1111",
          "mandate": null,
          "network": "visa",
          "three_d_secure": null,
          "wallet": null
        },
        "type": "card"
      },
      "receipt_email": null,
      "receipt_number": null,
      "receipt_url": "https://pay.stripe.com/receipts/invoices/CAcaFwoVYWNjdF8xS2hpUDhISHFlcE1GdUNYKKXh2ZUGMgbGX_2xNYo6LBaRUfVJ5xiisNFoA9yM061jsV-C4RywYR5qUyTG0umvYZuTHjvorcyKJODX?s=ap",
      "refunded": false,
      "refunds": {
        "object": "list",
        "data": [],
        "has_more": false,
        "total_count": 0,
        "url": "/v1/charges/ch_3LEOacHHqepMFuCX1gySD2WN/refunds"
      },
      "review": null,
      "shipping": null,
      "source": null,
      "source_transfer": null,
      "statement_descriptor": "product255 description",
      "statement_descriptor_suffix": null,
      "status": "succeeded",
      "transfer_data": null,
      "transfer_group": null
    },
    "appid": "tests_1656123544",
    "createdAt": "2022-06-25T02:19:17.147Z",
    "updatedAt": "2022-06-25T02:19:17.614Z"
  }
]

Receives

API routes may receive parameters from the URL and POST supporting simple and multipart:

Field Value Required Type
all boolean optional URL
limit integer optional URL
offset integer optional URL

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-accountid missing querystring accountid
invalid querystring accountid

NodeJS source (view on github)

const subscriptions = require('../../../../../index.js')

module.exports = {
  get: async (req) => {
    if (!req.query || !req.query.accountid) {
      throw new Error('invalid-accountid')
    }
    const account = await global.api.user.Account.get(req)
    if (!account) {
      throw new Error('invalid-account')
    }
    const where = {
      accountid: req.query.accountid,
      appid: req.appid || global.appid
    }
    let chargeids
    if (req.query.all) {
      chargeids = await subscriptions.Storage.Charge.findAll({
        where,
        attributes: ['chargeid'],
        order: [
          ['createdAt', 'DESC']
        ]
      })
    } else {
      const offset = req.query.offset ? parseInt(req.query.offset, 10) : 0
      const limit = req.query.limit ? parseInt(req.query.limit, 10) : global.pageSize
      chargeids = await subscriptions.Storage.Charge.findAll({
        where,
        attributes: ['chargeid'],
        offset,
        limit,
        order: [
          ['createdAt', 'DESC']
        ]
      })
    }
    if (!chargeids || !chargeids.length) {
      return null
    }
    const items = []
    for (const chargeInfo of chargeids) {
      req.query.chargeid = chargeInfo.dataValues.chargeid
      const charge = await global.api.user.subscriptions.Charge.get(req)
      items.push(charge)
    }
    return items
  }
}

Test source (view on github)

/* eslint-env mocha */
const assert = require('assert')
const TestHelper = require('../../../../../test-helper.js')
const TestStripeAccounts = require('../../../../../test-stripe-accounts.js')
const DashboardTestHelper = require('@layeredapps/dashboard/test-helper.js')

describe('/api/user/subscriptions/charges', function () {
  before(TestHelper.disableMetrics)
  after(TestHelper.enableMetrics)
  let cachedResponses, cachedCharges
  async function bundledData (retryNumber) {
    if (retryNumber > 0) {
      cachedResponses = {}
    }
    if (cachedResponses && cachedResponses.finished) {
      return
    }
    cachedResponses = {}
    cachedCharges = []
    await TestHelper.setupBefore()
    await DashboardTestHelper.setupBeforeEach()
    await TestHelper.setupBeforeEach()
    const administrator = await TestHelper.createOwner()
    await TestHelper.createProduct(administrator, {
      active: 'true'
    })
    const user = await TestStripeAccounts.createUserWithPaymentMethod()
    for (let i = 0, len = global.pageSize + 2; i < len; i++) {
      await TestHelper.createPrice(administrator, {
        productid: administrator.product.productid,
        active: 'true',
        unit_amount: 3000,
        currency: 'usd',
        tax_behavior: 'inclusive',
        recurring_interval: 'month',
        recurring_interval_count: '1',
        recurring_usage_type: 'licensed'
      })
      await TestStripeAccounts.createUserWithPaidSubscription(administrator.price, user)
      cachedCharges.unshift(user.charge.chargeid)
    }
    const req1 = TestHelper.createRequest(`/api/user/subscriptions/charges?accountid=${user.account.accountid}&offset=1`)
    req1.account = user.account
    req1.session = user.session
    cachedResponses.offset = await req1.get()
    const req2 = TestHelper.createRequest(`/api/user/subscriptions/charges?accountid=${user.account.accountid}&limit=1`)
    req2.account = user.account
    req2.session = user.session
    cachedResponses.limit = await req2.get()
    const req3 = TestHelper.createRequest(`/api/user/subscriptions/charges?accountid=${user.account.accountid}&all=true`)
    req3.account = user.account
    req3.session = user.session
    cachedResponses.all = await req3.get()
    const req4 = TestHelper.createRequest(`/api/user/subscriptions/charges?accountid=${user.account.accountid}`)
    req4.account = user.account
    req4.session = user.session
    req4.filename = __filename
    req4.saveResponse = true
    cachedResponses.returns = await req4.get()
    global.pageSize = 3
    cachedResponses.pageSize = await req4.get()
    global.pageSize = 2
    cachedResponses.finished = true
  }
  describe('exceptions', () => {
    describe('invalid-accountid', () => {
      it('missing querystring accountid', async () => {
        const user = await TestHelper.createUser()
        const req = TestHelper.createRequest('/api/user/subscriptions/charges')
        req.account = user.account
        req.session = user.session
        let errorMessage
        try {
          await req.get()
        } catch (error) {
          errorMessage = error.message
        }
        assert.strictEqual(errorMessage, 'invalid-accountid')
      })

      it('invalid querystring accountid', async () => {
        const user = await TestHelper.createUser()
        const req = TestHelper.createRequest('/api/user/subscriptions/charges?accountid=invalid')
        req.account = user.account
        req.session = user.session
        let errorMessage
        try {
          await req.get()
        } catch (error) {
          errorMessage = error.message
        }
        assert.strictEqual(errorMessage, 'invalid-accountid')
      })
    })

    describe('invalid-account', () => {
      it('ineligible accessing account', async function () {
        await bundledData(this.test.currentRetry())
        const user = await TestHelper.createUser()
        const user2 = await TestHelper.createUser()
        const req = TestHelper.createRequest(`/api/user/subscriptions/charges?accountid=${user.account.accountid}`)
        req.account = user2.account
        req.session = user2.session
        let errorMessage
        try {
          await req.get()
        } catch (error) {
          errorMessage = error.message
        }
        assert.strictEqual(errorMessage, 'invalid-account')
      })
    })
  })

  describe('receives', () => {
    it('optional querystring offset (integer)', async function () {
      await bundledData(this.test.currentRetry())
      const offset = 1
      const chargesNow = cachedResponses.offset
      for (let i = 0, len = global.pageSize; i < len; i++) {
        assert.strictEqual(chargesNow[i].chargeid, cachedCharges[offset + i])
      }
    })

    it('optional querystring limit (integer)', async function () {
      await bundledData(this.test.currentRetry())
      const limit = 1
      const chargesNow = cachedResponses.limit
      assert.strictEqual(chargesNow.length, limit)
    })

    it('optional querystring all (boolean)', async () => {
      const chargesNow = cachedResponses.all
      assert.strictEqual(chargesNow.length, cachedCharges.length)
    })
  })

  describe('returns', () => {
    it('array', async () => {
      const chargesNow = cachedResponses.returns
      assert.strictEqual(chargesNow.length, global.pageSize)
    })
  })

  describe('configuration', () => {
    it('environment PAGE_SIZE', async () => {
      const chargesNow = cachedResponses.pageSize
      assert.strictEqual(chargesNow.length, global.pageSize + 1)
    })
  })
})