This is the frontend library for the Tamed Stripe architecture. This library aims to provide the frontend functions that can be used to communicate with the tamed-stripe-backend
. It supports easy to adopt methods for basic customer generation, connected account generation, subscription generation and payment functions.
-
Assure the database and backend applications are up and running.
-
Install the library with peer dependencies
yarn add tamed-stripe-frontend react-native-webview@11.26.0 react-native-webview-with-web
- import the library
import tsf from 'tamed-stripe-frontend';
import { StripeActionPage } from 'tamed-stripe-frontend';
At this point you can use the library.
This function initializes the library with the backend url and routes.
If you are using the backend library, you can use the below exact same code.
useEffect(() => {
tsf.init({
apiBackend: apiBackend,
routes: {
"generateCustomer": "/generate-customer",
"generateSubscription": "/generate-subscription",
"generateProduct": "/generate-product",
"generateAccount": "/generate-account",
"oneTimePayment": "/one-time-payment",
"getOneTimePaymentStatus": "/get-one-time-payment-status",
"getSubscriptionPaymentsByStripeCustomerId": "/test/get-subscription-payments-by-stripe-customer-id",
},
debugMode: true
});
}, []);
Uses react-native-webview
to show the Stripe action pages.
Name | Type | Description |
---|---|---|
url | string | The url to be shown in the webview. |
setUrl | function | The function to be called when the url changes. Using this function caller can be signalled to close the web view. For example by setting the url as '' and detecting zero length url from the caller. |
<StripeActionPage
url={accountLinkUrl}
setUrl={setAccountLinkUrl}
/>
For an example usage of closing webview, please refer to the example application.
Generates a stripe customer and links the stripe customer and application customer using the backend generateCustomer
Name | Type | Description |
---|---|---|
props | object | The props object. |
Name | Type | Description |
---|---|---|
applicationCustomerId | string | The application customer id. |
description | string | The description of the customer. |
string | The email of the customer. | |
metadata | object | The metadata for the customer. |
name | string | The name of the customer. |
phone | string | The phone number of the customer. |
address | object | The address of the customer. |
publicDomain | string | The public domain of the application. |
successRoute | string | The route to be called when the customer is successfully generated. |
cancelRoute | string | The route to be called when the customer generation is cancelled. |
Name | Type | Description |
---|---|---|
city | string | City of the customer. |
country | string | Country of the customer. |
line1 | string | Line 1 of the address of the customer. |
line2 | string | Line 2 of the address of the customer. |
postal_code | string | Postal code of the customer. |
state | string | State of the customer. |
Returns a customer object and a checkout session. Use the checkout session to redirect the user to the checkout page to collect default payment method.
{
result: 'OK',
payload: {
customer,
checkoutSession
},
}
const [customerCheckoutSessionUrl, setCustomerCheckoutSessionUrl] = useState('');
...
const result = await tsf.generateCustomer({
applicationCustomerId: applicationCustomerId,
description: `Mobile App Test Customer`,
email: email,
metadata: { "test": "test" },
name: `Mobile App Test Customer`,
phone: `1234567890`,
address: { "line1": "1234 Main St", "city": "San Francisco", "state": "CA", "postal_code": "94111" },
publicDomain: apiBackend,
});
setCustomerCheckoutSessionUrl(result.payload.checkoutSession.url);
...
const screen = (customerCheckoutSessionUrl.length > 0)
? <View style={{ height: '100%', width: '100%' }}>
<StripeActionPage
url={customerCheckoutSessionUrl}
setUrl={setCustomerCheckoutSessionUrl}
/>
</View>
: <> </>
...
Gets a stripe customer using the backend getCustomer
Name | Type | Description |
---|---|---|
props | object | The props object. |
Name | Type | Description |
---|---|---|
applicationCustomerId | string | The application customer id. |
Returns a customer object.
{
result: 'OK',
payload: {
customer
},
}
const result = await tsf.getCustomer({
applicationCustomerId: applicationCustomerId,
});
Generates a product to be used for subscription generation using the backend generateProduct
Name | Type | Description |
---|---|---|
props | object | The props object. |
Name | Type | Description |
---|---|---|
name | string | The name of the product. |
description | string | The description of the product. |
currency | string | The currency of the product. |
unitAmountDecimal | string | The unit amount of the product. In cents. |
interval | string | The interval of the product. This can be one of following values; 'day' , 'week' , 'month' , 'year' . |
taxBehavior | string | Optional. Tax behavior of the product. This can be one of following values; 'exclusive' , 'inclusive' , 'unspecified' . |
taxCode | string | Optional. Tax code of the product. Comes from the Stripe's Product Tax Categories. |
Returns a product and a price object in the payload
{
result: 'OK',
payload: {
product,
price
}
}
const resultProduct = await tsf.generateProduct({
name: subscriptionName,
description: subscriptionName,
currency: 'usd',
unitAmountDecimal: `${subscriptionCharge}`,
interval: 'month',
taxBehavior: 'exclusive',
taxCode: 'txcd_30060006' // Stripe tax code for hats. :-)
});
Generates a subscription using the backend generateSubscription.
Name | Type | Description |
---|---|---|
props | object | The props object. |
Name | Type | Description |
---|---|---|
applicationCustomerId | string | The application's customer id. |
recurringPriceId | string | The stripe price id of the recurring price. Comes from generateProduct. |
description | string | The description of the subscription. |
automaticTax | object | Optional. Automatic tax settings of the subscription. If to be used following object should be passed: { enabled: true }
|
unlinkIfSubscriptionFails | boolean | Optional. If set to true, the customer will be unlinked from the application if the subscription fails. |
Returns a subscription object.
{
result: 'OK',
payload: subscription,
}
// first generate a product
const resultProduct = await tsf.generateProduct({
name: subscriptionName,
description: subscriptionName,
currency: 'usd',
unitAmountDecimal: `${subscriptionCharge}`,
interval: 'month',
taxBehavior: 'exclusive',
taxCode: 'txcd_30060006' // Stripe tax code for hats. :-)
});
// then generate a subscription using the product
const resultSubscription = await tsf.generateSubscription({
applicationCustomerId: props.applicationCustomerId,
recurringPriceId: resultProduct.payload.price.id,
description: `${subscriptionName} Subscription`,
automaticTax: { enabled: true },
unlinkIfSubscriptionFails: true,
});
Gets the DB rows indicating all subscription payments history for a certain stripe customer id. For a particular product's subscription, the returned rows should be filtered by the stripe_product_id
field at the application side.
Name | Type | Description |
---|---|---|
props | object | The props object. |
Name | Type | Description |
---|---|---|
customerId | string | The stripe customer id that the payments are to be retrieved for. |
Returns the DB rows indicating all subscription payments history for a certain stripe customer id.
{
result: 'OK',
payload: rows,
}
const payments = await tsf.exportedForTesting.getSubscriptionPaymentsByStripeCustomerId({
customerId: customerId
});
Generates a connected account that is to be used as a payee, using the backend generateAccount. The returned account URL should be used to initiate the account creation process. Similarly, for a process started earlier but not concluded, same method can be called to continue the registration process on Stripe.
Name | Type | Description |
---|---|---|
props | object | The props object. |
Name | Type | Description |
---|---|---|
applicationCustomerId | string | The application customer id, used to link the application customer to the Stripe connected account. |
string | The email of the connected account. | |
publicDomain | string | The public domain of the application. |
country | string | The country of the connected account, defaults to 'US'. |
refreshUrlRoute | string | Route for the refresh URL. Defaults to /generate-account-cancel-route for which the route can be handled by this library. |
returnUrlRoute | string | Route for the return URL. Defaults to /generate-account-success-route for which the route can be handled by this library. |
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,
}
}
const [accountLinkUrl, setAccountLinkUrl] = useState('');
...
const generateAccount = async () => {
const now = new Date().getTime();
const account = await tsf.generateAccount({
applicationCustomerId,
email,
publicDomain: apiBackend,
country: country.toUpperCase(),
});
setAccountLinkUrl(account.payload.accountLinkURL);
};
...
const screen = (accountLinkUrl.length > 0)
? <View style={{ height: '100%', width: '100%' }}>
<StripeActionPage
url={accountLinkUrl}
setUrl={setAccountLinkUrl}
/>
</View>
: <> </>
...
Gets the connected account that is to be used as a payee, using the backend getAccount.
Name | Type | Description |
---|---|---|
props | object | The props object. |
Name | Type | Description |
---|---|---|
applicationCustomerId | string | The application customer id, used to link the application customer to the Stripe connected account. |
Returns the connected account that is to be used as a payee.
{
result: 'OK',
payload: account,
}
const account = await tsf.getAccount({
applicationCustomerId: applicationCustomerId,
});
Generates a checkout session that is to be used to charge a customer and optionally transfer a portion to a payee, using the backend oneTimePayment.
Name | Type | Description |
---|---|---|
props | object | The props object. |
Name | Type | Description |
---|---|---|
applicationCustomerId | string | The application customer id, used to link the application customer to the payment. |
currency | string | The currency of the payment. Defaults to 'usd'
|
items | Array | The items to be charged. |
payoutData | Object | The payout data. |
publicDomain | Public domain of the server, to use the return URLs. | |
automaticTax | Object | (Optional) Automatic tax data for the payment. If sent, should be the object: { enabled: true }
|
newCustomerParams | Object | (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. |
Array of objects, each object should have the following fields:
Name | Type | Description |
---|---|---|
name | string | The name of the item. |
amount | number | The amount of the item, in cents. |
tax_code | string | Tax code of the item. Comes from the Stripe's Product Tax Categories. |
Name | Type | Description |
---|---|---|
payoutAccountId | string | Stripe account id of the payee. |
payoutAmount | string | Amount to be paid to the payee, in cents. |
Key | Type | Value |
---|---|---|
string | Email of the customer. | |
description | string | Description of the customer. |
metadata | Object | Metadata for the customer, you can embed andy data within this object, it is kept in Stripe servers also. |
name | string | Name of the customer. |
phone | string | Phone number of the customer. |
address | Object | Address of the customer. |
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,
}
const [oneTimePaymentUrl, setOneTimePaymentUrl] = useState('');
const tax_code = 'txcd_30060006';
...
const oneTimePayment = async () => {
const payoutData = {
payoutAmount,
payoutAccountId,
}
const items = [
{ name: oneTimeChargeItem1, unitAmountDecimal: `${oneTimeCharge1}`, tax_code, },
{ name: oneTimeChargeItem2, unitAmountDecimal: `${oneTimeCharge2}`, tax_code, },
];
const body = {
applicationCustomerId,
currency: 'usd',
items,
payoutData,
publicDomain: apiBackend,
automaticTax: { enabled: true },
};
const result = await tsf.oneTimePayment(body);
// wait 10 seconds for the webhook to fire
await new Promise(resolve => setTimeout(resolve, 10000));
setOneTimePaymentUrl(result.payload.url);
};
...
const screen = (oneTimePaymentUrl.length > 0)
? <View style={{ height: '100%', width: '100%' }}>
<StripeActionPage
url={oneTimePaymentUrl}
setUrl={setOneTimePaymentUrl}
/>
</View>
: <> </>
...
Used to get the current status of a checkout session using the backend getOneTimePaymentStatus.
Name | Type | Description |
---|---|---|
props | object | The props object. |
Name | Type | Description |
---|---|---|
checkoutSessionId | string | The checkout session id. |
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.
const result = await tsf.getOneTimePaymentStatus({checkoutSessionId});
console.log(`One Time Payment Status : ${JSON.stringify(result.payload.rows[0], null, 2)}`);
Used to refund a one time payment using the backend refundOneTimePayment.
Name | Type | Description |
---|---|---|
props | object | The props object. |
Name | Type | Description |
---|---|---|
checkoutSessionId | string | The checkout session id. |
Returns the refund object created by Stripe.
{
result: 'OK',
payload: refund,
}
const result = await tsf.refundOneTimePayment({checkoutSessionId});
console.log(`One Time Payment Refund : ${JSON.stringify(result.payload, null, 2)}`);
The example application (made with react-native and Expo) can be found here. Also the jest test cases can be used as examples, which can be found here.
The license is MIT and full text here.
Please refer to the main github page for the list of used modules.