1.1.13 • Published 1 year ago

tamed-stripe-backend v1.1.13

Weekly downloads
-
License
MIT
Repository
github
Last release
1 year ago

WHY?

This is the backend library for the Tamed Stripe architecture. This library aims to provide the backend integrations with the Stripe API servers for basic customer generation, connected account generation, subscription generation and payment functions.

SETUP

  1. Add the backend library to the backend of your project.
yarn add tamed-stripe-backend
  1. Modify the TAMED_STRIPE_SECRET_KEY environment parameter to use to connect to the Stripe.
export TAMED_STRIPE_SECRET_KEY="YOUR_STRIPE_SECRET_KEY" # starts with sk_
  1. Initialize parameters (modify below object according to your environment)

    Use this file as a template for your backend configuration. This file is to be required by your express server in the next step. You should modify the credentials, according to your environment.

    KeyTypeValue
    pgKeysObjectPostgreSQL connection parameters.
    debugModeBooleanIf true, the library will log debug messages.
  2. Call the init function of the library to initialize the db connection pool. And then start your server. As a reference you can use this file which utilize the tamed-express-server library for a quick start.

API

init

The init function initializes the database connection pool. Additionally it provides a method to increase the log level.

ParameterTypeDescription
p_paramsObjectParameters for the backend server.

p_params

KeyTypeValue
pgKeysObjectPostgreSQL connection parameters.
debugModeBooleanIf true, the library will log debug messages.

Returns

If successful, resolves to true. Otherwise, rejects with an error message.

Example

const tsb = require("../tamed-stripe-backend.js");
...
await tsb.init({
	debugMode: debugMode,
	// coming from database-setup
	pgKeys: {
		user: 'tamedstripeapp',
		password: 'tamedstripeapp.',
		database: 'tamedstripedb',
		host: 'localhost',
		port: 5432,
	},
});

generateCustomer

Generates a payer customer at Stripe and attaches a payment method to it so that the customer can do payments.

Reading Data from Database

Once a customer is generated, you can reach the customer within your database from the tamedstripe.customers table. The application_customer_id field of the tamedstripe.customers table is the applicationCustomerId parameter of this function. You can use this field to link your application's customer structure with the Stripe side customer id.

ParameterTypeDescription
bodyObjectParameters for the generating a payer customer at Stripe

body

KeyTypeValue
applicationCustomerIdstringThis is your application's customer id that you can use to link your application customer structure with stripe side customer id.
paymentMethodId(optional)stringPayment method id of the payment method to be attached to the customer. If this is omitted a new payment method will be generated with a checkout session.
descriptionstringDescription of the customer.
emailstringEmail of the customer.
metadataObjectMetadata for the customer, you can embed andy data within this object, it is kept in Stripe servers also.
namestringName of the customer.
phonestringPhone number of the customer.
addressObjectAddress of the customer.
publicDomainstringPublic domain of the website.
successRoutestringRoute to redirect to on successful checkout. Defaults to /generate-customer-success-route which is handled by the library function generateCustomerSuccessRoute. We suggest you to keep this as undefined and use the default value because the default value signals frontend a method to close WebViews.
cancelRoutestringRoute to redirect to on cancelled checkout. Defaults to /generate-customer-cancel-route which is handled by the library function generateCustomerCancelRoute. We suggest you to keep this as undefined and use the default value because the default value signals frontend a method to close WebViews.
testClockId(optional)stringThis is an optional clock id that is a method that Stripe provides for future dated tests. For an example usage, you can refer to subscriptionPayment - next 2 months tests.
address
KeyTypeValue
citystringCity of the customer.
countrystringCountry of the customer.
line1stringLine 1 of the address of the customer.
line2stringLine 2 of the address of the customer.
postal_codestringPostal code of the customer.
statestringState of the customer.

Returns

If successful, resolves to below JSON object. The checkoutSession object is optional and it holds the checkout session information which can be used to collect the default payment method information from users. Otherwise, rejects with an error message.

{
	result: 'OK',
	payload: {
		customer,
		checkoutSession
	},
}

Example

   ...
	const body = { applicationCustomerId, description, email, metadata, name, phone, address, publicDomain };
	let response = await tsb.generateCustomer(body);

generateCustomerSuccessRoute

This is the default route handler for the generateCustomer handler. This is used if the successRoute parameter of the generateCustomer handler is a falsy value. We suggest you to use this handler because the redirect signals frontend a method to close WebViews.

generateCustomerCancelRoute

This is the default route handler for the generateCustomer handler. This is used if the cancelRoute parameter of the generateCustomer handler is a falsy value. We suggest you to use this handler because the redirect signals frontend a method to close WebViews, and it also unlinks a customer so that it can not provide hurdles for future operations.

getCustomer

Gets stripe customer information from the database, using the applicationCustomerId parameter.

ParameterTypeDescription
bodyObjectParameters for the generating a payer customer at Stripe

body

KeyTypeValue
applicationCustomerIdstringThis is your application's customer id that you can use to link your application customer structure with stripe side customer id.

Returns

If successful, resolves to below JSON object. Otherwise, rejects with an error message.

{
	result: 'OK',
	payload: {
		customer // customer.rows[0] from DB with selected columns
	},
}

Example

   ...
	const body = { applicationCustomerId };
	let response = await tsb.getCustomer(body);

generateProduct

Generates a product that can be used in checkout sessions that is to be a basis for subscriptions. Once a product is generated, you can reach the product within your database from the tamedstripe.products table. The stripe_product_id field of the tamedstripe.products table is the Stripe's product id.

ParameterTypeDescription
bodyObjectParameters for the generating a payer customer at Stripe

body

KeyTypeValue
namestringName of the product.
descriptionstringDescription of the product.
currencystringCurrency of the product.
unitAmountDecimalnumberUnit amount of the product in CENTS.
intervalstringInterval of the product. This can be one of following values; 'day', 'week', 'month', 'year'.
taxBehaviorstringOptional. Tax behavior of the product. This can be one of following values; 'exclusive', 'inclusive', 'unspecified'.
taxCodestringOptional. Tax code of the product. Comes from the Stripe's Product Tax Categories.

Returns

If successful, resolves to below JSON object. Otherwise, rejects with an error message.

{
	result: 'OK',
	payload: {
		product,
		price
	},
}

Example

	const body = {
		name: 'Test Product',
		description: 'Test Product Description',
		currency: 'usd',
		unitAmountDecimal: 1000, // This value is in cents, so it is $10.00, 
		interval: 'month',
		taxBehavior: 'exclusive',
		taxCode: 'txcd_30060006' // Stripe tax code for hats. :-) 
	};
	let response = await tsb.generateProduct(body);

generateSubscription

Generates a subscription for a customer. Once a subscription is generated, you can reach the subscription within your database from the tamedstripe.subscriptions table. The stripe_subscription_id field of the tamedstripe.subscriptions table is the Stripe's subscription id. The stripe_product_id field of the tamedstripe.subscriptions table is the Stripe's product id. The state field can be one of following values; 'A' (active), 'C'(cancelled). As long as a subscription is active the Stripe will charge the customer automatically.

Reading Data from Database

Once Stripe charges a customer for a subscription, it is received via a 'invoice.paid' web hook. And when that webhook indicating a successfull payment is made, tamedstripe.subscription_payments table is modified accordingly. In this table you can check if current date-time is between the subscription_covered_from and subscription_covered_to fields of any row of the same subscription's payments. If it is, then the subscription is covered for that period. If it is not, then the subscription is not covered for that period. You can use this information to determine if a subscription is covered for a period or not and serve your functionality to your customer.

For example below row from the tamedstripe.subscription_payments table indicates that the subscription is covered for the period between 2023-03-23 14:36:36 and 2023-04-23 14:36:36. So if you want to check if a subscription is covered for the current date-time, you can check if the current date-time is between 2023-03-23 14:36:36 and 2023-04-23 14:36:36. If it is, then the subscription is covered for that period. If it is not, then the subscription is not covered for that period.

 id |    stripe_subscription_id    | unit_amount_decimal | currency | state | subscription_covered_from | subscription_covered_to 
----+------------------------------+---------------------+----------+-------+---------------------------+-------------------------
  1 | sub_1MopFoCDKfcpGwAfZiZTD1Gg |              100001 | usd      | P     | 2023-03-23 14:36:36       | 2023-04-23 14:36:36
ParameterTypeDescription
bodyObjectParameters for the generating a subscription at Stripe

body

KeyTypeValue
customerIdstringStripe customer id that the subscription will be generated for.
recurringPriceIdstringStripe price id of the recurring price, which should be previously generated using generateProduct function.
descriptionstringDescription of the subscription.
automaticTaxobjectOptional. Automatic tax settings of the subscription. If to be used following object should be passed: { enabled: true }
unlinkIfSubscriptionFailsbooleanOptional. If set to true, then the customer will be unlinked from the application if the subscription fails.

Returns

If successful, resolves to below JSON object. Otherwise, rejects with an error message.

{
	result: 'OK',
	payload: subscription,
}

Example

const productProps = {
	name: 'Test',
	description: 'Test',
	currency: 'usd',
	unitAmountDecimal: '1234567', // This value is in cents, so it is $12345,67,
	interval: 'month',
	taxBehavior: 'exclusive',
	taxCode: 'txcd_30060006' // Stripe tax code for hats. :-)
};
const response2 = await tsb.generateProduct(productProps);
const priceData = response2.payload.price;
...
await tsb.generateSubscription({
	applicationCustomerId: applicationCustomerId,
	recurringPriceId: priceData.id,
	description: description,
	automaticTax: { enabled: true },
	unlinkIfSubscriptionFails: true,
});

getSubscriptionPayments

Gets the payments of an application customer id for all subscriptions. The retrieved list can be filtered to find the needed payments.

ParameterTypeDescription
bodyObjectParameters for the generating a payer customer at Stripe

body

KeyTypeValue
applicationCustomerIdstringApplication customer id of the customer that the subscription payments will be retrieved for.

Returns

If successful, resolves to below JSON object. Otherwise, rejects with an error message.

{
	result: 'OK',
	payload: subscriptionPayments,
}

Example

const response = await tsb.getSubscriptionPayments({
	applicationCustomerId: applicationCustomerId,
});

cancelSubscription

Cancels a subscription.

ParameterTypeDescription
bodyObjectParameters for the generating a payer customer at Stripe

body

KeyTypeValue
subscriptionIdstringId of the subscription to be cancelled.

Returns

If successful, resolves to below JSON object where subscription object is coming from Stripe. Otherwise, rejects with an error message.

{
	result: 'OK',
	payload: subscription,
}

Example

	const body = {
		subscriptionId: 'sub_1234567890',
	};
	let response = await tsb.cancelSubscription(body);

generateAccount

Generates a payee account (aka connected account) at Stripe and its associated account link for the end user to complete the account generation process on Stripe.

The account link is generated for the end user to complete the account generation process on Stripe. The end user should be redirected to the Stripe's website to complete the account generation process using the returned link. After the account generation process is completed, the end user will be redirected to the return URL of the account link.

Reading Data from Database

The connected account information for a customer is kept in the tamedstripe.connected_accounts table. In this table application_customer_id is the customer id of your system and it is to be used to link your software to the generated application_customer_id. The state field can be either 'W' or A. W means the account is waiting for the end user to complete the account generation process on Stripe. 'A' means the account is active and ready to be used. For 'W' rows, you can re-call this function to recieeve an active URL that you can use to direct your users to complete their account generation process on Stripe.

ParameterTypeDescription
bodyObjectParameters for the generating a payee account at Stripe

body

KeyTypeValue
applicationCustomerIdstringId of the application customer that the account will be generated for.
emailstringEmail of the account.
publicDomainStringPublic domain of the server, to use the return URLs.
refreshUrlRouteStringRoute for the refresh URL. Defaults to /generate-account-cancel-route for which the route can be handled by this library.
returnUrlRouteStringRoute for the return URL. Defaults to /generate-account-success-route for which the route can be handled by this library.
countryStringCountry of the account. Defaults to US.
capabilitiesJSONDefaults to {transfers: { requested: true }}

Returns

You should expect 3 different responses from this function.

  • If there is a successfully generated account for the given applicationCustomerId, then the response will be as below, and the payload.id can be used as Stripe side payee (connected_account) id.
{
	result: 'OK',
	payload: {
		id: result.rows[0].stripe_account_id,
		accountLinkURL: ''
	}
}
  • If previously account generation process started but the end user did not complete the process, then the response will be as below, and the payload.accountLinkURL can be used to redirect the end user to the Stripe's website to complete the account generation process. Use the accountLinkURL field to redirect the end user to the Stripe's website to complete the account generation process.
{
	result: 'OK',
	payload: {
		id: result.rows[0].stripe_account_id,
		accountLinkURL: accountLinkForW.url,
		urlRegenerated: true
	}
}
  • If there is no account for the given applicationCustomerId, then the response will be as below, and the payload.accountLinkURL can be used to redirect the end user to the Stripe's website to start the account generation process.
{
	result: 'OK',
	payload: {
		result: 'OK',
		payload: account,
	}
}

Example

const props = {
	applicationCustomerId,
	email,
	publicDomain,
	country,
};
const response1 = await tsb.generateAccount(props);

generateAccountSuccessRoute

Provides the default route content for th /generate-account-success-route route. This route is used to handle the return URL of the account link. The default route content can be used as is, or you can use it as a template to create your own route content.

generateAccountCancelRoute

Provides the default route content for th /generate-account-cancel-route route. This route is used to handle the refresh URL of the account link. The default route content can be used as is, or you can use it as a template to create your own route content.

getAccount

Gets the account information for the given applicationCustomerId.

ParameterTypeDescription
bodyObjectParameters for the generating a payee account at Stripe

body

KeyTypeValue
applicationCustomerIdstringId of the application customer that the account will be generated for.

Returns

If successful, resolves to below JSON object. Otherwise, rejects with an error message.

{
	result: 'OK',
	payload: account, // account.rows[0] from DB with selected columns
}

Example

	const response2 = await tsb.getAccount({applicationCustomerId});

oneTimePayment

Generates a one time payment checkout session at Stripe. You can use that session URL to direct your users to the Stripe's website to complete the payment process.

Reading Data from Database

The payment data is kept in the tamedstripe.one_time_payments table. In this table application_customer_id is the customer id of your system and it is to be used to link your software to the generated checkout_session_id. The state field can be either 'W', 'P' or F. W means the payment is waiting for the end user to complete the payment process on Stripe. 'P' means the payment is completed. 'F' means payment is failed.

Additionally, for successfully paid customers, if you need to show your customer the related invoice, you can call the url residing in the hosted_invoice_url field.

ParameterTypeDescription
bodyObjectParameters for the generating a one time payment checkout session at Stripe

body

KeyTypeValue
applicationCustomerIdstringId of the application customer that the payment will be generated for.
currencystringCurrency of the payment.
itemsArrayArray of items to be paid.
payoutDataObjectPayout data for the payment.
publicDomainStringPublic domain of the server, to use the return URLs.
automaticTaxObject(Optional) Automatic tax data for the payment. If sent, should be the object: { enabled: true }
newCustomerParamsObject(Optional) This is only for oneTimePayment scenarios where no persistent customer exists, like the subscription or saved payment method scenarios. If sent, a new customer will be generated with the given parameters if there is no existing customer with the applicationCustomerId parameter.
items
KeyTypeValue
namestringName of the item.
amountstringAmount of the item, in cents.
tax_codestringTax code of the item. Comes from the Stripe's Product Tax Categories.
payoutData
KeyTypeValue
payoutAmountstringAmount to be paid to the payee, in cents.
payoutAccountIdstringStripe account id of the payee.
newCustomerParams
KeyTypeValue
emailstringEmail of the customer.
descriptionstringDescription of the customer.
metadataObjectMetadata for the customer, you can embed andy data within this object, it is kept in Stripe servers also.
namestringName of the customer.
phonestringPhone number of the customer.
addressObjectAddress of the customer.

Returns

Returns the checkoutSession object created by Stripe. The url field of the returned payload can be used to redirect the end user to the Stripe's website to complete the payment process.

{
	result: 'OK',
	payload: checkoutSession,
}

Example

const currency = 'eur';
const items = [
	// txcd_30060006 is the tax code for the "Hats" category in https://stripe.com/docs/tax/tax-categories
	{ name: "Red Hat", unitAmountDecimal: "100000", tax_code: 'txcd_30060006' }, 
	{ name: "Green Hat", unitAmountDecimal: "200000", tax_code: 'txcd_30060006' },
	{ name: "Blue Hat", unitAmountDecimal: "300000", tax_code: 'txcd_30060006' },
];
const payoutData = {
	payoutAmount: "225000",
	payoutAccountId: "some-account-id-who-will-receive-the-payment",
	useOnBehalfOf: true
};
const automaticTax = { enabled: true };
const props = {
	applicationCustomerId,
	currency,
	items,
	payoutData,
	publicDomain,
	automaticTax,
};
const response3 = await tsb.oneTimePayment(props);

oneTimePaymentSuccessRoute

Provides the default route content for th /one-time-payment-success-route route. This route is used to handle the return URL of the checkout session. The default route content can be used as is, or you can use it as a template to create your own route content. We suggest to use this route because it helps to manage the frontend application web view state.

oneTimePaymentCancelRoute

Provides the default route content for th /one-time-payment-cancel-route route. This route is used to handle the refresh URL of the checkout session. The default route content can be used as is, or you can use it as a template to create your own route content. We suggest to use this route because it helps to manage the frontend application web view state.

getOneTimePaymentStatus

Returns the status of a one time payment.

ParameterTypeDescription
bodyObjectParameters for the generating a one time payment checkout session at Stripe

body

KeyTypeValue
checkoutSessionIdstringId of the checkout session.

Returns

The payload holds the database state of the requested payment.

{
	result: 'OK',
	payload: rows,
}

The payload.rows[0] is a database row in the following form:

 id |              application_customer_id               | stripe_customer_id |                        checkout_session_id                         |        update_time         | total_amount_decimal | currency | state |         invoice_id          |                                                                      hosted_invoice_url                                                                       | payout_amount |   payout_account_id   | payout_state 
----+----------------------------------------------------+--------------------+--------------------------------------------------------------------+----------------------------+----------------------+----------+-------+-----------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------+-----------------------+--------------
  2 | Application Customer-1679582193973                 | cus_... | cs_xxxx... | 2023-03-24 14:34:57.000013 |               450000 | eur      | P     | in_... | https://invoice.stripe.com/i/acct_.../test_...?s=ap |        225000 | acct_... | W

Here the state = 'P' means the payment is completed. And you can ues the url in the hosted_invoice_url field to show the invoice to the customer.

refundOneTimePayment

Refunds a completed one time payment using the checkout session id.

ParameterTypeDescription
bodyObjectThe object that holds the parmeters

body

KeyTypeValue
checkoutSessionIdstringId of the checkout session.

Returns

The payload holds the refund object coming from Stripe.

{
	result: 'OK',
	payload: refund,
}

Example

const checkoutSessionIdToRefund = "cs_XXX"; // completed checkout session id of the payment to be refunded
await tsb.refundOneTimePayment({ checkoutSessionId: checkoutSessionIdToRefund });

webhook

This is a webhook endpoint that can be used to handle the Stripe events. The events are directed to different functions.

This library handles following events

EventFunctionDescription
checkout.session.completedwebhookCheckoutSessionCompletedSetup or webhookCheckoutSessionCompletedPaymentStripe sends this event when a checkout session for a new customer payment method is completed or when a one time payment is done. This library checks the event.data.object.mode parameter to differentiate these 2 events.
invoice.paidwebhookSubscriptionInvoicePaidWe use this event to detect subscription payments. For this purpose we check if the event.data.object.billing_reason field is subscription related or not. (If it is not subscription related, it is ignored.)
account.updatedwebhookAccountUpdatedWe use this event to detect connected account updates. And we check the event.data.object.charges_enabled and the event.data.object.payouts_enabled parameters to decide if the connected account is successfully generated or not.

Using the data in the DB

The tamed-stripe libraries provide the fundamental functionalities connecting to the Stripe. However, if there is no change at Stripe, the data in the database can be used to get latest state of the customers, connected accounts, subscriptions and payments without calling Stripe.

For these purposes we suggest to familiarize yourself with the database structure. The ERD of the database can be found below.

ERD

More Examples

The example application can be found here. Also the jest test cases can be used as examples, which can be found here.

License

The license is MIT and full text here.

Used Modules

Please refer to the main github page for the list of used modules.

1.1.13

1 year ago

1.1.12

2 years ago

1.1.9

2 years ago

1.1.8

2 years ago

1.1.11

2 years ago

1.1.10

2 years ago

1.1.7

2 years ago

1.1.6

2 years ago

1.1.5

2 years ago

1.1.4

2 years ago

1.0.82

2 years ago

1.0.81

2 years ago

1.0.79

2 years ago

1.0.78

2 years ago

1.0.77

2 years ago

1.0.76

2 years ago

1.0.75

2 years ago

1.0.74

2 years ago

1.0.73

2 years ago

1.0.71

2 years ago

1.0.70

2 years ago

1.0.69

2 years ago

1.0.68

2 years ago

1.0.67

2 years ago

1.0.66

2 years ago

1.0.65

2 years ago

1.0.64

2 years ago

1.0.63

2 years ago

1.0.62

2 years ago

1.0.61

2 years ago

1.0.60

2 years ago

1.0.59

2 years ago

1.0.58

2 years ago

1.0.57

2 years ago

1.0.56

2 years ago

1.0.55

2 years ago

1.0.54

2 years ago

1.0.53

2 years ago

1.0.52

2 years ago

1.0.51

2 years ago

1.0.50

2 years ago

1.0.49

2 years ago

1.0.48

2 years ago

1.0.47

2 years ago

1.0.46

2 years ago

1.0.45

2 years ago

1.0.44

2 years ago

1.0.43

2 years ago

1.0.42

2 years ago

1.0.41

2 years ago

1.0.40

2 years ago

1.0.39

2 years ago

1.0.38

2 years ago

1.0.37

2 years ago

1.0.36

2 years ago

1.0.35

2 years ago

1.0.34

2 years ago

1.0.33

2 years ago

1.0.32

2 years ago

1.0.31

2 years ago

1.0.30

2 years ago

1.0.29

2 years ago

1.0.28

2 years ago

1.0.27

2 years ago

1.0.26

2 years ago

1.0.25

2 years ago

1.0.24

2 years ago

1.0.23

2 years ago

1.0.21

2 years ago

1.0.20

2 years ago

1.0.19

2 years ago

1.0.18

2 years ago

1.0.17

2 years ago

1.0.16

2 years ago

1.0.15

2 years ago

1.0.14

2 years ago

1.0.13

2 years ago

1.0.12

2 years ago

1.0.11

2 years ago

1.0.10

2 years ago

1.0.8

2 years ago

1.0.7

2 years ago

1.0.6

2 years ago

1.0.5

2 years ago

1.0.4

2 years ago

1.0.3

2 years ago

1.0.2

2 years ago

1.0.1

2 years ago

1.0.0

2 years ago

0.0.1

2 years ago