Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
c43a100
Initial cut of the consumer issuing demo.
sidneyshek-stripe Apr 25, 2025
ab78a7f
Moved sidebar to top. Added some Spade enrichment data.
sidneyshek-stripe Apr 29, 2025
07efdc5
Make Google Maps render.
sidneyshek-stripe Apr 30, 2025
37d8f11
Fix logout bug
sidneyshek-stripe May 1, 2025
ddeba2a
Fix build error
sidneyshek-stripe May 2, 2025
636b2e1
Add missing dependencies to pacakge.json
sidneyshek-stripe May 2, 2025
5ddaf51
Fix build errors and ignore linting.
sidneyshek-stripe May 2, 2025
5eadd17
Add first integration with repayment API
sidneyshek-stripe May 2, 2025
2463f75
Fix repayment integration.
sidneyshek-stripe May 2, 2025
c1ef701
Make testmode styling different.
sidneyshek-stripe May 2, 2025
f40dbc4
Fix logout
sidneyshek-stripe May 3, 2025
5efab1c
UI updates.
sidneyshek-stripe May 5, 2025
b387a67
Add category to latest transaction table.
sidneyshek-stripe May 5, 2025
535b0da
Make repayment work.
sidneyshek-stripe May 6, 2025
cbcd68e
Add request logging.
sidneyshek-stripe May 6, 2025
6c9ac8d
Add a fetch credit data button
sidneyshek-stripe May 6, 2025
f081d7e
Adjust size of available credit.
sidneyshek-stripe May 6, 2025
1b65069
Fix delete account
sidneyshek-stripe May 6, 2025
15d7488
Update statements, fix rendering of Refund.
sidneyshek-stripe May 6, 2025
864b325
Skip credit ledger CLEs with FO
sidneyshek-stripe May 6, 2025
1bc95b2
Remove some console logging.
sidneyshek-stripe May 6, 2025
5f857dc
Optimize list retrieval
sidneyshek-stripe May 7, 2025
cfdeca3
Add payment reference.
sidneyshek-stripe May 14, 2025
a89d177
Fix adjustment rendering.
sidneyshek-stripe May 14, 2025
e050ce8
Fix FO filter
reshleman-stripe Jun 5, 2025
24f3db9
Add on-Stripe and off-Stripe repayment functionality - Enhanced API t…
reshleman-stripe Jun 6, 2025
36f40b9
Merge pull request #415 from stripe-samples/reshleman/ach-repayments
sidneyshek-stripe Jun 6, 2025
b45cc74
Fix repayment type in sidebar
reshleman-stripe Jun 6, 2025
a4dc120
Add back the payment method dropdown
reshleman-stripe Jun 6, 2025
8c9d3e3
Load payment methods when the sidebar opens
reshleman-stripe Jun 6, 2025
fb5a31b
Fix PM loading state
reshleman-stripe Jun 6, 2025
de14424
Fix repayment success message
reshleman-stripe Jun 6, 2025
98cb0b6
Merge pull request #416 from stripe-samples/reshleman/polish-repayments
reshleman-stripe Jun 6, 2025
5104c3b
Use the credit credit statements API
reshleman-stripe Jun 8, 2025
ad7cc5d
Merge pull request #417 from stripe-samples/reshleman/credit-statemen…
reshleman-stripe Jun 9, 2025
9a97c40
Empty-Commit
sidneyshek-stripe Jun 9, 2025
c39dd36
Bulk retrieve credit repayments.
sidneyshek-stripe Jun 10, 2025
cfe8c68
Log repayment POST requests
reshleman-stripe Jun 11, 2025
9873bdf
Merge pull request #418 from stripe-samples/reshleman/log-repayment-post
reshleman-stripe Jun 11, 2025
407da3f
Empty-Commit
sidneyshek-stripe Jun 11, 2025
2cb54d6
Various changes for Friday Fireside demo.
sidneyshek-stripe Jun 12, 2025
2f7c268
Fix styling.
sidneyshek-stripe Jun 12, 2025
9668e09
More Friday Fireside fixes.
sidneyshek-stripe Jun 12, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion _base/next.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const isDevelopment = process.env.NODE_ENV === "development";
const ContentSecurityPolicy = `
default-src 'none';
base-uri 'none';
connect-src 'self';
connect-src 'self' https://maps.googleapis.com;
font-src 'self' fonts.gstatic.com;
form-action 'self';
frame-ancestors 'none';
Expand Down
32 changes: 32 additions & 0 deletions consumer-issuing/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
### Stripe configuration

# You can get a test publishable key from the Stripe dashboard: https://dashboard.stripe.com/test/apikeys
# It has the `NEXT_PUBLIC_` prefix so that it can be used in the client-side code
# This demo app can support different regions by having separate platform accounts. You can create a
# platform account for each region and use the corresponding publishable and secret keys here.
# Not all regions/key pairs are required to be set up: you can provide either one of both of UK and EU.
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY_UK="" # pk_test_...
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY_EU="" # pk_test_...
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY_US="" # pk_test_...
STRIPE_SECRET_KEY_UK="" # sk_test_...
STRIPE_SECRET_KEY_EU="" # sk_test_...
STRIPE_SECRET_KEY_US="" # sk_test_...

# The URL that will be redirected to after a user completes Connect Onboarding
CONNECT_ONBOARDING_REDIRECT_URL="http://localhost:3000"

### Auth configuration

# You can generate this using `openssl rand -base64 32`
NEXTAUTH_SECRET=""
# Your NextAuth base URL
NEXTAUTH_URL="http://localhost:3000"

### Demo configuration

NEXT_PUBLIC_DEMO_MODE="false"

### Database configuration

DATABASE_URL="postgresql://postgres@localhost/consumer_issuing"
POSTGRES_URL=${DATABASE_URL}
25 changes: 25 additions & 0 deletions consumer-issuing/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// {
// "parser": "@typescript-eslint/parser",
// "plugins": ["@typescript-eslint", "prettier", "import", "unused-imports"],
// "extends": [
// "next/core-web-vitals",
// "plugin:@typescript-eslint/recommended",
// "plugin:prettier/recommended",
// "plugin:import/recommended",
// "plugin:import/typescript"
// ],
// "rules": {
// "import/order": ["error", {
// "newlines-between": "always",
// "alphabetize": {
// "order": "asc"
// }
// }],
// "no-console": "warn",
// "unused-imports/no-unused-imports": "error", // Autofix unused imports
// "unused-imports/no-unused-vars": [
// "warn",
// { "vars": "all", "varsIgnorePattern": "^_", "args": "after-used", "argsIgnorePattern": "^_" }
// ] // Autofix unused vars, with options to ignore variables and arguments starting with _
// }
// }
1 change: 1 addition & 0 deletions consumer-issuing/.node-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
18.17.1
107 changes: 107 additions & 0 deletions consumer-issuing/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# Stripe Issuing: An Expense Management starter application

This sample demonstrates a basic web application with expense management features built on Stripe’s Issuing APIs.

<p align="center">
<img width="715" alt="Issuing sample app card details screenshot" src="https://github.com/stripe-samples/issuing-treasury/blob/main/expense-management/public/assets/issuing-only-screenshot.jpeg" />
</p>

## Features

- Onboard and verify business customers 🔍
- Issue cards 💳
- Display full card numbers with PCI compliance 🔢
- Test funding an Issuing balance 🏦
- Simulate test payments ⚡
- Review transactions 📃

## Prerequisites

- Activate Stripe Issuing in test mode through this link: <https://dashboard.stripe.com/setup/issuing/activate?a=1>
- Obtain your Stripe API keys at <https://dashboard.stripe.com/test/apikeys>

## Deploy the sample app to the cloud

Click the button below to get started on [Vercel](https://vercel.com/docs). During setup, you will be asked to provide values for some environment variables. See information about [required environment variables](#environment-variables) below to learn more about the API keys and secrets you'll need to provide.

This starter app supports both UK and EU Issuing users: you can provide Stripe API keys for platforms based in _one or both_ of those regions. Most users will only issue in one region, so will need to provide only the `_UK` or `_EU` environment variables. Note that Vercel considers all environment variables for one-click deployments to be compulsory: use the string value `none` for the regional environment variables that you don't want to provide.

[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fstripe-samples%2Fissuing-treasury%2Fexpense-management&env=NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY_UK,STRIPE_SECRET_KEY_UK,NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY_EU,STRIPE_SECRET_KEY_EU,NEXTAUTH_SECRET&project-name=expense-management&demo-title=Expense%20Management%20app&demo-description=A%20commercial%20pre-funded%20card&repository-name=expense-management&stores=%5B%7B%22type%22%3A%22postgres%22%7D%5D)

## Local development

You can also clone this repo and run it locally by following the steps below.

### Clone the repo

Clone this repo and then run these steps inside it.

git clone https://github.com/stripe-samples/issuing-treasury.git && cd issuing-treasury/expense-management

### Node.js installation

Install the required Node.js runtime. You can install it directly from the [Node.js website](https://nodejs.org/en/download/releases)
but we recommend using a Node version manager. Most version managers can read the required version off of `.node-version`
and install it.

If you're using the `nodenv` Node version manager ([setup instructions for nodenv](https://github.com/nodenv/nodenv#installation)), use:

nodenv install

If you're using the popular `nvm` Node version manager ([setup instructions for Node Version Manager](https://github.com/nvm-sh/nvm#installing-and-updating)), use:

nvm install

### Dependency installation

Once Node.js is installed and activated, install the application's dependencies using:

npm install

### Environment variables file setup <a name="environment-variables"></a>

Replicate `.env.example` as `.env` using:

cp .env.example .env

Update `.env` to reflect:

- **NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY**: Your Stripe publishable test mode [API key](https://dashboard.stripe.com/test/apikeys) (starts with `pk_test_...`).
- **STRIPE_SECRET_KEY**: Your Stripe secret test mode [API key](https://dashboard.stripe.com/test/apikeys) (starts with `sk_test_...`).
- **NEXTAUTH_SECRET**: For JWT encryption by NextAuth.js ([learn more](https://next-auth.js.org/configuration/options#nextauth_secret)). Use `openssl rand -base64 32` to obtain a new one.
- **NEXTAUTH_URL**: Your application URL, for local use you can keep the default "<http://localhost:3000>".
- **CONNECT_ONBOARDING_REDIRECT_URL**: Your application URL, for local use you can keep the default "<http://localhost:3000>".

### Database setup

On Mac, follow these instructions to install Postgres:

brew install postgresql@14
createuser -s postgres
createdb "$(whoami)"

You'll find more about the why you need the `createuser` step [here](https://stackoverflow.com/a/15309551).

Next, create the database with:

npx prisma migrate dev

If it errors out (perhaps due to permission issue running the Prisma CLI), simply run the included script:

./db/setup-database.postgres.sh

This script creates a local Postgres `expense_management` database.

### Application launch

After necessary setups, launch the application with `npm run dev`.

*Note: This application serves as an example and should not proceed to production deployment as it is.*

## Customizing your UI with the Devias Material UI theme

This sample uses the [free Devias UI kit](https://github.com/devias-io/material-kit-react) under an MIT license, which seamlessly integrates with Material UI and React.

You can easily customize aspects of the theme like the color palette by modifying the code in `/src/theme`.

To build a full-featured, production-ready application we recommend the [Devias Pro](https://material-kit-pro-react.devias.io/) version, which offers additional layouts, advanced React components, pre-built dashboards, and essential TypeScript support that ensures your code remains clean, robust, and scalable.
34 changes: 34 additions & 0 deletions consumer-issuing/db/setup-database.postgres.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#!/bin/bash

# Ideally you should be able to use `npx prisma migrate dev` to migrate your Postgres database but if that fails for any
# reason, you can use this script to get started quickly.

DB_NAME="expense_management"

# Check if the database exists
db_exists=$(psql -tAc "SELECT 1 FROM pg_database WHERE datname='$DB_NAME'")

if [ "$db_exists" != "1" ]; then
# Create the database
echo "Creating database..."
psql -c "CREATE DATABASE $DB_NAME;"
else
echo "Database already exists, skipping creation..."
fi

# Connect to the database and create the users table if it doesn't exist
echo "Creating users table..."
psql -d $DB_NAME -c "
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
email TEXT UNIQUE NOT NULL,
password TEXT NOT NULL,
account_id TEXT NOT NULL,
country TEXT NOT NULL,
last_login_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
"

echo "Setup complete!"
5 changes: 5 additions & 0 deletions consumer-issuing/next-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/pages/building-your-application/configuring/typescript for more information.
52 changes: 52 additions & 0 deletions consumer-issuing/next.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
const isDevelopment = process.env.NODE_ENV === "development";

// We are setting the CSP headers as strictly as possible. There are a few notable exceptions being made:
// - We are allowing 'unsafe-eval' in the script-src directive in development only because we are using Next.js'
// built-in support for React Fast Refresh. This is a temporary exception until Next.js supports a better
// solution for Fast Refresh.
// - We are allowing 'unsafe-inline' in the style-src directive. This is a temporary exception until Next.js
// supports a better solution.
// - We are allowing fonts.gstatic.com and fonts.googleapis.com in the font-src directive. We could host the
// fonts ourselves, but it's easier to use Google Fonts and the risk is minimal. Feel free to host the fonts
// yourself if you prefer and tighten up the font-src and style-src directives.
// - We are allowing js.stripe.com in the frame-src directive. This is required for Stripe Issuing Elements to work.
//
// Learn more about CSP: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
// Learn more about Next.js security headers: https://nextjs.org/docs/pages/api-reference/next-config-js/headers#content-security-policy
//
// Also follow [this discussion](https://github.com/vercel/next.js/discussions/41473) about making Next.js have a
// strict CSP implementation which would make it easier to tighten these directives with a `nonce`.
const ContentSecurityPolicy = `
default-src 'none';
base-uri 'none';
connect-src 'self';
font-src 'self' fonts.gstatic.com;
form-action 'self';
frame-ancestors 'none';
frame-src js.stripe.com;
img-src 'self';
script-src 'self' js.stripe.com ${isDevelopment ? "'unsafe-eval'" : ""};
style-src 'self' 'unsafe-inline' fonts.googleapis.com;
upgrade-insecure-requests;
`;

/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
swcMinify: true,
async headers() {
return [
{
source: "/:path*",
headers: [
{
key: "Content-Security-Policy",
value: ContentSecurityPolicy.replace(/\s{2,}/g, " ").trim(),
},
],
},
];
},
};

export default nextConfig;
Loading