├── schema ├── .gitignore ├── README.md ├── jest.config.js ├── .eslintrc ├── tsconfig.json └── package.json ├── examples ├── settings-view │ ├── .env.example │ └── bring-your-own-backend │ │ ├── Screenshot-2.png │ │ ├── screenshot-1.png │ │ ├── frontend │ │ ├── jest.config.ts │ │ ├── .gitignore │ │ ├── stripe-app.json │ │ ├── tsconfig.json │ │ ├── package.json │ │ └── src │ │ │ └── views │ │ │ └── App.tsx │ │ ├── backend │ │ ├── node │ │ │ ├── README.md │ │ │ ├── package.json │ │ │ └── app.js │ │ └── .gitignore │ │ └── README.md ├── climate │ ├── src │ │ ├── mocks │ │ │ └── fileMock.tsx │ │ ├── views │ │ │ └── ClimateSampleApp.tsx │ │ └── components │ │ │ ├── ClimateLinkComponent.test.tsx │ │ │ ├── climate_logo.svg │ │ │ └── ClimateLinkComponent.tsx │ ├── screenshot.png │ ├── jest.config.ts │ ├── .gitignore │ ├── stripe-app.json │ ├── tsconfig.json │ ├── package.json │ └── README.md ├── crm-full-stack │ ├── nodejs-backend │ │ ├── .gitignore │ │ ├── src │ │ │ ├── index.ts │ │ │ ├── lib │ │ │ │ └── prisma.ts │ │ │ ├── services │ │ │ │ └── index.ts │ │ │ └── app.ts │ │ ├── Dockerfile │ │ ├── prisma │ │ │ └── schema.prisma │ │ └── package.json │ ├── stripe-app │ │ ├── .gitignore │ │ ├── src │ │ │ ├── types │ │ │ │ └── index.ts │ │ │ ├── api │ │ │ │ └── index.ts │ │ │ ├── views │ │ │ │ ├── brand_icon.svg │ │ │ │ └── HomeOverviewView.tsx │ │ │ └── components │ │ │ │ ├── Notes │ │ │ │ └── index.tsx │ │ │ │ └── AddNoteView │ │ │ │ └── index.tsx │ │ ├── jest.config.ts │ │ ├── tsconfig.json │ │ ├── stripe-app.json │ │ ├── images.d.ts │ │ ├── .eslintrc.json │ │ └── package.json │ ├── logo.png │ └── README.md ├── show-toast │ ├── src │ │ ├── components │ │ │ ├── index.ts │ │ │ └── Form.tsx │ │ └── events.ts │ ├── app_icon.png │ ├── jest.config.ts │ ├── stripe-app.json │ ├── tsconfig.json │ ├── images.d.ts │ └── package.json ├── dropbox-oauth-pkce │ ├── config.example.ts │ ├── src │ │ ├── util │ │ │ ├── types.ts │ │ │ ├── getDropboxAccount.ts │ │ │ └── getDropboxToken.ts │ │ └── hooks │ │ │ └── useSecretStore.tsx │ ├── .gitignore │ ├── tsconfig.json │ ├── package.json │ ├── stripe-app.json │ └── README.md ├── ui-testing │ ├── .prettierrc │ ├── jest.config.ts │ ├── .gitignore │ ├── stripe-app.json │ ├── README.md │ ├── tsconfig.json │ ├── package.json │ └── src │ │ └── views │ │ ├── App.test.tsx │ │ └── App.tsx ├── ship-io │ ├── .vscode │ │ └── extensions.json │ ├── src │ │ ├── constants.ts │ │ ├── assets │ │ │ ├── ficus-altissima.jpeg │ │ │ ├── fiddle-leaf-fig.jpeg │ │ │ ├── stripe-brand-icon.png │ │ │ └── gardening-tool-set.jpeg │ │ ├── common │ │ │ └── types.ts │ │ ├── views │ │ │ ├── App.tsx │ │ │ ├── HomeView.tsx │ │ │ └── LoginView.tsx │ │ ├── hooks │ │ │ └── LoginState.tsx │ │ └── components │ │ │ └── BaseView.tsx │ ├── ShipIOPreview.gif │ ├── jest.config.ts │ ├── .gitignore │ ├── stripe-app.json │ ├── tsconfig.json │ ├── images.d.ts │ ├── .eslintrc.json │ ├── package.json │ └── README.md ├── accessing-contextual-data │ ├── .prettierrc │ ├── Screenshot-1.png │ ├── jest.config.ts │ ├── .gitignore │ ├── tsconfig.json │ ├── README.md │ ├── package.json │ ├── stripe-app.json │ └── src │ │ └── views │ │ └── Product.tsx ├── routing │ ├── list-screen.png │ ├── actions-screen.png │ ├── jest.config.ts │ ├── .gitignore │ ├── stripe-app.json │ ├── tsconfig.json │ ├── package.json │ └── README.md ├── send-mail │ ├── screenshot.png │ ├── jest.config.ts │ ├── .gitignore │ ├── api │ │ ├── package.json │ │ └── index.ts │ ├── stripe-app.json │ ├── tsconfig.json │ ├── package.json │ ├── src │ │ ├── views │ │ │ └── App.tsx │ │ ├── components │ │ │ ├── SendButton.tsx │ │ │ ├── SendEmailForm.spec.tsx │ │ │ └── SendEmailForm.tsx │ │ └── hooks │ │ │ └── loadCustomer.ts │ └── README.md ├── focus-view │ ├── screenshot-1.png │ ├── screenshot-2.png │ ├── jest.config.ts │ ├── .gitignore │ ├── README.md │ ├── stripe-app.json │ ├── tsconfig.json │ ├── package.json │ └── src │ │ └── views │ │ └── App.tsx ├── install-webhooks │ ├── backend │ │ ├── ruby │ │ │ ├── Gemfile │ │ │ ├── README.md │ │ │ └── index.rb │ │ ├── java │ │ │ ├── gradle │ │ │ │ └── wrapper │ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── .gitattributes │ │ │ ├── settings.gradle │ │ │ ├── README.md │ │ │ └── app │ │ │ │ └── build.gradle │ │ ├── dotnet │ │ │ ├── appsettings.Development.json │ │ │ ├── appsettings.json │ │ │ ├── Model │ │ │ │ └── UserAccount.cs │ │ │ ├── README.md │ │ │ ├── dotnet.csproj │ │ │ ├── Program.cs │ │ │ └── Properties │ │ │ │ └── launchSettings.json │ │ ├── python │ │ │ ├── requirements.txt │ │ │ ├── README.md │ │ │ └── index.py │ │ ├── php │ │ │ ├── composer.json │ │ │ └── README.md │ │ ├── node │ │ │ ├── .gitignore │ │ │ ├── README.md │ │ │ ├── package.json │ │ │ └── index.js │ │ ├── .gitignore │ │ ├── go │ │ │ └── README.md │ │ └── README.md │ ├── app-screenshot.png │ ├── .env.example │ └── frontend │ │ ├── jest.config.ts │ │ ├── .gitignore │ │ ├── stripe-app.json │ │ ├── tsconfig.json │ │ ├── package.json │ │ └── src │ │ └── views │ │ └── App.tsx ├── super-todo │ ├── PaymentListView.png │ ├── CustomerDetailView.png │ ├── CustomerListView.png │ ├── HomeOverviewView.png │ ├── jest.config.ts │ ├── src │ │ ├── assets │ │ │ ├── super-todo-logo.svg │ │ │ ├── super-todo-icon.svg │ │ │ └── stripe-logo.svg │ │ ├── components │ │ │ ├── index.ts │ │ │ ├── SuperTodoView.tsx │ │ │ ├── ListTabPanel.tsx │ │ │ ├── CreateListMeta.tsx │ │ │ ├── TodosComponent.tsx │ │ │ └── CreateListBasics.tsx │ │ └── views │ │ │ ├── PaymentListView.tsx │ │ │ ├── CustomerDetailView.tsx │ │ │ └── HomeOverviewView.tsx │ ├── .gitignore │ ├── .editorconfig │ ├── package.json │ ├── tsconfig.json │ ├── images.d.ts │ ├── stripe-app.json │ ├── .eslintrc.json │ └── README.md ├── linking-different-stripe-object │ ├── Screenshot-1.png │ ├── Screenshot-2.png │ ├── jest.config.ts │ ├── .gitignore │ ├── tsconfig.json │ ├── README.md │ ├── package.json │ ├── stripe-app.json │ └── src │ │ └── views │ │ ├── AppView.tsx │ │ └── CustomerView.tsx ├── messaging │ ├── src │ │ ├── __mocks__ │ │ │ └── dayjs.ts │ │ ├── types.ts │ │ ├── utils │ │ │ ├── time.ts │ │ │ └── stripeApi.ts │ │ ├── clients │ │ │ └── stripe.ts │ │ ├── fakeData.ts │ │ └── views │ │ │ └── Messaging.tsx │ ├── jest.config.ts │ ├── .gitignore │ ├── README.md │ ├── package.json │ ├── tsconfig.json │ └── stripe-app.json ├── github-oauth │ ├── packages │ │ ├── backend │ │ │ ├── README.md │ │ │ ├── .env.example │ │ │ ├── tsconfig.json │ │ │ ├── src │ │ │ │ └── config.ts │ │ │ └── package.json │ │ └── frontend │ │ │ ├── package.json │ │ │ ├── stripe-app.json │ │ │ └── tsconfig.json │ ├── .gitignore │ ├── .prettierrc │ ├── .eslintrc.js │ ├── package.json │ └── README.md ├── secret-store │ ├── backend │ │ ├── package.json │ │ ├── README.md │ │ └── app.js │ └── ui-extension │ │ ├── README.md │ │ ├── tsconfig.json │ │ ├── stripe-app.json │ │ └── package.json └── basic-auth │ ├── backend │ ├── tsconfig.json │ └── package.json │ └── frontend │ ├── package.json │ ├── stripe-app.json │ └── tsconfig.json ├── .gitignore ├── CHANGELOG.md ├── .readme ├── bg-banner-top.png ├── bg-banner-bottom.png └── blocks.svg ├── .github ├── ISSUE_TEMPLATE │ ├── documentation.md │ ├── feature-request-enhancement.md │ └── -bug--bug-report.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ └── test_schema.yml ├── SECURITY.md ├── CONTRIBUTING.md ├── LICENSE └── README.md /schema/.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | -------------------------------------------------------------------------------- /examples/settings-view/.env.example: -------------------------------------------------------------------------------- 1 | APP_SECRET= 2 | STRIPE_API_KEY= -------------------------------------------------------------------------------- /examples/climate/src/mocks/fileMock.tsx: -------------------------------------------------------------------------------- 1 | export default "test-file-stub" -------------------------------------------------------------------------------- /examples/crm-full-stack/nodejs-backend/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .env.* -------------------------------------------------------------------------------- /examples/show-toast/src/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./Form"; 2 | -------------------------------------------------------------------------------- /examples/dropbox-oauth-pkce/config.example.ts: -------------------------------------------------------------------------------- 1 | export const client_id = ''; 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | 4 | examples/**/.build 5 | 6 | .yalc 7 | yalc.lock 8 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | View the changelog on NPM: https://www.npmjs.com/package/@stripe/ui-extension-sdk 2 | -------------------------------------------------------------------------------- /examples/ui-testing/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "es5", 3 | "singleQuote": true 4 | } -------------------------------------------------------------------------------- /.readme/bg-banner-top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stripe/stripe-apps/main/.readme/bg-banner-top.png -------------------------------------------------------------------------------- /examples/ship-io/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["dbaeumer.vscode-eslint"] 3 | } 4 | -------------------------------------------------------------------------------- /.readme/bg-banner-bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stripe/stripe-apps/main/.readme/bg-banner-bottom.png -------------------------------------------------------------------------------- /examples/crm-full-stack/stripe-app/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | .env* 4 | 5 | .build 6 | .vscode -------------------------------------------------------------------------------- /examples/ship-io/src/constants.ts: -------------------------------------------------------------------------------- 1 | export const TITLE = "Ship.IO"; 2 | export const BRAND_COLOR = "#00356b"; 3 | -------------------------------------------------------------------------------- /examples/accessing-contextual-data/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "es5", 3 | "singleQuote": true 4 | } 5 | -------------------------------------------------------------------------------- /examples/climate/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stripe/stripe-apps/main/examples/climate/screenshot.png -------------------------------------------------------------------------------- /examples/crm-full-stack/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stripe/stripe-apps/main/examples/crm-full-stack/logo.png -------------------------------------------------------------------------------- /examples/routing/list-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stripe/stripe-apps/main/examples/routing/list-screen.png -------------------------------------------------------------------------------- /examples/show-toast/app_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stripe/stripe-apps/main/examples/show-toast/app_icon.png -------------------------------------------------------------------------------- /examples/send-mail/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stripe/stripe-apps/main/examples/send-mail/screenshot.png -------------------------------------------------------------------------------- /examples/ship-io/ShipIOPreview.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stripe/stripe-apps/main/examples/ship-io/ShipIOPreview.gif -------------------------------------------------------------------------------- /examples/focus-view/screenshot-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stripe/stripe-apps/main/examples/focus-view/screenshot-1.png -------------------------------------------------------------------------------- /examples/focus-view/screenshot-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stripe/stripe-apps/main/examples/focus-view/screenshot-2.png -------------------------------------------------------------------------------- /examples/routing/actions-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stripe/stripe-apps/main/examples/routing/actions-screen.png -------------------------------------------------------------------------------- /examples/install-webhooks/backend/ruby/Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem 'stripe' 4 | gem 'sinatra' 5 | gem 'dotenv' -------------------------------------------------------------------------------- /examples/super-todo/PaymentListView.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stripe/stripe-apps/main/examples/super-todo/PaymentListView.png -------------------------------------------------------------------------------- /examples/super-todo/CustomerDetailView.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stripe/stripe-apps/main/examples/super-todo/CustomerDetailView.png -------------------------------------------------------------------------------- /examples/super-todo/CustomerListView.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stripe/stripe-apps/main/examples/super-todo/CustomerListView.png -------------------------------------------------------------------------------- /examples/super-todo/HomeOverviewView.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stripe/stripe-apps/main/examples/super-todo/HomeOverviewView.png -------------------------------------------------------------------------------- /examples/install-webhooks/app-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stripe/stripe-apps/main/examples/install-webhooks/app-screenshot.png -------------------------------------------------------------------------------- /examples/ship-io/src/assets/ficus-altissima.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stripe/stripe-apps/main/examples/ship-io/src/assets/ficus-altissima.jpeg -------------------------------------------------------------------------------- /examples/ship-io/src/assets/fiddle-leaf-fig.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stripe/stripe-apps/main/examples/ship-io/src/assets/fiddle-leaf-fig.jpeg -------------------------------------------------------------------------------- /examples/ship-io/src/assets/stripe-brand-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stripe/stripe-apps/main/examples/ship-io/src/assets/stripe-brand-icon.png -------------------------------------------------------------------------------- /examples/accessing-contextual-data/Screenshot-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stripe/stripe-apps/main/examples/accessing-contextual-data/Screenshot-1.png -------------------------------------------------------------------------------- /examples/ship-io/src/assets/gardening-tool-set.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stripe/stripe-apps/main/examples/ship-io/src/assets/gardening-tool-set.jpeg -------------------------------------------------------------------------------- /examples/linking-different-stripe-object/Screenshot-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stripe/stripe-apps/main/examples/linking-different-stripe-object/Screenshot-1.png -------------------------------------------------------------------------------- /examples/linking-different-stripe-object/Screenshot-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stripe/stripe-apps/main/examples/linking-different-stripe-object/Screenshot-2.png -------------------------------------------------------------------------------- /examples/settings-view/bring-your-own-backend/Screenshot-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stripe/stripe-apps/main/examples/settings-view/bring-your-own-backend/Screenshot-2.png -------------------------------------------------------------------------------- /examples/settings-view/bring-your-own-backend/screenshot-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stripe/stripe-apps/main/examples/settings-view/bring-your-own-backend/screenshot-1.png -------------------------------------------------------------------------------- /examples/messaging/src/__mocks__/dayjs.ts: -------------------------------------------------------------------------------- 1 | const mock = () => ({ 2 | fromNow: jest.fn().mockReturnValue('Test date') 3 | }); 4 | 5 | mock.extend = jest.fn(); 6 | 7 | export default mock; 8 | -------------------------------------------------------------------------------- /examples/install-webhooks/backend/java/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stripe/stripe-apps/main/examples/install-webhooks/backend/java/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /examples/send-mail/jest.config.ts: -------------------------------------------------------------------------------- 1 | import type {Config} from '@jest/types'; 2 | 3 | const config: Config.InitialOptions = { 4 | preset: 'ts-jest', 5 | roots: ['./src'], 6 | }; 7 | export default config; -------------------------------------------------------------------------------- /examples/messaging/jest.config.ts: -------------------------------------------------------------------------------- 1 | import type {Config} from '@jest/types'; 2 | 3 | const config: Config.InitialOptions = { 4 | preset: 'ts-jest', 5 | roots: ['./src'], 6 | }; 7 | export default config; 8 | -------------------------------------------------------------------------------- /examples/routing/jest.config.ts: -------------------------------------------------------------------------------- 1 | import type {Config} from '@jest/types'; 2 | 3 | const config: Config.InitialOptions = { 4 | preset: 'ts-jest', 5 | roots: ['./src'], 6 | }; 7 | 8 | export default config; 9 | -------------------------------------------------------------------------------- /examples/focus-view/jest.config.ts: -------------------------------------------------------------------------------- 1 | import type {Config} from '@jest/types'; 2 | 3 | const config: Config.InitialOptions = { 4 | preset: 'ts-jest', 5 | roots: ['./src'], 6 | }; 7 | 8 | export default config; 9 | -------------------------------------------------------------------------------- /examples/super-todo/jest.config.ts: -------------------------------------------------------------------------------- 1 | import type {Config} from '@jest/types'; 2 | 3 | const config: Config.InitialOptions = { 4 | preset: 'ts-jest', 5 | roots: ['./src'], 6 | }; 7 | 8 | export default config; 9 | -------------------------------------------------------------------------------- /examples/ui-testing/jest.config.ts: -------------------------------------------------------------------------------- 1 | import type {Config} from '@jest/types'; 2 | 3 | const config: Config.InitialOptions = { 4 | preset: 'ts-jest', 5 | roots: ['./src'], 6 | }; 7 | 8 | export default config; 9 | -------------------------------------------------------------------------------- /examples/install-webhooks/backend/dotnet/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /examples/accessing-contextual-data/jest.config.ts: -------------------------------------------------------------------------------- 1 | import type {Config} from '@jest/types'; 2 | 3 | const config: Config.InitialOptions = { 4 | preset: 'ts-jest', 5 | roots: ['./src'], 6 | }; 7 | 8 | export default config; 9 | -------------------------------------------------------------------------------- /examples/install-webhooks/.env.example: -------------------------------------------------------------------------------- 1 | STRIPE_API_KEY=/* the secret API key from your Developer Dashboard */ 2 | STRIPE_WEBHOOK_SECRET=/* signing secret you can find by running `stripe listen` or going to the webhook setup page */ -------------------------------------------------------------------------------- /examples/install-webhooks/backend/java/.gitattributes: -------------------------------------------------------------------------------- 1 | # 2 | # https://help.github.com/articles/dealing-with-line-endings/ 3 | # 4 | # These are explicitly windows files and should use crlf 5 | *.bat text eol=crlf 6 | 7 | -------------------------------------------------------------------------------- /examples/install-webhooks/frontend/jest.config.ts: -------------------------------------------------------------------------------- 1 | import type {Config} from '@jest/types'; 2 | 3 | const config: Config.InitialOptions = { 4 | preset: 'ts-jest', 5 | roots: ['./src'], 6 | }; 7 | 8 | export default config; 9 | -------------------------------------------------------------------------------- /examples/linking-different-stripe-object/jest.config.ts: -------------------------------------------------------------------------------- 1 | import type {Config} from '@jest/types'; 2 | 3 | const config: Config.InitialOptions = { 4 | preset: 'ts-jest', 5 | roots: ['./src'], 6 | }; 7 | 8 | export default config; 9 | -------------------------------------------------------------------------------- /schema/README.md: -------------------------------------------------------------------------------- 1 | # Stripe Apps manifest JSON schema 2 | 3 | This package stores and tests the JSON schema for the `stripe-app.json` manifest file. It will be referenced in the [JSON Schema Store](https://schemastore.org) catalog. 4 | -------------------------------------------------------------------------------- /examples/messaging/src/types.ts: -------------------------------------------------------------------------------- 1 | export interface Message { 2 | id: string; 3 | subject: string; 4 | from: string; 5 | to: string; 6 | date: number; // epoch milliseconds 7 | snippet: string; 8 | body: string; 9 | }; 10 | -------------------------------------------------------------------------------- /examples/github-oauth/packages/backend/README.md: -------------------------------------------------------------------------------- 1 | Before starting, make sure you: 2 | 3 | 1. Create a `.env` file based on the contents of `.env.example` with correct values. 4 | 2. Run `yarn generateKeys` to create `server.key` and `server.cert` files. -------------------------------------------------------------------------------- /examples/messaging/src/utils/time.ts: -------------------------------------------------------------------------------- 1 | import dayjs from 'dayjs'; 2 | import relativeTime from 'dayjs/plugin/relativeTime'; 3 | 4 | dayjs.extend(relativeTime); 5 | 6 | export const getEpochMsDisplayText = (date: number) => dayjs(date).fromNow(); 7 | -------------------------------------------------------------------------------- /examples/settings-view/bring-your-own-backend/frontend/jest.config.ts: -------------------------------------------------------------------------------- 1 | import type {Config} from '@jest/types'; 2 | 3 | const config: Config.InitialOptions = { 4 | preset: 'ts-jest', 5 | roots: ['./src'], 6 | }; 7 | 8 | export default config; 9 | -------------------------------------------------------------------------------- /examples/install-webhooks/backend/dotnet/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*" 9 | } 10 | -------------------------------------------------------------------------------- /examples/crm-full-stack/stripe-app/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export interface Note { 2 | id: number; 3 | agentId: string; 4 | customerId: string; 5 | message: string; 6 | createdAt: Date; 7 | } 8 | 9 | export interface APIResponse { 10 | data: any; 11 | error: boolean; 12 | } -------------------------------------------------------------------------------- /examples/install-webhooks/backend/dotnet/Model/UserAccount.cs: -------------------------------------------------------------------------------- 1 | namespace Model; 2 | 3 | public class UserAccount 4 | { 5 | public string Id { get; set; } 6 | public string Name { get; set; } 7 | public DateTime Date { get; set; } = DateTime.Now; 8 | 9 | } 10 | -------------------------------------------------------------------------------- /examples/crm-full-stack/nodejs-backend/src/index.ts: -------------------------------------------------------------------------------- 1 | import * as dotenv from "dotenv"; 2 | import app from "./app"; 3 | dotenv.config(); 4 | 5 | const port = process.env.PORT || 3000; 6 | 7 | app.listen(port, () => { 8 | console.log(`server started at http://localhost:${port}`) 9 | }) 10 | -------------------------------------------------------------------------------- /examples/install-webhooks/backend/java/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /examples/climate/jest.config.ts: -------------------------------------------------------------------------------- 1 | import type {Config} from '@jest/types'; 2 | 3 | const config: Config.InitialOptions = { 4 | preset: 'ts-jest', 5 | roots: ['./src'], 6 | moduleNameMapper: { 7 | '\\.svg': '/src/mocks/fileMock.tsx', 8 | }, 9 | }; 10 | 11 | export default config; 12 | -------------------------------------------------------------------------------- /examples/github-oauth/packages/backend/.env.example: -------------------------------------------------------------------------------- 1 | STRIPE_PUBLIC_KEY= 2 | STRIPE_SECRET_KEY= 3 | STRIPE_APP_SECRET= 4 | GITHUB_AUTH_URI=https://github.com/login/oauth 5 | GITHUB_API_URI=https://api.github.com 6 | GITHUB_CLIENT_ID= 7 | GITHUB_CLIENT_SECRET= 8 | REDIRECT_URI=https://localhost:8080/auth/callback/logged-in -------------------------------------------------------------------------------- /examples/crm-full-stack/nodejs-backend/src/lib/prisma.ts: -------------------------------------------------------------------------------- 1 | import { PrismaClient } from ".prisma/client"; 2 | 3 | declare global { 4 | var prisma: PrismaClient | undefined; 5 | } 6 | 7 | export const prisma = global.prisma || new PrismaClient(); 8 | 9 | if (process.env.NODE_ENV !== 'production') { global.prisma = prisma } -------------------------------------------------------------------------------- /examples/super-todo/src/assets/super-todo-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /examples/install-webhooks/backend/python/requirements.txt: -------------------------------------------------------------------------------- 1 | Jinja2==3.1.2 2 | MarkupSafe==2.1.1 3 | Werkzeug==2.1.2 4 | click==8.1.3 5 | flask==2.1.2 6 | itsdangerous==2.1.2 7 | python-dotenv==0.20.0 8 | certifi==2021.10.8 9 | charset-normalizer==2.0.12 10 | idna==3.3 11 | requests==2.27.1 12 | stripe==3.0.0 13 | urllib3==1.26.9 -------------------------------------------------------------------------------- /examples/install-webhooks/backend/php/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "require": { 3 | "slim/slim": "^4.10", 4 | "slim/psr7": "^1.5", 5 | "vlucas/phpdotenv": "^5.4", 6 | "stripe/stripe-php": "^8.0" 7 | }, 8 | "scripts": { 9 | "start": "php -S localhost:8080 index.php" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /examples/secret-store/backend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.natw.secret_store_example", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "app.js", 6 | "scripts": {}, 7 | "author": "Stripe", 8 | "license": "ISC", 9 | "dependencies": { 10 | "express": "^4.17.3", 11 | "stripe": "^9.4" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /examples/ship-io/jest.config.ts: -------------------------------------------------------------------------------- 1 | import type {Config} from '@jest/types'; 2 | 3 | const config: Config.InitialOptions = { 4 | preset: 'ts-jest', 5 | roots: ['./src'], 6 | transform: { 7 | ".+\\.(svg|css|styl|less|sass|scss|png|jpg|ttf|woff|woff2)$": "jest-transform-stub" 8 | }, 9 | }; 10 | 11 | export default config; 12 | -------------------------------------------------------------------------------- /examples/show-toast/jest.config.ts: -------------------------------------------------------------------------------- 1 | import type {Config} from '@jest/types'; 2 | 3 | const config: Config.InitialOptions = { 4 | preset: 'ts-jest', 5 | roots: ['./src'], 6 | transform: { 7 | ".+\\.(svg|css|styl|less|sass|scss|png|jpg|ttf|woff|woff2)$": "jest-transform-stub" 8 | }, 9 | }; 10 | 11 | export default config; 12 | -------------------------------------------------------------------------------- /examples/show-toast/src/events.ts: -------------------------------------------------------------------------------- 1 | export function withValueFromEvent< 2 | Element extends { value: string }, 3 | Event extends { target: Element }, 4 | ReturnValue 5 | >( 6 | callback: (value: Event["target"]["value"]) => ReturnValue 7 | ): (event: Event) => ReturnValue { 8 | return (event) => callback(event.target.value); 9 | } 10 | -------------------------------------------------------------------------------- /examples/crm-full-stack/stripe-app/jest.config.ts: -------------------------------------------------------------------------------- 1 | import type {Config} from '@jest/types'; 2 | 3 | const config: Config.InitialOptions = { 4 | preset: 'ts-jest', 5 | roots: ['./src'], 6 | transform: { 7 | ".+\\.(svg|css|styl|less|sass|scss|png|jpg|ttf|woff|woff2)$": "jest-transform-stub" 8 | }, 9 | }; 10 | 11 | export default config; 12 | -------------------------------------------------------------------------------- /examples/dropbox-oauth-pkce/src/util/types.ts: -------------------------------------------------------------------------------- 1 | export interface TokenData { 2 | access_token: string; 3 | account_id: string; 4 | expires_in: number; 5 | scope: string; 6 | token_type: string; 7 | uid: string; 8 | } 9 | 10 | export interface AccountData { 11 | email: string; 12 | name: { 13 | display_name: string; 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /examples/super-todo/src/assets/super-todo-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /examples/crm-full-stack/nodejs-backend/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:10-alpine 2 | 3 | RUN mkdir -p /home/node/app/node_modules && chown -R node:node /home/node/app 4 | 5 | WORKDIR /home/node/app 6 | 7 | COPY package*.json ./ 8 | 9 | USER node 10 | 11 | RUN npm install 12 | 13 | COPY --chown=node:node . . 14 | 15 | EXPOSE 8080 16 | 17 | CMD [ "node", "app.js" ] -------------------------------------------------------------------------------- /examples/super-todo/src/components/index.ts: -------------------------------------------------------------------------------- 1 | export { default as CreateListBasics } from "./CreateListBasics"; 2 | export { default as CreateListMeta } from "./CreateListMeta"; 3 | export { default as ListTabPanel } from "./ListTabPanel"; 4 | export { default as SuperTodoView } from "./SuperTodoView"; 5 | export { default as TodosComponent } from "./TodosComponent"; 6 | -------------------------------------------------------------------------------- /examples/messaging/src/clients/stripe.ts: -------------------------------------------------------------------------------- 1 | import Stripe from 'stripe'; 2 | import {createHttpClient, STRIPE_API_KEY} from '@stripe/ui-extension-sdk/http_client'; 3 | 4 | const stripeClient = new Stripe( 5 | STRIPE_API_KEY, 6 | { 7 | httpClient: createHttpClient(), 8 | apiVersion: '2020-08-27', 9 | } 10 | ); 11 | 12 | export default stripeClient; 13 | -------------------------------------------------------------------------------- /examples/ship-io/src/common/types.ts: -------------------------------------------------------------------------------- 1 | export interface LoginContext { 2 | isLoggedIn: boolean; 3 | setIsLoggedIn: (state: boolean) => void; 4 | } 5 | 6 | export interface ProviderProps { 7 | children: React.ReactNode; 8 | } 9 | 10 | export interface Product { 11 | name: string; 12 | image: string; 13 | selected: boolean; 14 | quantity: number; 15 | } 16 | -------------------------------------------------------------------------------- /examples/basic-auth/backend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2017", 4 | "module": "commonjs", 5 | "outDir": "./dist", 6 | "rootDir": "./src", 7 | "strict": true, 8 | "moduleResolution": "node", 9 | "esModuleInterop": true, 10 | "sourceMap": true, 11 | "forceConsistentCasingInFileNames": true 12 | }, 13 | "include": ["src"] 14 | } 15 | -------------------------------------------------------------------------------- /examples/show-toast/src/components/Form.tsx: -------------------------------------------------------------------------------- 1 | import { Box } from "@stripe/ui-extension-sdk/ui"; 2 | import * as React from "react"; 3 | 4 | export const Form = ({ children }: React.PropsWithChildren) => { 5 | return ( 6 | <> 7 | {React.Children.map(children, (child) => ( 8 | {child} 9 | ))} 10 | 11 | ); 12 | }; 13 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/documentation.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Documentation 3 | about: Gaps and problems related to documentation 4 | title: '' 5 | labels: docs, needs-triage 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## Your Problem 11 | What are you trying to do? What information can't you find? Include: 12 | - Related components 13 | - Related APIs 14 | 15 | ## Existing Documentation URLs (If applicable) 16 | -------------------------------------------------------------------------------- /examples/settings-view/bring-your-own-backend/backend/node/README.md: -------------------------------------------------------------------------------- 1 | # Name of sample 2 | An Express server implementation 3 | 4 | ## Requirements 5 | - Node v14+ 6 | - [Configured .env file](../../README.md) 7 | 8 | ## How to run 9 | 1. Install dependencies 10 | ```bash 11 | yarn 12 | ``` 13 | 2. Run the application 14 | ```bash 15 | yarn start 16 | ``` 17 | Server is running on `localhost:8080` 18 | -------------------------------------------------------------------------------- /examples/climate/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /.build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /examples/focus-view/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /.build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /examples/messaging/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /.build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /examples/routing/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /.build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /examples/send-mail/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /.build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /examples/ship-io/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /.build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /examples/super-todo/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /.build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /examples/ui-testing/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /.build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Summary 4 | 5 | 6 | ## Motivation 7 | 8 | -------------------------------------------------------------------------------- /examples/messaging/README.md: -------------------------------------------------------------------------------- 1 | # Messaging UI Demo 2 | 3 | This is an example of a Stripe dashboard app that displays recent messages from a customer on the customer page. It can be extended to display messages from any source with an API, including email and chat services. 4 | 5 | API code needs to be added that fetches message data from a 3rd party source. See [the documentation](https://stripe.com/docs/stripe-apps) for more. 6 | -------------------------------------------------------------------------------- /examples/github-oauth/packages/backend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "esModuleInterop": true, 5 | "target": "es6", 6 | "noImplicitAny": true, 7 | "moduleResolution": "node", 8 | "sourceMap": true, 9 | "outDir": "dist", 10 | "baseUrl": ".", 11 | "paths": { 12 | "*": ["node_modules/*"] 13 | } 14 | }, 15 | "include": ["src/**/*"] 16 | } 17 | -------------------------------------------------------------------------------- /examples/accessing-contextual-data/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /.build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /examples/install-webhooks/frontend/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /.build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /examples/dropbox-oauth-pkce/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /.build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | config.ts -------------------------------------------------------------------------------- /examples/linking-different-stripe-object/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /.build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /examples/install-webhooks/backend/node/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /.build 11 | 12 | # misc 13 | .DS_Store 14 | .env 15 | .env.local 16 | .env.development.local 17 | .env.test.local 18 | .env.production.local 19 | 20 | npm-debug.log* 21 | yarn-debug.log* 22 | yarn-error.log* 23 | -------------------------------------------------------------------------------- /examples/settings-view/bring-your-own-backend/backend/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # node 4 | node_modules 5 | 6 | # testing 7 | coverage 8 | 9 | # production 10 | dist 11 | 12 | # misc 13 | .DS_Store 14 | .env 15 | .env.local 16 | .env.development.local 17 | .env.test.local 18 | .env.production.local 19 | 20 | npm-debug.log* 21 | yarn-debug.log* 22 | yarn-error.log* 23 | -------------------------------------------------------------------------------- /examples/install-webhooks/backend/java/settings.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * This file was generated by the Gradle 'init' task. 3 | * 4 | * The settings file is used to specify which projects to include in your build. 5 | * 6 | * Detailed information about configuring a multi-project build in Gradle can be found 7 | * in the user manual at https://docs.gradle.org/7.4.2/userguide/multi_project_builds.html 8 | */ 9 | 10 | rootProject.name = 'java' 11 | include('app') 12 | -------------------------------------------------------------------------------- /examples/settings-view/bring-your-own-backend/frontend/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /.build 11 | dist 12 | 13 | # misc 14 | .DS_Store 15 | .env.local 16 | .env.development.local 17 | .env.test.local 18 | .env.production.local 19 | 20 | npm-debug.log* 21 | yarn-debug.log* 22 | yarn-error.log* 23 | -------------------------------------------------------------------------------- /examples/super-todo/.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Unix-style newlines with a newline ending every file 7 | [*] 8 | end_of_line = lf 9 | insert_final_newline = true 10 | indent_style = space 11 | indent_size = 2 12 | charset = utf-8 13 | trim_trailing_whitespace = true 14 | 15 | # Markdown 16 | [*.md] 17 | indent_size = 4 18 | trim_trailing_whitespace = false 19 | -------------------------------------------------------------------------------- /examples/super-todo/src/components/SuperTodoView.tsx: -------------------------------------------------------------------------------- 1 | import { ContextView } from "@stripe/ui-extension-sdk/ui"; 2 | const SuperTodoIcon = require("../assets/super-todo-icon.svg"); 3 | 4 | const SuperTodoView = ({ title = "SuperTodo", ...contextViewProps }) => ( 5 | 11 | ); 12 | 13 | export default SuperTodoView; 14 | -------------------------------------------------------------------------------- /examples/basic-auth/frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.example.oauth2-test", 3 | "version": "0.0.1", 4 | "description": "OAuth2 Test", 5 | "private": true, 6 | "license": "~~proprietary~~", 7 | "dependencies": { 8 | "@stripe/ui-extension-sdk": "^8.0.0", 9 | "react": "^17.0.2", 10 | "stripe": "^8.202.0" 11 | }, 12 | "engines": { 13 | "node": ">=14" 14 | }, 15 | "devDependencies": { 16 | "typescript": "^4.5.5" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examples/crm-full-stack/nodejs-backend/prisma/schema.prisma: -------------------------------------------------------------------------------- 1 | // This is your Prisma schema file, 2 | // learn more about it in the docs: https://pris.ly/d/prisma-schema 3 | 4 | generator client { 5 | provider = "prisma-client-js" 6 | } 7 | 8 | datasource db { 9 | provider = "postgresql" 10 | url = env("DATABASE_URL") 11 | } 12 | 13 | model Note { 14 | id Int @id @default(autoincrement()) 15 | agentId String 16 | customerId String 17 | message String 18 | } -------------------------------------------------------------------------------- /examples/focus-view/README.md: -------------------------------------------------------------------------------- 1 | # Focus View Example 2 | 3 | ![Screenshot](./screenshot-1.png) 4 | ![Screenshot](./screenshot-2.png) 5 | 6 | ## Summarry 7 | 8 | This is an example code that demonstrates opening and closing a FocusView. 9 | 10 | ## Running 11 | 12 | 1. From the `stripe-apps/examples/focus-view` directory, run `yarn` to install dependencies. 13 | 2. Once you install the `stripe apps` CLI plugin, run the start command: 14 | 15 | ``` 16 | stripe apps start 17 | ``` 18 | -------------------------------------------------------------------------------- /examples/basic-auth/frontend/stripe-app.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "com.example.oauth2-test", 3 | "version": "0.0.1", 4 | "name": "OAuth2 Test", 5 | "icon": "", 6 | "permissions": [], 7 | "ui_extension": { 8 | "views": [ 9 | { 10 | "viewport": "stripe.dashboard.home.overview", 11 | "component": "App" 12 | } 13 | ], 14 | "actions": [], 15 | "content_security_policy": { 16 | "connect-src": null, 17 | "purpose": "" 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /examples/install-webhooks/backend/ruby/README.md: -------------------------------------------------------------------------------- 1 | # Install-webhooks Example (Ruby server) 2 | A Sinatra implementation. 3 | 4 | ## Requirements 5 | - Ruby v2.4.5+ 6 | - [Configured .env file](https://github.com/stripe/stripe-apps/blob/master/examples/install-webhooks/README.md#backend) 7 | 8 | ## How to run 9 | 1. Install dependencies 10 | ```bash 11 | bundle install 12 | ``` 13 | 14 | 2. Run the application 15 | ```bash 16 | ruby server.rb 17 | ``` 18 | 19 | Server is running on `localhost:8080` -------------------------------------------------------------------------------- /examples/install-webhooks/backend/node/README.md: -------------------------------------------------------------------------------- 1 | # Install-webhooks Example (Node Server) 2 | An Express server implementation 3 | 4 | ## Requirements 5 | - Node v10+ 6 | - [Configured .env file](https://github.com/stripe/stripe-apps/blob/master/examples/install-webhooks/README.md#backend) 7 | 8 | ## How to run 9 | 10 | 1. Install dependencies 11 | ```bash 12 | npm install 13 | ``` 14 | 15 | 2. Run the application 16 | ```bash 17 | npm start 18 | ``` 19 | 20 | Server is running on `localhost:8080` -------------------------------------------------------------------------------- /examples/install-webhooks/backend/node/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "install-webhooks-example-backend", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "~~proprietary~~", 6 | "private": true, 7 | "scripts": { 8 | "start": "node ." 9 | }, 10 | "dependencies": { 11 | "cors": "^2.8.5", 12 | "dotenv": "^16.0.1", 13 | "express": "^4.17.3", 14 | "stripe": "^8.214.0" 15 | }, 16 | "devDependencies": { 17 | "@types/stripe": "^8.0.417" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /examples/github-oauth/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | **/node_modules 5 | 6 | # testing 7 | **/coverage 8 | 9 | # production 10 | **/.build 11 | 12 | # misc 13 | .DS_Store 14 | **/.env 15 | **/.env.local 16 | **/.env.development.local 17 | **/.env.test.local 18 | **/.env.production.local 19 | **/*.key 20 | **/*.cert 21 | **/*.pem 22 | 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | .vscode -------------------------------------------------------------------------------- /examples/github-oauth/packages/frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frontend", 3 | "version": "0.0.1", 4 | "description": "Allows users to create invoices from GitHub issues and pull requests.", 5 | "private": true, 6 | "license": "~~proprietary~~", 7 | "scripts": { 8 | "start": "stripe apps start", 9 | "upload": "stripe apps upload" 10 | }, 11 | "dependencies": { 12 | "@stripe/ui-extension-sdk": "^8.0.0", 13 | "react": "^17.0.2", 14 | "stripe": "^8.200.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /examples/routing/stripe-app.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "com.example.router", 3 | "version": "0.0.1", 4 | "name": "Router Example", 5 | "icon": "", 6 | "permissions": [], 7 | "ui_extension": { 8 | "views": [ 9 | { 10 | "viewport": "stripe.dashboard.drawer.default", 11 | "component": "App" 12 | } 13 | ], 14 | "actions": [], 15 | "content_security_policy": { 16 | "connect-src": null, 17 | "image-src": null, 18 | "purpose": "" 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /examples/github-oauth/packages/backend/src/config.ts: -------------------------------------------------------------------------------- 1 | import 'dotenv/config'; 2 | 3 | export const stripeSecretKey = process.env.STRIPE_SECRET_KEY; 4 | export const stripeAppSecret = process.env.STRIPE_APP_SECRET; 5 | export const githubAuthURI = process.env.GITHUB_AUTH_URI; 6 | export const githubAPIURI = process.env.GITHUB_API_URI; 7 | export const client_id = process.env.GITHUB_CLIENT_ID; 8 | export const client_secret = process.env.GITHUB_CLIENT_SECRET; 9 | export const redirect_uri = process.env.REDIRECT_URI; 10 | -------------------------------------------------------------------------------- /schema/jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */ 2 | module.exports = { 3 | roots: ['test'], 4 | moduleFileExtensions: ['js', 'ts'], 5 | transform: { 6 | '\\.[jt]sx?$': [ 7 | '@swc/jest', 8 | { 9 | module: { 10 | type: 'commonjs', 11 | }, 12 | // Inline snapshots require source maps: 13 | // https://github.com/facebook/jest/issues/6744 14 | sourceMaps: 'inline', 15 | }, 16 | ], 17 | }, 18 | }; 19 | -------------------------------------------------------------------------------- /examples/github-oauth/packages/frontend/stripe-app.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "com.example.github-oauth-example", 3 | "version": "0.0.1", 4 | "name": "GitHub OAuth Example", 5 | "icon": "", 6 | "permissions": [], 7 | "ui_extension": { 8 | "views": [ 9 | { 10 | "viewport": "stripe.dashboard.home.overview", 11 | "component": "App" 12 | } 13 | ], 14 | "actions": [], 15 | "content_security_policy": { 16 | "connect-src": null, 17 | "purpose": "" 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /examples/ui-testing/stripe-app.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "com.example.ui-testing", 3 | "version": "0.0.1", 4 | "name": "UI Testing Example", 5 | "icon": "", 6 | "permissions": [], 7 | "ui_extension": { 8 | "views": [ 9 | { 10 | "viewport": "stripe.dashboard.customer.detail", 11 | "component": "App" 12 | } 13 | ], 14 | "actions": [], 15 | "content_security_policy": { 16 | "connect-src": null, 17 | "image-src": null, 18 | "purpose": "" 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /examples/focus-view/stripe-app.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "com.example.focus-view-example", 3 | "version": "0.0.1", 4 | "name": "FocusView Example", 5 | "icon": "", 6 | "permissions": [], 7 | "ui_extension": { 8 | "views": [ 9 | { 10 | "viewport": "stripe.dashboard.drawer.default", 11 | "component": "App" 12 | } 13 | ], 14 | "actions": [], 15 | "content_security_policy": { 16 | "connect-src": null, 17 | "image-src": null, 18 | "purpose": "" 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /examples/settings-view/bring-your-own-backend/backend/node/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "setting-view-example", 3 | "version": "1.0.0", 4 | "main": "app.js", 5 | "license": "UNLICENSED", 6 | "engines": { 7 | "node": ">=14" 8 | }, 9 | "scripts": { 10 | "start": "node ." 11 | }, 12 | "dependencies": { 13 | "cors": "^2.8.5", 14 | "dotenv": "^16.0.0", 15 | "express": "^4.17.3", 16 | "stripe": "^8.216.0" 17 | }, 18 | "devDependencies": { 19 | "@types/stripe": "^8.0.417" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /.github/workflows/test_schema.yml: -------------------------------------------------------------------------------- 1 | name: Test JSON schema 2 | on: 3 | push: 4 | pull_request_target: 5 | types: [labeled] 6 | jobs: 7 | test-schema: 8 | runs-on: ubuntu-latest 9 | if: contains(github.event.pull_request.labels.*.name, 'safe-to-test') 10 | steps: 11 | - uses: actions/checkout@v3 12 | - name: Test schema 13 | run: | 14 | yarn install --frozen-lockfile 15 | yarn types 16 | yarn lint 17 | yarn test 18 | working-directory: ./schema 19 | -------------------------------------------------------------------------------- /examples/climate/stripe-app.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "com.example.climate", 3 | "version": "0.0.1", 4 | "name": "Stripe Climate Example App", 5 | "icon": "", 6 | "permissions": [], 7 | "ui_extension": { 8 | "views": [ 9 | { 10 | "viewport": "stripe.dashboard.drawer.default", 11 | "component": "ClimateSampleApp" 12 | } 13 | ], 14 | "actions": [], 15 | "content_security_policy": { 16 | "connect-src": null, 17 | "image-src": null, 18 | "purpose": "" 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /examples/super-todo/src/assets/stripe-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /examples/ship-io/stripe-app.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "com.example.ship-io", 3 | "version": "0.0.1", 4 | "name": "Ship.IO", 5 | "icon": "", 6 | "permissions": [], 7 | "ui_extension": { 8 | "views": [ 9 | { 10 | "viewport": "stripe.dashboard.drawer.default", 11 | "component": "App" 12 | } 13 | ], 14 | "actions": [], 15 | "content_security_policy": { 16 | "connect-src": null, 17 | "image-src": null, 18 | "purpose": "" 19 | } 20 | }, 21 | "post_install_action": null 22 | } -------------------------------------------------------------------------------- /examples/install-webhooks/backend/php/README.md: -------------------------------------------------------------------------------- 1 | # Install-webhooks Example (PHP server) 2 | 3 | ## Requirements 4 | - PHP >= 8.1.5 5 | - Composer 6 | - [Slim](https://www.slimframework.com/) 7 | - [Configured .env file](https://github.com/stripe/stripe-apps/blob/master/examples/install-webhooks/README.md#backend) 8 | 9 | ## How to run 10 | 1. Install dependencies 11 | 12 | ```bash 13 | composer install 14 | ``` 15 | 2. Run the application 16 | 17 | ```bash 18 | composer start 19 | ``` 20 | The application is running on `localhost:8080`. 21 | -------------------------------------------------------------------------------- /examples/install-webhooks/frontend/stripe-app.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "com.example.install-webhooks", 3 | "version": "0.0.1", 4 | "name": "Webhooks Example App", 5 | "icon": "", 6 | "permissions": [], 7 | "ui_extension": { 8 | "views": [ 9 | { 10 | "viewport": "stripe.dashboard.drawer.default", 11 | "component": "App" 12 | } 13 | ], 14 | "actions": [], 15 | "content_security_policy": { 16 | "connect-src": null, 17 | "image-src": null, 18 | "purpose": "" 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ### Reporting a vulnerability 4 | 5 | Please do not open GitHub issues or pull requests for security vulnerabilities - this makes the problem immediately visible to everyone, including malicious actors. 6 | 7 | Security issues in this open-source project can be safely reported to Stripe's [Vulnerability Disclosure and Reward Program](https://stripe.com/docs/security/stripe#disclosure-and-reward-program). 8 | Stripe's security team will triage your report and respond according to its impact on Stripe users and systems. -------------------------------------------------------------------------------- /examples/install-webhooks/backend/dotnet/README.md: -------------------------------------------------------------------------------- 1 | # Install-webhooks Example (.NET Server) 2 | 3 | ## Requirements 4 | - .NET Core v6.x 5 | - [Configured .env file](https://github.com/stripe/stripe-apps/blob/master/examples/install-webhooks/README.md#backend) 6 | 7 | ## How to run 8 | 1. Make sure you have `.NET SDK` installed on your machine 9 | 10 | 2. From the `dotnet` directory run: 11 | 12 | ```bash 13 | dotnet build 14 | ``` 15 | 16 | 3. Run the application 17 | 18 | ```bash 19 | dotnet run 20 | ``` 21 | 22 | Server is running on `localhost:8080` -------------------------------------------------------------------------------- /examples/show-toast/stripe-app.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "com.example.show-toast", 3 | "version": "0.1.0", 4 | "name": "Show Toast", 5 | "icon": "./app_icon.png", 6 | "permissions": [], 7 | "ui_extension": { 8 | "views": [ 9 | { 10 | "viewport": "stripe.dashboard.drawer.default", 11 | "component": "App" 12 | } 13 | ], 14 | "actions": [], 15 | "content_security_policy": { 16 | "connect-src": null, 17 | "image-src": null, 18 | "purpose": "" 19 | } 20 | }, 21 | "post_install_action": null 22 | } -------------------------------------------------------------------------------- /schema/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "extends": [ 4 | "plugin:@typescript-eslint/eslint-recommended", 5 | "plugin:@typescript-eslint/recommended", 6 | "prettier" 7 | ], 8 | "parser": "@typescript-eslint/parser", 9 | "plugins": ["jest", "@typescript-eslint", "prettier"], 10 | "env": { 11 | "jest": true 12 | }, 13 | "rules": { 14 | "@typescript-eslint/no-shadow": ["error"], 15 | "@typescript-eslint/no-use-before-define": ["error"], 16 | "no-shadow": "off", 17 | "no-use-before-define": "off" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /examples/send-mail/api/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "api", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "Hidetaka Okamoto", 11 | "license": "ISC", 12 | "dependencies": { 13 | "@sendgrid/mail": "^7.6.0", 14 | "@types/express": "^4.17.13", 15 | "@types/node": "^14.18.1", 16 | "dotenv": "^10.0.0", 17 | "ts-node": "^10.4.0", 18 | "typescript": "^4.6.0-dev.20211218" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /examples/install-webhooks/backend/dotnet/dotnet.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /examples/super-todo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.example.super-todo", 3 | "version": "0.0.1", 4 | "description": "Super Todo", 5 | "private": true, 6 | "license": "~~proprietary~~", 7 | "scripts": { 8 | "test": "jest" 9 | }, 10 | "dependencies": { 11 | "@stripe/ui-extension-sdk": "^7.1.0", 12 | "react": "^17.0.2", 13 | "stripe": "^8.202.0" 14 | }, 15 | "engines": { 16 | "node": ">=14" 17 | }, 18 | "devDependencies": { 19 | "typescript": "^4.5.5" 20 | }, 21 | "resolutions": { 22 | "@types/react": "^17.0.2" 23 | } 24 | } -------------------------------------------------------------------------------- /examples/install-webhooks/backend/java/README.md: -------------------------------------------------------------------------------- 1 | # Install-webhooks Example (Java Server) 2 | 3 | ## Requirements 4 | - Gradle 5 | - Java v18.x 6 | - [Configured .env file](https://github.com/stripe/stripe-apps/blob/master/examples/install-webhooks/README.md#backend) 7 | 8 | ## How to run 9 | 1. Make sure you have `Java` and `Gradle` installed on your machine 10 | 11 | 2. From the `Java` directory run: 12 | 13 | ```bash 14 | gradle install 15 | ``` 16 | 17 | 3. Run the application 18 | 19 | ```bash 20 | ./gradlew run 21 | ``` 22 | 23 | Server is running on `localhost:8080` -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | Welcome, and thank you for your interest in contributing to Stripe Apps! 3 | 4 | ## Submitting changes 5 | [Create a new fork of stripe-apps](https://github.com/stripe/stripe-apps/fork) to begin contributing. Develop your changes on a branch in your new fork and then [open a new pull request](https://github.com/stripe/stripe-apps/compare). A maintainer will review your pull request and merge it, or request changes if necessary. 6 | 7 | Note: a reviewer must add the `safe-for-testing` label to your pull request before GitHub actions will run and test your changes. 8 | -------------------------------------------------------------------------------- /examples/climate/src/views/ClimateSampleApp.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | ContextView, 3 | } from '@stripe/ui-extension-sdk/ui'; 4 | import type { ExtensionContextValue } from '@stripe/ui-extension-sdk/context'; 5 | import ClimateLinkComponent from '../components/ClimateLinkComponent'; 6 | 7 | const ClimateSampleApp = ({userContext, environment}: ExtensionContextValue) => { 8 | return ( 9 | 10 | 11 | 12 | ); 13 | }; 14 | 15 | export default ClimateSampleApp; 16 | -------------------------------------------------------------------------------- /examples/climate/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | 4 | "compilerOptions": { 5 | "lib": ["dom", "dom.iterable", "esnext"], 6 | "module": "esnext", 7 | "allowJs": true, 8 | "allowSyntheticDefaultImports": true, 9 | "jsx": "react-jsx", 10 | "forceConsistentCasingInFileNames": true, 11 | "isolatedModules": true, 12 | "moduleResolution": "node", 13 | "noEmit": true, 14 | "noFallthroughCasesInSwitch": true, 15 | "skipLibCheck": true, 16 | "strict": true 17 | }, 18 | "exclude": [ 19 | "node_modules", 20 | ".build" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /examples/focus-view/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | 4 | "compilerOptions": { 5 | "lib": ["dom", "dom.iterable", "esnext"], 6 | "module": "esnext", 7 | "allowJs": true, 8 | "allowSyntheticDefaultImports": true, 9 | "jsx": "react-jsx", 10 | "forceConsistentCasingInFileNames": true, 11 | "isolatedModules": true, 12 | "moduleResolution": "node", 13 | "noEmit": true, 14 | "noFallthroughCasesInSwitch": true, 15 | "skipLibCheck": true, 16 | "strict": true 17 | }, 18 | "exclude": [ 19 | "node_modules", 20 | ".build" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /examples/routing/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | 4 | "compilerOptions": { 5 | "lib": ["dom", "dom.iterable", "esnext"], 6 | "module": "esnext", 7 | "allowJs": true, 8 | "allowSyntheticDefaultImports": true, 9 | "jsx": "react-jsx", 10 | "forceConsistentCasingInFileNames": true, 11 | "isolatedModules": true, 12 | "moduleResolution": "node", 13 | "noEmit": true, 14 | "noFallthroughCasesInSwitch": true, 15 | "skipLibCheck": true, 16 | "strict": true 17 | }, 18 | "exclude": [ 19 | "node_modules", 20 | ".build" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /examples/send-mail/stripe-app.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "com.example.sendmail", 3 | "version": "0.0.1", 4 | "name": "Easy Mail Sender", 5 | "icon": "", 6 | "permissions": [ 7 | { 8 | "permission": "user_email_read", 9 | "purpose": "Allows the app to access the dashboard user email." 10 | } 11 | ], 12 | "ui_extension": { 13 | "views": [ 14 | { 15 | "viewport": "stripe.dashboard.customer.detail", 16 | "component": "App" 17 | } 18 | ], 19 | "actions": [], 20 | "content_security_policy": { 21 | "connect-src": [], 22 | "purpose": "" 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /examples/send-mail/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | 4 | "compilerOptions": { 5 | "lib": ["dom", "dom.iterable", "esnext"], 6 | "module": "esnext", 7 | "allowJs": true, 8 | "allowSyntheticDefaultImports": true, 9 | "jsx": "react-jsx", 10 | "forceConsistentCasingInFileNames": true, 11 | "isolatedModules": true, 12 | "moduleResolution": "node", 13 | "noEmit": true, 14 | "noFallthroughCasesInSwitch": true, 15 | "skipLibCheck": true, 16 | "strict": true 17 | }, 18 | "exclude": [ 19 | "node_modules", 20 | ".build" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /examples/ship-io/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | 4 | "compilerOptions": { 5 | "lib": ["dom", "dom.iterable", "esnext"], 6 | "module": "esnext", 7 | "allowJs": true, 8 | "allowSyntheticDefaultImports": true, 9 | "jsx": "react-jsx", 10 | "forceConsistentCasingInFileNames": true, 11 | "isolatedModules": true, 12 | "moduleResolution": "node", 13 | "noEmit": true, 14 | "noFallthroughCasesInSwitch": true, 15 | "skipLibCheck": true, 16 | "strict": true 17 | }, 18 | "exclude": [ 19 | "node_modules", 20 | ".build" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /examples/show-toast/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | 4 | "compilerOptions": { 5 | "lib": ["dom", "dom.iterable", "esnext"], 6 | "module": "esnext", 7 | "allowJs": true, 8 | "allowSyntheticDefaultImports": true, 9 | "jsx": "react-jsx", 10 | "forceConsistentCasingInFileNames": true, 11 | "isolatedModules": true, 12 | "moduleResolution": "node", 13 | "noEmit": true, 14 | "noFallthroughCasesInSwitch": true, 15 | "skipLibCheck": true, 16 | "strict": true 17 | }, 18 | "exclude": [ 19 | "node_modules", 20 | ".build" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /examples/super-todo/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | 4 | "compilerOptions": { 5 | "lib": ["dom", "dom.iterable", "esnext"], 6 | "module": "esnext", 7 | "allowJs": true, 8 | "allowSyntheticDefaultImports": true, 9 | "jsx": "react-jsx", 10 | "forceConsistentCasingInFileNames": true, 11 | "isolatedModules": true, 12 | "moduleResolution": "node", 13 | "noEmit": true, 14 | "noFallthroughCasesInSwitch": true, 15 | "skipLibCheck": true, 16 | "strict": true 17 | }, 18 | "exclude": [ 19 | "node_modules", 20 | ".build" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /examples/ui-testing/README.md: -------------------------------------------------------------------------------- 1 | # UI Testing Example 2 | This is an example code that demonstrates testing a single view with very basic form. 3 | 4 | ## Features Demonstrated 5 | - Snapshot tests 6 | - Remote-UI testing limitations 7 | 8 | ## Running 9 | 1. From the `stripe-apps/examples/ui-testing` directory, run `yarn` to install dependencies 10 | 2. Once you have the `stripe apps` CLI fork available locally, run the start command: 11 | ``` 12 | stripe apps start 13 | ``` 14 | 15 | ## Testing 16 | From the `stripe-apps/examples/ui-testing` directory, run: 17 | 18 | ``` 19 | yarn test 20 | ``` 21 | 22 | To run tests on this example. -------------------------------------------------------------------------------- /examples/ui-testing/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | 4 | "compilerOptions": { 5 | "lib": ["dom", "dom.iterable", "esnext"], 6 | "module": "esnext", 7 | "allowJs": true, 8 | "allowSyntheticDefaultImports": true, 9 | "jsx": "react-jsx", 10 | "forceConsistentCasingInFileNames": true, 11 | "isolatedModules": true, 12 | "moduleResolution": "node", 13 | "noEmit": true, 14 | "noFallthroughCasesInSwitch": true, 15 | "skipLibCheck": true, 16 | "strict": true 17 | }, 18 | "exclude": [ 19 | "node_modules", 20 | ".build" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /examples/basic-auth/frontend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | 4 | "compilerOptions": { 5 | "lib": ["dom", "dom.iterable", "esnext"], 6 | "module": "esnext", 7 | "allowJs": true, 8 | "allowSyntheticDefaultImports": true, 9 | "jsx": "react-jsx", 10 | "forceConsistentCasingInFileNames": true, 11 | "isolatedModules": true, 12 | "moduleResolution": "node", 13 | "noEmit": true, 14 | "noFallthroughCasesInSwitch": true, 15 | "skipLibCheck": true, 16 | "strict": true 17 | }, 18 | "exclude": [ 19 | "node_modules", 20 | ".build" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /examples/dropbox-oauth-pkce/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | 4 | "compilerOptions": { 5 | "lib": ["dom", "dom.iterable", "esnext"], 6 | "module": "esnext", 7 | "allowJs": true, 8 | "allowSyntheticDefaultImports": true, 9 | "jsx": "react-jsx", 10 | "forceConsistentCasingInFileNames": true, 11 | "isolatedModules": true, 12 | "moduleResolution": "node", 13 | "noEmit": true, 14 | "noFallthroughCasesInSwitch": true, 15 | "skipLibCheck": true, 16 | "strict": true 17 | }, 18 | "exclude": [ 19 | "node_modules", 20 | ".build" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /examples/secret-store/ui-extension/README.md: -------------------------------------------------------------------------------- 1 | # Secret Store UI Extension Demo 2 | 3 | This is an example of using the Secret Store API from a UI extension. The extension allows you to fetch, set, and delete secrets associated with the currently authenticated user. 4 | 5 | In a real application, the secret value would most likely be consumed from an OAuth callback or from an API request that fetches secret material. 6 | 7 | See the [Secret Store docs](https://stripe.com/docs/stripe-apps/store-auth-data-custom-objects) to learn more about the API, and the [API reference](https://stripe.com/docs/api/secret_management) for request and response definitions. -------------------------------------------------------------------------------- /examples/accessing-contextual-data/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | 4 | "compilerOptions": { 5 | "lib": ["dom", "dom.iterable", "esnext"], 6 | "module": "esnext", 7 | "allowJs": true, 8 | "allowSyntheticDefaultImports": true, 9 | "jsx": "react-jsx", 10 | "forceConsistentCasingInFileNames": true, 11 | "isolatedModules": true, 12 | "moduleResolution": "node", 13 | "noEmit": true, 14 | "noFallthroughCasesInSwitch": true, 15 | "skipLibCheck": true, 16 | "strict": true 17 | }, 18 | "exclude": [ 19 | "node_modules", 20 | ".build" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /examples/crm-full-stack/stripe-app/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | 4 | "compilerOptions": { 5 | "lib": ["dom", "dom.iterable", "esnext"], 6 | "module": "esnext", 7 | "allowJs": true, 8 | "allowSyntheticDefaultImports": true, 9 | "jsx": "react-jsx", 10 | "forceConsistentCasingInFileNames": true, 11 | "isolatedModules": true, 12 | "moduleResolution": "node", 13 | "noEmit": true, 14 | "noFallthroughCasesInSwitch": true, 15 | "skipLibCheck": true, 16 | "strict": true 17 | }, 18 | "exclude": [ 19 | "node_modules", 20 | ".build" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /examples/install-webhooks/frontend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | 4 | "compilerOptions": { 5 | "lib": ["dom", "dom.iterable", "esnext"], 6 | "module": "esnext", 7 | "allowJs": true, 8 | "allowSyntheticDefaultImports": true, 9 | "jsx": "react-jsx", 10 | "forceConsistentCasingInFileNames": true, 11 | "isolatedModules": true, 12 | "moduleResolution": "node", 13 | "noEmit": true, 14 | "noFallthroughCasesInSwitch": true, 15 | "skipLibCheck": true, 16 | "strict": true 17 | }, 18 | "exclude": [ 19 | "node_modules", 20 | ".build" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /examples/secret-store/ui-extension/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | 4 | "compilerOptions": { 5 | "lib": ["dom", "dom.iterable", "esnext"], 6 | "module": "esnext", 7 | "allowJs": true, 8 | "allowSyntheticDefaultImports": true, 9 | "jsx": "react-jsx", 10 | "forceConsistentCasingInFileNames": true, 11 | "isolatedModules": true, 12 | "moduleResolution": "node", 13 | "noEmit": true, 14 | "noFallthroughCasesInSwitch": true, 15 | "skipLibCheck": true, 16 | "strict": true 17 | }, 18 | "exclude": [ 19 | "node_modules", 20 | ".build" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /examples/accessing-contextual-data/README.md: -------------------------------------------------------------------------------- 1 | # Accessing Contextual Data Example 2 | 3 | ![screenshot-1](./Screenshot-1.png) 4 | This is an example code that demonstrates accessing userContext and environment variables, accessing more data via Stripe API and outputing data into app view on each dashboard page. 5 | 6 | ## Features Demonstrated 7 | 8 | - ExtensionContextValue 9 | - Stripe API 10 | 11 | ## Running 12 | 13 | 1. From the `stripe-apps/examples/accessing-contextual-data` directory, run `yarn` to install dependencies. 14 | 2. Once you install the `stripe apps` CLI plugin, run the start command: 15 | 16 | ``` 17 | stripe apps start 18 | ``` -------------------------------------------------------------------------------- /examples/github-oauth/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "arrowParens": "avoid", 3 | "bracketSameLine": false, 4 | "bracketSpacing": true, 5 | "embeddedLanguageFormatting": "auto", 6 | "htmlWhitespaceSensitivity": "css", 7 | "importOrder": ["^@stripe/(.*)$", "^[./]"], 8 | "importOrderSeparation": true, 9 | "importOrderSortSpecifiers": true, 10 | "insertPragma": false, 11 | "jsxSingleQuote": false, 12 | "printWidth": 80, 13 | "proseWrap": "preserve", 14 | "quoteProps": "as-needed", 15 | "requirePragma": false, 16 | "semi": true, 17 | "singleQuote": true, 18 | "tabWidth": 2, 19 | "trailingComma": "all", 20 | "useTabs": false 21 | } 22 | -------------------------------------------------------------------------------- /examples/github-oauth/packages/frontend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | 4 | "compilerOptions": { 5 | "lib": ["dom", "dom.iterable", "esnext"], 6 | "module": "esnext", 7 | "allowJs": true, 8 | "allowSyntheticDefaultImports": true, 9 | "jsx": "react-jsx", 10 | "forceConsistentCasingInFileNames": true, 11 | "isolatedModules": true, 12 | "moduleResolution": "node", 13 | "noEmit": true, 14 | "noFallthroughCasesInSwitch": true, 15 | "skipLibCheck": true, 16 | "strict": true 17 | }, 18 | "exclude": [ 19 | "node_modules", 20 | ".build" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /examples/linking-different-stripe-object/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | 4 | "compilerOptions": { 5 | "lib": ["dom", "dom.iterable", "esnext"], 6 | "module": "esnext", 7 | "allowJs": true, 8 | "allowSyntheticDefaultImports": true, 9 | "jsx": "react-jsx", 10 | "forceConsistentCasingInFileNames": true, 11 | "isolatedModules": true, 12 | "moduleResolution": "node", 13 | "noEmit": true, 14 | "noFallthroughCasesInSwitch": true, 15 | "skipLibCheck": true, 16 | "strict": true 17 | }, 18 | "exclude": [ 19 | "node_modules", 20 | ".build" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /examples/settings-view/bring-your-own-backend/frontend/stripe-app.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "com.example.settings-view", 3 | "version": "0.0.1", 4 | "name": "Settings View Example", 5 | "icon": "", 6 | "permissions": [], 7 | "ui_extension": { 8 | "views": [ 9 | { 10 | "viewport": "stripe.dashboard.drawer.default", 11 | "component": "App" 12 | }, 13 | { 14 | "viewport": "settings", 15 | "component": "AppSettings" 16 | } 17 | ], 18 | "actions": [], 19 | "content_security_policy": { 20 | "connect-src": null, 21 | "image-src": null, 22 | "purpose": "" 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /examples/secret-store/ui-extension/stripe-app.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "com.natw.secret_store_example", 3 | "version": "0.0.1", 4 | "name": "Secret Store Example", 5 | "icon": "", 6 | "permissions": [ 7 | { 8 | "permission": "secret_write", 9 | "purpose": "For storing secrets in Stripe" 10 | } 11 | ], 12 | "ui_extension": { 13 | "views": [ 14 | { 15 | "viewport": "stripe.dashboard.drawer.default", 16 | "component": "App" 17 | } 18 | ], 19 | "actions": [], 20 | "content_security_policy": { 21 | "connect-src": null, 22 | "image-src": null, 23 | "purpose": "" 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /examples/settings-view/bring-your-own-backend/frontend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | 4 | "compilerOptions": { 5 | "lib": ["dom", "dom.iterable", "esnext"], 6 | "module": "esnext", 7 | "allowJs": true, 8 | "allowSyntheticDefaultImports": true, 9 | "jsx": "react-jsx", 10 | "forceConsistentCasingInFileNames": true, 11 | "isolatedModules": true, 12 | "moduleResolution": "node", 13 | "noEmit": true, 14 | "noFallthroughCasesInSwitch": true, 15 | "skipLibCheck": true, 16 | "strict": true 17 | }, 18 | "exclude": [ 19 | "node_modules", 20 | ".build" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /examples/install-webhooks/backend/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # node 4 | node_modules 5 | 6 | npm-debug.log* 7 | yarn-debug.log* 8 | yarn-error.log* 9 | 10 | # testing 11 | coverage 12 | 13 | # production 14 | .build 15 | 16 | # ruby 17 | Gemfile.lock 18 | 19 | # .NET 20 | obj 21 | bin 22 | 23 | # Go 24 | go.mod* 25 | go.sum* 26 | 27 | # Python 28 | env 29 | __pycache__ 30 | 31 | # java 32 | .gradle 33 | build 34 | bin 35 | 36 | # PHP 37 | vendor 38 | 39 | # misc 40 | .DS_Store 41 | .env 42 | .env.local 43 | .env.development.local 44 | .env.test.local 45 | .env.production.local 46 | 47 | -------------------------------------------------------------------------------- /examples/messaging/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.example.messaging", 3 | "version": "0.0.1", 4 | "description": "Messaging", 5 | "private": true, 6 | "license": "~~proprietary~~", 7 | "dependencies": { 8 | "@stripe/ui-extension-sdk": "^8.0.0", 9 | "dayjs": "^1.10.7", 10 | "react": "^17.0.2", 11 | "stripe": "^8.170.0" 12 | }, 13 | "devDependencies": { 14 | "@types/jest": "^27.4.0", 15 | "jest": "^27.4.7", 16 | "ts-jest": "^27.1.3", 17 | "ts-node": "^10.4.0", 18 | "typescript": "^4.5.5" 19 | }, 20 | "engines": { 21 | "node": ">=14" 22 | }, 23 | "scripts": { 24 | "test": "jest --watchAll" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /examples/messaging/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "compilerOptions": { 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "module": "esnext", 10 | "allowJs": true, 11 | "allowSyntheticDefaultImports": true, 12 | "jsx": "react-jsx", 13 | "forceConsistentCasingInFileNames": true, 14 | "isolatedModules": true, 15 | "moduleResolution": "node", 16 | "noEmit": true, 17 | "noFallthroughCasesInSwitch": true, 18 | "skipLibCheck": true, 19 | "strict": true 20 | }, 21 | "exclude": [ 22 | "node_modules", 23 | ".build" 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /examples/github-oauth/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | browser: true, 4 | es2021: true, 5 | node: true, 6 | }, 7 | extends: [ 8 | 'eslint:recommended', 9 | 'plugin:react/recommended', 10 | 'plugin:@typescript-eslint/recommended', 11 | 'prettier', 12 | ], 13 | parser: '@typescript-eslint/parser', 14 | parserOptions: { 15 | ecmaFeatures: { 16 | jsx: true, 17 | }, 18 | ecmaVersion: 'latest', 19 | sourceType: 'module', 20 | }, 21 | plugins: ['react', '@typescript-eslint'], 22 | rules: { 23 | 'no-fallthrough': 'off', 24 | 'react/jsx-uses-react': 'off', 25 | 'react/react-in-jsx-scope': 'off', 26 | }, 27 | }; 28 | -------------------------------------------------------------------------------- /examples/crm-full-stack/stripe-app/stripe-app.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "com.saasbase.stripe-app-fe", 3 | "version": "0.0.1", 4 | "name": "CRM Buddy", 5 | "icon": "", 6 | "permissions": [], 7 | "ui_extension": { 8 | "views": [ 9 | { 10 | "viewport": "stripe.dashboard.customer.detail", 11 | "component": "CustomerDetailView" 12 | }, 13 | { 14 | "viewport": "stripe.dashboard.home.overview", 15 | "component": "HomeOverviewView" 16 | } 17 | ], 18 | "actions": [], 19 | "content_security_policy": { 20 | "connect-src": null, 21 | "image-src": null, 22 | "purpose": "" 23 | } 24 | }, 25 | "post_install_action": null 26 | } -------------------------------------------------------------------------------- /examples/secret-store/ui-extension/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.natw.secret_store_example", 3 | "version": "0.0.1", 4 | "description": "Secret Store Example", 5 | "private": true, 6 | "license": "~~proprietary~~", 7 | "dependencies": { 8 | "@stripe/ui-extension-sdk": "^8.0.0", 9 | "react": "^17.0.2", 10 | "stripe": "^9.4" 11 | }, 12 | "engines": { 13 | "node": ">=14" 14 | }, 15 | "scripts": {}, 16 | "resolutions": { 17 | "@types/react": "^17.0.2" 18 | }, 19 | "devDependencies": { 20 | "@types/jest": "^27.4.1", 21 | "jest": "^27.5.1", 22 | "ts-jest": "^27.1.3", 23 | "ts-node": "^10.7.0", 24 | "typescript": "^4.7.0-dev.20220319" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /examples/send-mail/api/index.ts: -------------------------------------------------------------------------------- 1 | import express from 'express'; 2 | import sgMail from '@sendgrid/mail'; 3 | import 'dotenv/config'; 4 | 5 | const app = express(); 6 | app.use(express.json()); 7 | 8 | app.post("/api/email", async (request, response) => { 9 | sgMail.setApiKey(process.env.SENDGRID_API_KEY as string); 10 | const mailData = { 11 | from: request.body.from, 12 | to: request.body.to, 13 | subject: request.body.subject, 14 | text: request.body.text, 15 | }; 16 | const result = await sgMail.send(mailData); 17 | response.send({ 18 | result 19 | }); 20 | }); 21 | 22 | app.listen(4242, () => console.log("Node server listening on port 4242!")); -------------------------------------------------------------------------------- /examples/install-webhooks/backend/dotnet/Program.cs: -------------------------------------------------------------------------------- 1 | var builder = WebApplication.CreateBuilder(args); 2 | 3 | // Add services to the container. 4 | 5 | builder.Services.AddControllers(); 6 | // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle 7 | builder.Services.AddEndpointsApiExplorer(); 8 | builder.Services.AddSwaggerGen(); 9 | 10 | var app = builder.Build(); 11 | 12 | // Configure the HTTP request pipeline. 13 | if (app.Environment.IsDevelopment()) 14 | { 15 | app.UseSwagger(); 16 | app.UseSwaggerUI(); 17 | } 18 | 19 | app.UseHttpsRedirection(); 20 | 21 | app.UseAuthorization(); 22 | 23 | app.MapControllers(); 24 | 25 | app.Run(); 26 | -------------------------------------------------------------------------------- /examples/install-webhooks/backend/go/README.md: -------------------------------------------------------------------------------- 1 | # Install-webhooks Example (Go Server) 2 | A Go server implementation with net/http 3 | 4 | ## Requirements 5 | - Go v1.x 6 | - [Configured .env file](https://github.com/stripe/stripe-apps/blob/master/examples/install-webhooks/README.md#backend) 7 | 8 | ## How to run 9 | 1. Make sure you have Go installed on your machine 10 | 11 | 2. From the `Go` directory initialize the go server: 12 | 13 | ```bash 14 | go mod init stripe.com/install-webhooks 15 | ``` 16 | 3. Add module requirements: 17 | 18 | ```bash 19 | go mod tidy 20 | ``` 21 | 22 | 4. Run the application 23 | 24 | ```bash 25 | go run main.go 26 | ``` 27 | 28 | Server is running on `localhost:8080` 29 | -------------------------------------------------------------------------------- /examples/focus-view/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.example.focus-view-example", 3 | "version": "0.0.1", 4 | "description": "FocusView Example", 5 | "private": true, 6 | "license": "~~proprietary~~", 7 | "dependencies": { 8 | "@stripe/ui-extension-sdk": "^8.0.0", 9 | "react": "^17.0.2", 10 | "stripe": "^8.219.0" 11 | }, 12 | "engines": { 13 | "node": ">=14" 14 | }, 15 | "scripts": { 16 | "test": "jest" 17 | }, 18 | "devDependencies": { 19 | "@types/jest": "^27.4.1", 20 | "jest": "^27.5.1", 21 | "ts-jest": "^27.1.4", 22 | "ts-node": "^10.7.0", 23 | "typescript": "^4.6.3" 24 | }, 25 | "resolutions": { 26 | "@types/react": "^17.0.2" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /examples/ui-testing/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.example.ui-testing", 3 | "version": "0.0.1", 4 | "description": "UI Testing Example", 5 | "private": true, 6 | "license": "~~proprietary~~", 7 | "dependencies": { 8 | "@stripe/ui-extension-sdk": "^8.0.0", 9 | "react": "^17.0.2", 10 | "stripe": "^8.170.0" 11 | }, 12 | "engines": { 13 | "node": ">=14" 14 | }, 15 | "scripts": { 16 | "test": "jest", 17 | "format": "prettier --write ./src" 18 | }, 19 | "devDependencies": { 20 | "@types/jest": "^27.4.1", 21 | "jest": "^27.5.1", 22 | "prettier": "^2.6.2", 23 | "ts-jest": "^27.1.4", 24 | "ts-node": "^10.7.0", 25 | "typescript": "^4.6.3" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /examples/climate/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.example.climate", 3 | "version": "0.0.1", 4 | "description": "Stripe Climate Example App", 5 | "private": true, 6 | "license": "~~proprietary~~", 7 | "dependencies": { 8 | "@stripe/ui-extension-sdk": "^8.0.0", 9 | "react": "^17.0.2", 10 | "stripe": "^8.213.0" 11 | }, 12 | "engines": { 13 | "node": ">=14" 14 | }, 15 | "scripts": { 16 | "test": "jest" 17 | }, 18 | "resolutions": { 19 | "@types/react": "^17.0.2" 20 | }, 21 | "devDependencies": { 22 | "@types/jest": "^27.4.1", 23 | "jest": "^27.5.1", 24 | "ts-jest": "^27.1.3", 25 | "ts-node": "^10.7.0", 26 | "typescript": "^4.7.0-dev.20220312" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /examples/send-mail/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.example.sendmail", 3 | "version": "0.0.1", 4 | "description": "Easy Mail Sender", 5 | "private": true, 6 | "license": "~~proprietary~~", 7 | "dependencies": { 8 | "@stripe/ui-extension-sdk": "^8.0.0", 9 | "express": "^5.0.0-alpha.8", 10 | "react": "^17.0.2", 11 | "stripe": "^8.193.0" 12 | }, 13 | "engines": { 14 | "node": ">=14" 15 | }, 16 | "scripts": { 17 | "test": "jest" 18 | }, 19 | "devDependencies": { 20 | "@types/express": "^4.17.13", 21 | "@types/jest": "^27.4.0", 22 | "jest": "^27.4.7", 23 | "ts-jest": "^27.1.3", 24 | "ts-node": "^10.4.0", 25 | "typescript": "^4.6.0-dev.20220204" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /examples/ship-io/src/views/App.tsx: -------------------------------------------------------------------------------- 1 | import { MemoryRouter, Routes, Route } from "react-router-dom"; 2 | 3 | import { LoginProvider } from "../hooks/LoginState"; 4 | 5 | import HomeView from "./HomeView"; 6 | import ProductsView from "./ProductsView"; 7 | import ShipmentView from "./ShipmentView"; 8 | 9 | const App = () => { 10 | return ( 11 | 12 | 13 | 14 | } /> 15 | } /> 16 | } /> 17 | 18 | 19 | 20 | ); 21 | }; 22 | 23 | export default App; 24 | -------------------------------------------------------------------------------- /examples/install-webhooks/frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.example.install-webhooks", 3 | "version": "0.0.1", 4 | "description": "Webhooks Example App", 5 | "private": true, 6 | "license": "~~proprietary~~", 7 | "dependencies": { 8 | "@stripe/ui-extension-sdk": "^8.0.0", 9 | "react": "^18.1.0", 10 | "stripe": "^9.1.0" 11 | }, 12 | "engines": { 13 | "node": ">=14" 14 | }, 15 | "scripts": { 16 | "test": "jest" 17 | }, 18 | "devDependencies": { 19 | "@types/jest": "^27.5.1", 20 | "jest": "^28.1.0", 21 | "ts-jest": "^28.0.2", 22 | "ts-node": "^10.7.0", 23 | "typescript": "^4.6.4" 24 | }, 25 | "resolutions": { 26 | "@types/react": "^17.0.2" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /examples/routing/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.example.router", 3 | "version": "0.0.1", 4 | "description": "Router Example", 5 | "private": true, 6 | "license": "~~proprietary~~", 7 | "dependencies": { 8 | "@stripe/ui-extension-sdk": "^8.0.0", 9 | "react": "^18.0.0", 10 | "react-router-dom": "^6.3.0", 11 | "stripe": "^8.218.0" 12 | }, 13 | "engines": { 14 | "node": ">=14" 15 | }, 16 | "scripts": { 17 | "test": "jest" 18 | }, 19 | "devDependencies": { 20 | "@types/jest": "^27.4.1", 21 | "jest": "^27.5.1", 22 | "ts-jest": "^27.1.4", 23 | "ts-node": "^10.7.0", 24 | "typescript": "^4.6.3" 25 | }, 26 | "resolutions": { 27 | "@types/react": "^17.0.2" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /examples/dropbox-oauth-pkce/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.example.dropbox-oauth-pkce", 3 | "version": "0.0.1", 4 | "description": "Dropbox OAuth PKCE with Secret Store", 5 | "private": true, 6 | "license": "~~proprietary~~", 7 | "dependencies": { 8 | "@stripe/ui-extension-sdk": "^8.0.0", 9 | "date-fns": "^2.28.0", 10 | "react": "^17.0.2", 11 | "stripe": "^8.209.0" 12 | }, 13 | "engines": { 14 | "node": ">=14" 15 | }, 16 | "scripts": { 17 | "start": "stripe apps start", 18 | "test": "jest" 19 | }, 20 | "devDependencies": { 21 | "@types/jest": "^27.4.1", 22 | "jest": "^27.5.1", 23 | "ts-jest": "^27.1.3", 24 | "ts-node": "^10.7.0", 25 | "typescript": "^4.6.2" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /examples/settings-view/bring-your-own-backend/frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.example.settings-view", 3 | "version": "0.0.1", 4 | "description": "Settings View Example", 5 | "private": true, 6 | "license": "~~proprietary~~", 7 | "dependencies": { 8 | "@stripe/ui-extension-sdk": "^8.0.0", 9 | "react": "^17.0.2", 10 | "stripe": "^8.216.0" 11 | }, 12 | "engines": { 13 | "node": ">=14" 14 | }, 15 | "scripts": { 16 | "test": "jest" 17 | }, 18 | "devDependencies": { 19 | "@types/jest": "^27.4.1", 20 | "jest": "^27.5.1", 21 | "ts-jest": "^27.1.4", 22 | "ts-node": "^10.7.0", 23 | "typescript": "^4.6.3" 24 | }, 25 | "resolutions": { 26 | "@types/react": "^17.0.2" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /examples/messaging/stripe-app.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "com.example.messaging", 3 | "version": "0.0.1", 4 | "name": "Messaging", 5 | "icon": "", 6 | "permissions": [ 7 | { 8 | "permission": "customer_read", 9 | "purpose": "Allows the app to access the customer." 10 | }, 11 | { 12 | "permission": "user_email_read", 13 | "purpose": "Allows the app to access the dashboard user email." 14 | } 15 | ], 16 | "ui_extension": { 17 | "views": [ 18 | { 19 | "viewport": "stripe.dashboard.customer.detail", 20 | "component": "Messaging" 21 | } 22 | ], 23 | "actions": [], 24 | "content_security_policy": { 25 | "connect-src": null, 26 | "purpose": "" 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-request-enhancement.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request/Enhancement 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: feature-request, needs-triage 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /examples/crm-full-stack/nodejs-backend/src/services/index.ts: -------------------------------------------------------------------------------- 1 | import { Prisma } from ".prisma/client"; 2 | import { prisma } from "../lib/prisma"; 3 | 4 | export async function createNote(data: Prisma.NoteUncheckedCreateInput) { 5 | const { agentId, customerId, message } = data; 6 | const user = await prisma.note.create({ 7 | data: { 8 | agentId, 9 | customerId, 10 | message 11 | } 12 | }) 13 | 14 | return user; 15 | } 16 | 17 | export async function getAllNotes() { 18 | const allUsers = await prisma.note.findMany(); 19 | return allUsers; 20 | } 21 | 22 | export async function getNotesByCustomerId(customerId: string) { 23 | const allUsers = await prisma.note.findMany({ where: { customerId } }); 24 | return allUsers; 25 | } -------------------------------------------------------------------------------- /examples/linking-different-stripe-object/README.md: -------------------------------------------------------------------------------- 1 | # Linking to Different Stripe Object Example 2 | 3 | ![screenshot1](./Screenshot-1.png) 4 | ![screenshot2](./Screenshot-2.png) 5 | 6 | This is an example code that demonstrates how to construct a link with URL that leads to a different dashboard page. 7 | 8 | ## Features Demonstrated 9 | - How to construct a link with a URL that will lead a user to the dashboard page for a different Stripe object. 10 | - Building the URL for both test and live environments. 11 | 12 | ## Running 13 | 14 | 1. From the `stripe-apps/examples/linking-different-stripe-object` directory, run `yarn` to install dependencies. 15 | 2. Once you install the `stripe apps` CLI plugin, run the start command: 16 | 17 | ``` 18 | stripe apps start 19 | ``` -------------------------------------------------------------------------------- /examples/linking-different-stripe-object/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.example.linking-different-stripe-object", 3 | "version": "0.0.1", 4 | "description": "Linking Different Stripe Object Example", 5 | "private": true, 6 | "license": "~~proprietary~~", 7 | "dependencies": { 8 | "@stripe/ui-extension-sdk": "^8.0.0", 9 | "react": "^17.0.2", 10 | "stripe": "^8.217.0" 11 | }, 12 | "engines": { 13 | "node": ">=14" 14 | }, 15 | "scripts": { 16 | "test": "jest" 17 | }, 18 | "devDependencies": { 19 | "@types/jest": "^27.4.1", 20 | "jest": "^27.5.1", 21 | "ts-jest": "^27.1.4", 22 | "ts-node": "^10.7.0", 23 | "typescript": "^4.6.3" 24 | }, 25 | "resolutions": { 26 | "@types/react": "^17.0.2" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /examples/climate/src/components/ClimateLinkComponent.test.tsx: -------------------------------------------------------------------------------- 1 | import {render} from '@stripe/ui-extension-sdk/testing'; 2 | import {Button} from '@stripe/ui-extension-sdk/ui'; 3 | import ClimateLinkComponent from './ClimateLinkComponent'; 4 | 5 | describe('Climate', () => { 6 | it('renders Learn more button', () => { 7 | const {wrapper} = render(); 8 | expect(wrapper.find(Button)).toContainText('Learn more'); 9 | }); 10 | 11 | it('the Learn more button link contains our app id referrer param', () => { 12 | const {wrapper} = render(); 13 | expect(wrapper.find(Button)?.prop('href')).toContain( 14 | '?src_app=com.example.climate', 15 | ); 16 | }); 17 | }); -------------------------------------------------------------------------------- /examples/github-oauth/packages/backend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "backend", 3 | "version": "1.0.0", 4 | "description": "Backend for Stripe GitHub app.", 5 | "private": true, 6 | "license": "~~proprietary~~", 7 | "scripts": { 8 | "start": "nodemon ./src/index.ts", 9 | "generateKeys": "openssl req -nodes -new -x509 -keyout server.key -out server.cert" 10 | }, 11 | "dependencies": { 12 | "axios": "^0.25.0", 13 | "cors": "^2.8.5", 14 | "dotenv": "^15.0.0", 15 | "express": "^4.17.2", 16 | "stripe": "^8.202.0" 17 | }, 18 | "devDependencies": { 19 | "@types/cookie-parser": "^1.4.2", 20 | "@types/cors": "^2.8.12", 21 | "@types/express": "^4.17.13", 22 | "@types/node": "^17.0.13", 23 | "nodemon": "^2.0.15", 24 | "ts-node": "^10.4.0" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /examples/crm-full-stack/stripe-app/src/api/index.ts: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import { APIResponse } from "../types"; 3 | 4 | export async function addNoteAPI({ customerId, message, agentId }: { customerId: string, message: string, agentId: string }) { 5 | 6 | const response = await axios.post("http://localhost:3000/note", { agentId, customerId, message }) 7 | 8 | return response.data; 9 | } 10 | 11 | export async function getAllNotesAPI(): Promise { 12 | const response = await axios.get("http://localhost:3000/notes") 13 | return response.data; 14 | } 15 | 16 | export async function getNotesForCustomerAPI({ customerId }: { customerId: string }): Promise { 17 | const response = await axios.get(`http://localhost:3000/notes/${customerId}`) 18 | 19 | return response.data; 20 | } -------------------------------------------------------------------------------- /examples/accessing-contextual-data/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.example.accessing-contextual-data", 3 | "version": "0.0.1", 4 | "description": "Accessing Contextual Data", 5 | "private": true, 6 | "license": "~~proprietary~~", 7 | "dependencies": { 8 | "@stripe/ui-extension-sdk": "^8.0.0", 9 | "react": "^17.0.2", 10 | "stripe": "^8.214.0" 11 | }, 12 | "engines": { 13 | "node": ">=14" 14 | }, 15 | "scripts": { 16 | "test": "jest", 17 | "format": "prettier --write ./src" 18 | }, 19 | "devDependencies": { 20 | "@types/jest": "^27.4.1", 21 | "jest": "^27.5.1", 22 | "prettier": "^2.6.1", 23 | "ts-jest": "^27.1.4", 24 | "ts-node": "^10.7.0", 25 | "typescript": "^4.6.3" 26 | }, 27 | "resolutions": { 28 | "@types/react": "^17.0.2" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /schema/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "alwaysStrict": true, 4 | "declaration": true, 5 | "esModuleInterop": true, 6 | "forceConsistentCasingInFileNames": true, 7 | "incremental": true, 8 | "isolatedModules": true, 9 | "lib": ["dom", "dom.iterable", "esnext"], 10 | "module": "CommonJS", 11 | "moduleResolution": "node", 12 | "noEmit": true, 13 | "noFallthroughCasesInSwitch": true, 14 | "noImplicitAny": true, 15 | "noImplicitReturns": false, 16 | "noImplicitThis": true, 17 | "noUnusedLocals": true, 18 | "noUnusedParameters": true, 19 | "outDir": "dist", 20 | "resolveJsonModule": true, 21 | "skipLibCheck": true, 22 | "sourceMap": true, 23 | "strict": true, 24 | "target": "ES2016" 25 | }, 26 | "include": ["test/**/*"] 27 | } 28 | -------------------------------------------------------------------------------- /examples/ship-io/src/hooks/LoginState.tsx: -------------------------------------------------------------------------------- 1 | import { useContext, useState, createContext } from "react"; 2 | import { LoginContext, ProviderProps } from "../common/types"; 3 | import LoginView from "../views/LoginView"; 4 | 5 | const LoginContext = createContext({ 6 | isLoggedIn: false, 7 | setIsLoggedIn: () => undefined, 8 | }); 9 | 10 | export const LoginProvider = ({ children }: ProviderProps) => { 11 | const [isLoggedIn, setIsLoggedIn] = useState(false); 12 | 13 | return ( 14 | 15 | {isLoggedIn ? children : } 16 | 17 | ); 18 | }; 19 | 20 | export const useLogin = () => { 21 | const { isLoggedIn, setIsLoggedIn } = useContext(LoginContext); 22 | return { isLoggedIn, setIsLoggedIn }; 23 | }; 24 | -------------------------------------------------------------------------------- /examples/dropbox-oauth-pkce/stripe-app.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "com.example.dropbox-oauth-pkce", 3 | "version": "0.0.1", 4 | "name": "Dropbox OAuth PKCE", 5 | "icon": "", 6 | "permissions": [ 7 | { 8 | "permission": "secret_write", 9 | "purpose": "For storing secrets in Stripe." 10 | } 11 | ], 12 | "ui_extension": { 13 | "views": [ 14 | { 15 | "viewport": "stripe.dashboard.drawer.default", 16 | "component": "App" 17 | } 18 | ], 19 | "actions": [], 20 | "content_security_policy": { 21 | "connect-src": [ 22 | "https://api.dropboxapi.com/oauth2/token", 23 | "https://api.dropboxapi.com/2/users/get_account" 24 | ], 25 | "image-src": null, 26 | "purpose": "Enables Dropbox integration" 27 | } 28 | }, 29 | "post_install_action": null 30 | } -------------------------------------------------------------------------------- /examples/linking-different-stripe-object/stripe-app.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "com.example.linking-different-stripe-object", 3 | "version": "0.0.1", 4 | "name": "Linking Different Stripe Object Example", 5 | "icon": "", 6 | "permissions": [ 7 | { 8 | "permission": "customer_read", 9 | "purpose": "Allows the home page to read the list of customers" 10 | } 11 | ], 12 | "ui_extension": { 13 | "views": [ 14 | { 15 | "viewport": "stripe.dashboard.customer.detail", 16 | "component": "CustomerView" 17 | }, 18 | { 19 | "viewport": "stripe.dashboard.drawer.default", 20 | "component": "AppView" 21 | } 22 | ], 23 | "actions": [], 24 | "content_security_policy": { 25 | "connect-src": null, 26 | "image-src": null, 27 | "purpose": "" 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /examples/dropbox-oauth-pkce/src/util/getDropboxAccount.ts: -------------------------------------------------------------------------------- 1 | import { TokenData, AccountData } from "./types"; 2 | 3 | export const getDropboxAccount = async ( 4 | tokenData: TokenData, 5 | ): Promise => { 6 | try { 7 | const response = await fetch( 8 | 'https://api.dropboxapi.com/2/users/get_account', 9 | { 10 | method: 'POST', 11 | body: JSON.stringify({ account_id: tokenData.account_id }), 12 | headers: { 13 | Authorization: `Bearer ${tokenData.access_token}`, 14 | 'Content-Type': 'application/json', 15 | }, 16 | }, 17 | ); 18 | if (response.ok) { 19 | return await response.json(); 20 | } 21 | throw new Error(await response.text()); 22 | } catch (e) { 23 | console.error('Unable to get account data:', (e as Error).message); 24 | } 25 | }; -------------------------------------------------------------------------------- /examples/super-todo/src/components/ListTabPanel.tsx: -------------------------------------------------------------------------------- 1 | import { Box, Divider, Inline, TabPanel } from "@stripe/ui-extension-sdk/ui"; 2 | 3 | type ListTabPanelProps = { 4 | lists: { [name: string]: { current: number; total: number } }; 5 | }; 6 | 7 | const ListTabPanel = ({ lists }: ListTabPanelProps) => ( 8 | 9 | 10 | {Object.entries(lists).map(([name, { current, total }]) => ( 11 | <> 12 | 13 | Team {name} 14 | 15 | 16 | {current}/{total} complete 17 | 18 | 19 | 20 | ))} 21 | 22 | 23 | ); 24 | 25 | export default ListTabPanel; 26 | -------------------------------------------------------------------------------- /examples/routing/README.md: -------------------------------------------------------------------------------- 1 | # Routing example 2 | 3 | This example shows how you can use React Router within a Stripe App to control 4 | complex multi-step flows that need to be history-aware (i.e. support a "Back" 5 | button). Since sandboxed Apps don't have access to the browser history routing 6 | won't be reflected in the page URL but most features of React Router still work 7 | with an in-memory router implementation. This is conceptually similar to how 8 | routing works in React Native apps. 9 | 10 | ![Screenshot of a list in the sample app](./list-screen.png) 11 | ![Screenshot of the sample app's detail view](./actions-screen.png) 12 | 13 | ## Running 14 | 15 | 1. Install dependencies by running `yarn` 16 | 2. Make sure you have [installed the Stripe Apps CLI plugin](https://stripe.com/docs/stripe-apps/getting-started#install) 17 | 3. Start the app preview by running `stripe apps start` -------------------------------------------------------------------------------- /examples/ship-io/images.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-explicit-any */ 2 | 3 | declare module "*.jpg" { 4 | const value: any; 5 | export = value; 6 | } 7 | 8 | declare module "*.jpeg" { 9 | const value: any; 10 | export = value; 11 | } 12 | 13 | declare module "*.jfif" { 14 | const value: any; 15 | export = value; 16 | } 17 | 18 | declare module "*.png" { 19 | const value: any; 20 | export = value; 21 | } 22 | 23 | declare module "*.gif" { 24 | const value: any; 25 | export = value; 26 | } 27 | 28 | declare module "*.pjp" { 29 | const value: any; 30 | export = value; 31 | } 32 | 33 | declare module "*.pjpeg" { 34 | const value: any; 35 | export = value; 36 | } 37 | 38 | declare module "*.svg" { 39 | const value: any; 40 | export = value; 41 | } 42 | 43 | declare module "*.webp" { 44 | const value: any; 45 | export = value; 46 | } 47 | 48 | -------------------------------------------------------------------------------- /examples/show-toast/images.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-explicit-any */ 2 | 3 | declare module "*.svg" { 4 | const value: any; 5 | export = value; 6 | } 7 | 8 | declare module "*.jpg" { 9 | const value: any; 10 | export = value; 11 | } 12 | 13 | declare module "*.jfif" { 14 | const value: any; 15 | export = value; 16 | } 17 | 18 | declare module "*.pjp" { 19 | const value: any; 20 | export = value; 21 | } 22 | 23 | declare module "*.png" { 24 | const value: any; 25 | export = value; 26 | } 27 | 28 | declare module "*.webp" { 29 | const value: any; 30 | export = value; 31 | } 32 | 33 | declare module "*.gif" { 34 | const value: any; 35 | export = value; 36 | } 37 | 38 | declare module "*.jpeg" { 39 | const value: any; 40 | export = value; 41 | } 42 | 43 | declare module "*.pjpeg" { 44 | const value: any; 45 | export = value; 46 | } 47 | 48 | -------------------------------------------------------------------------------- /examples/super-todo/images.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-explicit-any */ 2 | 3 | declare module "*.svg" { 4 | const value: any; 5 | export = value; 6 | } 7 | 8 | declare module "*.webp" { 9 | const value: any; 10 | export = value; 11 | } 12 | 13 | declare module "*.jpg" { 14 | const value: any; 15 | export = value; 16 | } 17 | 18 | declare module "*.pjpeg" { 19 | const value: any; 20 | export = value; 21 | } 22 | 23 | declare module "*.png" { 24 | const value: any; 25 | export = value; 26 | } 27 | 28 | declare module "*.pjp" { 29 | const value: any; 30 | export = value; 31 | } 32 | 33 | declare module "*.gif" { 34 | const value: any; 35 | export = value; 36 | } 37 | 38 | declare module "*.jpeg" { 39 | const value: any; 40 | export = value; 41 | } 42 | 43 | declare module "*.jfif" { 44 | const value: any; 45 | export = value; 46 | } 47 | 48 | -------------------------------------------------------------------------------- /examples/crm-full-stack/stripe-app/images.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-explicit-any */ 2 | 3 | declare module "*.jpg" { 4 | const value: any; 5 | export = value; 6 | } 7 | 8 | declare module "*.pjpeg" { 9 | const value: any; 10 | export = value; 11 | } 12 | 13 | declare module "*.webp" { 14 | const value: any; 15 | export = value; 16 | } 17 | 18 | declare module "*.gif" { 19 | const value: any; 20 | export = value; 21 | } 22 | 23 | declare module "*.jfif" { 24 | const value: any; 25 | export = value; 26 | } 27 | 28 | declare module "*.pjp" { 29 | const value: any; 30 | export = value; 31 | } 32 | 33 | declare module "*.png" { 34 | const value: any; 35 | export = value; 36 | } 37 | 38 | declare module "*.svg" { 39 | const value: any; 40 | export = value; 41 | } 42 | 43 | declare module "*.jpeg" { 44 | const value: any; 45 | export = value; 46 | } 47 | 48 | -------------------------------------------------------------------------------- /examples/crm-full-stack/stripe-app/src/views/brand_icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /examples/send-mail/src/views/App.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | Box, 3 | ContextView, 4 | } from '@stripe/ui-extension-sdk/ui'; 5 | import type { ExtensionContextValue } from '@stripe/ui-extension-sdk/context'; 6 | import { useCustomerLoader } from '../hooks/loadCustomer'; 7 | import { SendEmailForm } from '../components/SendEmailForm'; 8 | 9 | const App = (props: ExtensionContextValue) => { 10 | const customerProps = useCustomerLoader(props); 11 | return ( 12 | 13 | 22 | 26 | 27 | 28 | ); 29 | }; 30 | 31 | export default App; 32 | -------------------------------------------------------------------------------- /examples/install-webhooks/backend/python/README.md: -------------------------------------------------------------------------------- 1 | # Install-webhooks Example (Python server) 2 | A Flask server implementation 3 | 4 | ## Requirements 5 | - Python 3 6 | - [Configured .env file](https://github.com/stripe/stripe-apps/blob/master/examples/install-webhooks/README.md#backend) 7 | 8 | ## How to run 9 | 1. Create and activate a new virtual environment 10 | 11 | 2. Install dependencies 12 | 13 | 3. Export and run the application 14 | 15 | #### MacOS / Unix 16 | 17 | ```bash 18 | python3 -m venv env 19 | source env/bin/activate 20 | 21 | pip install -r requirements.txt 22 | 23 | export FLASK_APP=index.py 24 | python3 -m flask run --port=8080 25 | ``` 26 | 27 | #### Windows (PowerShell) 28 | 29 | ```bash 30 | python3 -m venv env 31 | .\env\Scripts\activate.bat 32 | 33 | pip install -r requirements.txt 34 | 35 | $env:FLASK_APP=“server.py" 36 | python3 -m flask run --port=8080 37 | ``` 38 | 39 | Server is running on `localhost:8080` -------------------------------------------------------------------------------- /examples/super-todo/stripe-app.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "com.example.super-todo", 3 | "version": "0.0.7", 4 | "name": "SuperTodo", 5 | "icon": "", 6 | "permissions": [], 7 | "ui_extension": { 8 | "views": [ 9 | { 10 | "viewport": "stripe.dashboard.customer.detail", 11 | "component": "CustomerDetailView" 12 | }, 13 | { 14 | "viewport": "stripe.dashboard.payment.list", 15 | "component": "PaymentListView" 16 | }, 17 | { 18 | "viewport": "stripe.dashboard.home.overview", 19 | "component": "HomeOverviewView" 20 | }, 21 | { 22 | "viewport": "stripe.dashboard.customer.list", 23 | "component": "CustomerListView" 24 | } 25 | ], 26 | "actions": [], 27 | "content_security_policy": { 28 | "connect-src": null, 29 | "image-src": null, 30 | "purpose": "" 31 | } 32 | }, 33 | "post_install_action": null 34 | } 35 | -------------------------------------------------------------------------------- /examples/ship-io/src/components/BaseView.tsx: -------------------------------------------------------------------------------- 1 | import { Box, ContextView, Inline, Link } from "@stripe/ui-extension-sdk/ui"; 2 | import BrandIconLight from "../assets/brand-icon-light.svg"; 3 | import { TITLE, BRAND_COLOR } from "../constants"; 4 | import { useLogin } from "../hooks/LoginState"; 5 | 6 | export const BaseView = ({ ...contextViewProps }) => { 7 | const { isLoggedIn, setIsLoggedIn } = useLogin(); 8 | return ( 9 | 15 | {contextViewProps.children} 16 | {isLoggedIn ? ( 17 | 22 | 23 | setIsLoggedIn(false)}>Sign out 24 | 25 | 26 | ) : null} 27 | 28 | ); 29 | }; 30 | -------------------------------------------------------------------------------- /examples/github-oauth/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.example.enneagynous-encephalitis", 3 | "version": "0.0.1", 4 | "description": "GitHub", 5 | "private": true, 6 | "license": "~~proprietary~~", 7 | "workspaces": [ 8 | "packages/*" 9 | ], 10 | "scripts": { 11 | "start": "concurrently -n backend,frontend -c blue,magenta \"yarn start:backend\" \"yarn start:frontend\"", 12 | "start:backend": "yarn workspace backend start", 13 | "start:frontend": "yarn workspace frontend start" 14 | }, 15 | "devDependencies": { 16 | "@trivago/prettier-plugin-sort-imports": "^3.1.1", 17 | "@typescript-eslint/eslint-plugin": "^5.10.0", 18 | "@typescript-eslint/parser": "^5.10.0", 19 | "concurrently": "^7.0.0", 20 | "eslint": "^8.7.0", 21 | "eslint-config-prettier": "^8.3.0", 22 | "eslint-plugin-react": "^7.28.0", 23 | "prettier": "^2.5.1", 24 | "typescript": "^4.5.5" 25 | }, 26 | "engines": { 27 | "node": ">=14" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /examples/ship-io/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es2021": true 5 | }, 6 | "extends": [ 7 | "eslint:recommended", 8 | "plugin:react/recommended", 9 | "plugin:@typescript-eslint/recommended", 10 | "plugin:react-hooks/recommended" 11 | ], 12 | "parser": "@typescript-eslint/parser", 13 | "parserOptions": { 14 | "ecmaFeatures": { 15 | "jsx": true 16 | }, 17 | "ecmaVersion": "latest", 18 | "sourceType": "module" 19 | }, 20 | "plugins": [ 21 | "react", 22 | "@typescript-eslint" 23 | ], 24 | "rules": { 25 | "react/react-in-jsx-scope": 0, 26 | "no-restricted-syntax": [ 27 | "error", 28 | { 29 | "message": "This element is not supported. Supported components can be imported from '@stripe/ui-extension-sdk/ui'.", 30 | "selector": "JSXOpeningElement[name.name=/^[a-z]*$/][name.name!='option']" 31 | } 32 | ] 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /examples/ship-io/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.example.ship-io", 3 | "version": "0.0.1", 4 | "description": "Ship.IO", 5 | "private": true, 6 | "license": "~~proprietary~~", 7 | "dependencies": { 8 | "@stripe/ui-extension-sdk": "^8.0.0", 9 | "react": "^17.0.2", 10 | "react-router-dom": "^6.3.0", 11 | "stripe": "^9.8.0" 12 | }, 13 | "engines": { 14 | "node": ">=14" 15 | }, 16 | "scripts": { 17 | "test": "jest" 18 | }, 19 | "resolutions": { 20 | "@types/react": "^17.0.2" 21 | }, 22 | "devDependencies": { 23 | "@types/jest": "^28.1.1", 24 | "@typescript-eslint/eslint-plugin": "^5.28.0", 25 | "@typescript-eslint/parser": "^5.28.0", 26 | "eslint": "^8.17.0", 27 | "eslint-plugin-react": "^7.30.0", 28 | "eslint-plugin-react-hooks": "^4.5.0", 29 | "jest": "^27.5.1", 30 | "jest-transform-stub": "^2.0.0", 31 | "ts-jest": "^27.1.4", 32 | "ts-node": "^10.8.1", 33 | "typescript": "^4.7.3" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /examples/show-toast/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.example.show-toast", 3 | "version": "0.1.0", 4 | "description": "App for testing toasts and other things", 5 | "private": true, 6 | "license": "~~proprietary~~", 7 | "dependencies": { 8 | "@stripe/ui-extension-sdk": "8.3.0", 9 | "react": "^17.0.2", 10 | "stripe": "^9.13.0" 11 | }, 12 | "engines": { 13 | "node": ">=14" 14 | }, 15 | "scripts": { 16 | "test": "jest" 17 | }, 18 | "resolutions": { 19 | "@types/react": "^17.0.2" 20 | }, 21 | "devDependencies": { 22 | "@types/jest": "^28.1.5", 23 | "@typescript-eslint/eslint-plugin": "^5.30.6", 24 | "@typescript-eslint/parser": "^5.30.6", 25 | "eslint": "^8.19.0", 26 | "eslint-plugin-react": "^7.30.1", 27 | "eslint-plugin-react-hooks": "^4.6.0", 28 | "jest": "^27.5.1", 29 | "jest-transform-stub": "^2.0.0", 30 | "ts-jest": "^27.1.4", 31 | "ts-node": "^10.8.2", 32 | "typescript": "^4.7.4" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /examples/super-todo/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es2021": true 5 | }, 6 | "extends": [ 7 | "eslint:recommended", 8 | "plugin:react/recommended", 9 | "plugin:@typescript-eslint/recommended", 10 | "plugin:react-hooks/recommended" 11 | ], 12 | "parser": "@typescript-eslint/parser", 13 | "parserOptions": { 14 | "ecmaFeatures": { 15 | "jsx": true 16 | }, 17 | "ecmaVersion": "latest", 18 | "sourceType": "module" 19 | }, 20 | "plugins": [ 21 | "react", 22 | "@typescript-eslint" 23 | ], 24 | "rules": { 25 | "react/react-in-jsx-scope": 0, 26 | "no-restricted-syntax": [ 27 | "error", 28 | { 29 | "message": "This element is not supported. Supported components can be imported from '@stripe/ui-extension-sdk/ui'.", 30 | "selector": "JSXOpeningElement[name.name=/^[a-z]*$/][name.name!='option']" 31 | } 32 | ] 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /examples/install-webhooks/backend/dotnet/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/launchsettings.json", 3 | "iisSettings": { 4 | "windowsAuthentication": false, 5 | "anonymousAuthentication": true, 6 | "iisExpress": { 7 | "applicationUrl": "http://localhost:47409", 8 | "sslPort": 44315 9 | } 10 | }, 11 | "profiles": { 12 | "dotnet": { 13 | "commandName": "Project", 14 | "dotnetRunMessages": true, 15 | "launchBrowser": true, 16 | "launchUrl": "swagger", 17 | "applicationUrl": "http://localhost:8080", 18 | "environmentVariables": { 19 | "ASPNETCORE_ENVIRONMENT": "Development" 20 | } 21 | }, 22 | "IIS Express": { 23 | "commandName": "IISExpress", 24 | "launchBrowser": true, 25 | "launchUrl": "swagger", 26 | "environmentVariables": { 27 | "ASPNETCORE_ENVIRONMENT": "Development" 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /examples/crm-full-stack/stripe-app/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es2021": true 5 | }, 6 | "extends": [ 7 | "eslint:recommended", 8 | "plugin:react/recommended", 9 | "plugin:@typescript-eslint/recommended", 10 | "plugin:react-hooks/recommended" 11 | ], 12 | "parser": "@typescript-eslint/parser", 13 | "parserOptions": { 14 | "ecmaFeatures": { 15 | "jsx": true 16 | }, 17 | "ecmaVersion": "latest", 18 | "sourceType": "module" 19 | }, 20 | "plugins": [ 21 | "react", 22 | "@typescript-eslint" 23 | ], 24 | "rules": { 25 | "react/react-in-jsx-scope": 0, 26 | "no-restricted-syntax": [ 27 | "error", 28 | { 29 | "message": "This element is not supported. Supported components can be imported from '@stripe/ui-extension-sdk/ui'.", 30 | "selector": "JSXOpeningElement[name.name=/^[a-z]*$/][name.name!='option']" 31 | } 32 | ] 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /examples/crm-full-stack/stripe-app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.saasbase.crmbuddy", 3 | "version": "0.0.1", 4 | "description": "CRM Buddy", 5 | "private": true, 6 | "license": "~~proprietary~~", 7 | "dependencies": { 8 | "@stripe/ui-extension-sdk": "^8.3.0", 9 | "axios": "^0.27.2", 10 | "moment": "^2.29.4", 11 | "react": "^18.2.0", 12 | "stripe": "^10.12.0" 13 | }, 14 | "engines": { 15 | "node": ">=14" 16 | }, 17 | "scripts": { 18 | "test": "jest" 19 | }, 20 | "resolutions": { 21 | "@types/react": "^17.0.2" 22 | }, 23 | "devDependencies": { 24 | "@types/jest": "^29.1.0", 25 | "@typescript-eslint/eslint-plugin": "^5.38.1", 26 | "@typescript-eslint/parser": "^5.38.1", 27 | "eslint": "^8.24.0", 28 | "eslint-plugin-react": "^7.31.8", 29 | "eslint-plugin-react-hooks": "^4.6.0", 30 | "jest": "^29.1.1", 31 | "jest-transform-stub": "^2.0.0", 32 | "ts-jest": "^29.0.3", 33 | "ts-node": "^10.9.1", 34 | "typescript": "^4.8.4" 35 | } 36 | } -------------------------------------------------------------------------------- /schema/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@stripe/app-manifest-schema", 3 | "version": "0.0.0", 4 | "description": "Stripe App manifest schema", 5 | "scripts": { 6 | "lint": "eslint --ext ts test", 7 | "test": "jest", 8 | "types": "tsc" 9 | }, 10 | "author": "Stripe, Inc.", 11 | "license": "UNLICENSED", 12 | "devDependencies": { 13 | "@swc/core": "1.2.121", 14 | "@swc/jest": "^0.2.20", 15 | "@types/jest": "^27.4.0", 16 | "@typescript-eslint/eslint-plugin": "^5.14.1-alpha.6", 17 | "@typescript-eslint/parser": "^5.14.1-alpha.6", 18 | "ajv": "^8.11.0", 19 | "ajv-formats": "^2.1.1", 20 | "eslint": "^7.29.0", 21 | "eslint-config-prettier": "^8.3.0", 22 | "eslint-plugin-import": "^2.25.4", 23 | "eslint-plugin-jest": "^25.3.4", 24 | "eslint-plugin-jsx-a11y": "^6.5.1", 25 | "eslint-plugin-no-unsanitized": "^4.0.1", 26 | "eslint-plugin-prettier": "^4.0.0", 27 | "jest": "^27.4.7", 28 | "prettier": "^2.5.1", 29 | "typescript": "4.6.2" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Stripe, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/-bug--bug-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "[Bug] Bug report" 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug, needs-triage 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser: [e.g. chrome, safari] 29 | - Version: [e.g. 22] 30 | - Viewport dimensions: [e.g. 1920 x 1080] 31 | 32 | **App (please complete the following information):** 33 | - App Id: [e.g. com.example.helloworld] 34 | - @stripe/ui-extension-sdk package version: [e.g. 8.9.1] 35 | 36 | **Additional context** 37 | Add any other context about the problem here. 38 | -------------------------------------------------------------------------------- /examples/send-mail/src/components/SendButton.tsx: -------------------------------------------------------------------------------- 1 | import { FC } from "react"; 2 | import { Button, Box } from '@stripe/ui-extension-sdk/ui'; 3 | import { useSendMail } from "../hooks/sendMail"; 4 | import Stripe from "stripe"; 5 | 6 | 7 | export type SendButtonProps = Pick, 'sendingStatus' | 'callSendMailAPI' | 'sendEmailErrorMessage'> & { 8 | customer?: Stripe.Customer | null; 9 | }; 10 | export const SendButton: FC = ({ 11 | sendingStatus, 12 | callSendMailAPI, 13 | sendEmailErrorMessage, 14 | customer, 15 | }) => { 16 | if (sendingStatus === 'error') { 17 | return {sendEmailErrorMessage}; 18 | } else if (sendingStatus === 'complete') { 19 | return Email has sent!; 20 | }; 21 | return ( 22 | 31 | ); 32 | }; -------------------------------------------------------------------------------- /examples/settings-view/bring-your-own-backend/frontend/src/views/App.tsx: -------------------------------------------------------------------------------- 1 | import { Box, ContextView, Inline } from "@stripe/ui-extension-sdk/ui"; 2 | 3 | const App = () => { 4 | return ( 5 | 6 | 14 | To open the settings view: 15 | 16 | 1. click on the options button{" "} 17 | (...) at the top 18 | right corner of the page to display a dropdown. 19 | 20 | 21 | 2. Click on{" "} 22 | preview app settings{" "} 23 | from the dropdown and the settings view will open on a new tab. 24 | 25 | 26 | 27 | ); 28 | }; 29 | 30 | export default App; 31 | -------------------------------------------------------------------------------- /examples/crm-full-stack/nodejs-backend/src/app.ts: -------------------------------------------------------------------------------- 1 | import { Prisma } from ".prisma/client"; 2 | import cors from "cors"; 3 | import express from "express"; 4 | import helmet from "helmet"; 5 | import { createNote, getAllNotes, getNotesByCustomerId } from "./services"; 6 | 7 | const app = express(); 8 | 9 | app.use(helmet()); 10 | app.use(cors()); 11 | cors({ credentials: true, origin: true }) 12 | 13 | app.use(express.json()); 14 | 15 | app.post("/note", async (req, res) => { 16 | const { agentId, customerId, message } = req.body; 17 | 18 | const newNote: Prisma.NoteUncheckedCreateInput = { agentId, customerId, message } 19 | 20 | await createNote(newNote); 21 | res.json({ error: false, data: {} }) 22 | }) 23 | 24 | app.get("/notes", async (req, res) => { 25 | const notes = await getAllNotes(); 26 | res.json({ error: false, data: { notes } }) 27 | }) 28 | 29 | app.get("/notes/:customerId", async (req, res) => { 30 | const customerId = req.params.customerId; 31 | 32 | const notes = await getNotesByCustomerId(customerId); 33 | res.json({ error: false, data: { notes } }) 34 | }) 35 | 36 | export default app; 37 | -------------------------------------------------------------------------------- /examples/install-webhooks/backend/README.md: -------------------------------------------------------------------------------- 1 | # Running the server 2 | 3 | We included several RESTful server that each implement the same endpoints and logic. Pick the language you are most comfortable in and follow the instructions in the directory on how to run. 4 | 5 | # Supported Languages 6 | - [Javascript (Node)](https://github.com/stripe/stripe-apps/blob/master/examples/install-webhooks/backend/node/README.md) 7 | - [Python (Flask)](https://github.com/stripe/stripe-apps/blob/master/examples/install-webhooks/backend/python/README.md) 8 | - [Ruby (Sinatra)](https://github.com/stripe/stripe-apps/blob/master/examples/install-webhooks/backend/ruby/README.md) 9 | - [Go](https://github.com/stripe/stripe-apps/blob/master/examples/install-webhooks/backend/go/README.md) 10 | - [PHP (Slim)](https://github.com/stripe/stripe-apps/blob/master/examples/install-webhooks/backend/php/README.md) 11 | - [C# (.NET Core)](https://github.com/stripe/stripe-apps/blob/master/examples/install-webhooks/backend/dotnet/README.md) 12 | - [Java (Spark)](https://github.com/stripe/stripe-apps/blob/master/examples/install-webhooks/backend/java/README.md) 13 | -------------------------------------------------------------------------------- /examples/messaging/src/fakeData.ts: -------------------------------------------------------------------------------- 1 | import type { Message } from "./types"; 2 | 3 | export const fakeUserMessages: Message[] = [ 4 | { 5 | id: '1', 6 | subject: 'Refund processing', 7 | from: 'sds@example.com', 8 | to: 'some.merchant@gmail.com', 9 | date: 1637088399000, 10 | snippet: 'Hi there, Has my refund processed yet? I don\'t see it in my bank account yet. I know these things...', 11 | body: 'Hi there,\n\nHas my refund processed yet? I don\'t see it in my bank account yet. I know these things take time to process, and I appreciate you looking into it.\n\nWarm regards,\nExample Customer', 12 | }, 13 | { 14 | id: '2', 15 | subject: 'Your order #012345678', 16 | from: 'some.merchant@gmail.com', 17 | to: 'sds@example.com', 18 | date: 1636088399000, 19 | snippet: 'Dear Soumya, Get ready, because your order is on the way! Look out for a tracking number within...', 20 | body: 'Dear Soumya,\n\nGet ready, because your order is on the way! Look out for a tracking number within 1-3 business days. We\'re excited for you to try out your new widget.\n\nWarm regards,\nCool Merchant', 21 | }, 22 | ]; 23 | -------------------------------------------------------------------------------- /examples/crm-full-stack/nodejs-backend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "@prisma/client": "^4.1.1", 4 | "cors": "^2.8.5", 5 | "express": "^4.17.2", 6 | "helmet": "^4.6.0", 7 | "jest": "^27.4.5", 8 | "supertest": "^6.1.6", 9 | "ts-jest": "^27.1.2" 10 | }, 11 | "jest": { 12 | "moduleFileExtensions": [ 13 | "ts", 14 | "tsx", 15 | "js" 16 | ], 17 | "transform": { 18 | "\\.(ts|tsx)$": "ts-jest" 19 | } 20 | }, 21 | "name": "be", 22 | "version": "1.0.0", 23 | "main": "index.js", 24 | "devDependencies": { 25 | "@types/cors": "^2.8.12", 26 | "@types/dotenv": "^8.2.0", 27 | "@types/express": "^4.17.13", 28 | "@types/helmet": "^4.0.0", 29 | "@types/jest": "^27.0.3", 30 | "@types/node": "^17.0.4", 31 | "@types/supertest": "^2.0.11", 32 | "dotenv": "^10.0.0", 33 | "prisma": "^4.1.1", 34 | "ts-node-dev": "^1.1.8", 35 | "typescript": "^4.5.4" 36 | }, 37 | "scripts": { 38 | "dev": "ts-node-dev --respawn --pretty --transpile-only src/index.ts", 39 | "test": "jest" 40 | }, 41 | "author": "", 42 | "license": "ISC", 43 | "description": "" 44 | } 45 | -------------------------------------------------------------------------------- /examples/dropbox-oauth-pkce/README.md: -------------------------------------------------------------------------------- 1 | # Dropbox OAuth PKCE with Secret Store 2 | 3 | **This app is not endorsed by Dropbox, it was written by Stripe as a demonstration of the Stripe App platform.** 4 | 5 | The "Dropbox OAuth PKCE" app allows Dashboard users to retrieve an OAuth token from Dropbox using OAuth 2.0 PKCE. 6 | 7 | ## Platform capabilities demonstrated 8 | - OAuth PKCE workflow 9 | - `createOAuthState` function 10 | - Using Secret Store API to save OAuth tokens 11 | - Connecting to an external API 12 | 13 | ## Usage 14 | 15 | To test this example, you'll need to [create a Dropbox app](https://www.dropbox.com/lp/developers). 16 | 17 | Once you've created an app, copy the "App key" from the developer console and paste it into a new file `config.ts` like so: 18 | 19 | ```typescript 20 | export const client_id='random_clientID' 21 | ``` 22 | 23 | This test app will require the correct redirect URI to be set in the app settings. In the case of this example, that's: 24 | 25 | ``` 26 | https://dashboard.stripe.com/test/apps-oauth/com.example.dropbox-oauth-pkce 27 | ``` 28 | 29 | Finally, for the Load Account Data button to work, grant your app the `sharing.read` scope. -------------------------------------------------------------------------------- /examples/install-webhooks/backend/java/app/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * This file was generated by the Gradle 'init' task. 3 | * 4 | * This generated file contains a sample Java application project to get you started. 5 | * For more details take a look at the 'Building Java & JVM projects' chapter in the Gradle 6 | * User Manual available at https://docs.gradle.org/7.4.2/userguide/building_java_projects.html 7 | */ 8 | 9 | plugins { 10 | // Apply the application plugin to add support for building a CLI application in Java. 11 | id 'application' 12 | } 13 | 14 | repositories { 15 | // Use Maven Central for resolving dependencies. 16 | mavenCentral() 17 | } 18 | 19 | dependencies { 20 | 21 | // This dependency is used by the application. 22 | implementation 'com.google.guava:guava:30.1.1-jre' 23 | implementation "com.stripe:stripe-java:20.120.0" 24 | implementation 'com.sparkjava:spark-core:2.3' 25 | implementation 'com.google.code.gson:gson:2.9.0' 26 | implementation 'io.github.cdimascio:dotenv-java:2.2.3' 27 | } 28 | 29 | application { 30 | // Define the main class for the application. 31 | mainClass = 'stripe.App' 32 | } 33 | 34 | -------------------------------------------------------------------------------- /examples/ship-io/README.md: -------------------------------------------------------------------------------- 1 | # Ship.IO Example 2 | 3 | ![A gif of the Ship.IO UI-only app flow](ShipIOPreview.gif) 4 | 5 | ## Summary 6 | 7 | This UI-only example demonstrates building a basic Stripe App using approved UI component patterns. It only contains enough logic to demonstrate basic UI functionality, making it easy to copy and use as a basis for a new Stripe App. 8 | 9 | The app mocks an order fulfillment app that lets users create labels for shipments. It demonstrates how to build a views that follow [Stripe Apps design standards](https://stripe.com/docs/stripe-apps/patterns), including: 10 | 11 | - Authentication [(LoginView)](src/views/LoginView.tsx) 12 | - Sign out [(BaseView)](src/components/BaseView.tsx/) 13 | - Navigation and routing [(App.tsx)](/src/views/App.tsx) 14 | - Backlinks ([HomeView](/src/views/HomeView.tsx), [ProductsView](/src/views/ProductsView.tsx), [ShipmentView](/src/views/ShipmentView.tsx)) 15 | - Action buttons ([ProductsView](/src/views/ProductsView.tsx), [HomeView](/src/views/HomeView.tsx)) 16 | 17 | ## Running 18 | 19 | You can run this app in preview mode to see it in action by using the following command. 20 | 21 | ``` 22 | stripe apps start 23 | ``` 24 | -------------------------------------------------------------------------------- /examples/messaging/src/utils/stripeApi.ts: -------------------------------------------------------------------------------- 1 | import {useState, useEffect} from 'react'; 2 | import type {Stripe} from "stripe"; 3 | import stripeClient from '../clients/stripe'; 4 | import {getDashboardUserEmail} from '@stripe/ui-extension-sdk/utils'; 5 | 6 | export const useCustomer = (customerId?: string) => { 7 | if (!customerId) { 8 | return null; 9 | } 10 | 11 | const [customer, setCustomer] = useState(null); 12 | 13 | const loadCustomer = async () => { 14 | const customer = await stripeClient.customers.retrieve(customerId); 15 | 16 | setCustomer(customer); 17 | }; 18 | 19 | useEffect(() => { 20 | loadCustomer(); 21 | }, [customerId]); 22 | 23 | return customer; 24 | }; 25 | 26 | export const useDashboardUserEmail = () => { 27 | const [customer, setCustomer] = useState(null); 28 | 29 | const loadEmail = async () => { 30 | try { 31 | const {email} = await getDashboardUserEmail(); 32 | setCustomer(email); 33 | } catch(e) { 34 | console.error(e); 35 | } 36 | }; 37 | 38 | useEffect(() => { 39 | loadEmail(); 40 | }, []); 41 | 42 | return customer; 43 | }; 44 | -------------------------------------------------------------------------------- /examples/super-todo/src/components/CreateListMeta.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | Box, 3 | Button, 4 | Checkbox, 5 | FocusView, 6 | Icon, 7 | TextArea, 8 | } from "@stripe/ui-extension-sdk/ui"; 9 | 10 | type CreateListMetaProps = { 11 | shown: boolean; 12 | onSave: () => void; 13 | onBack: () => void; 14 | }; 15 | 16 | const CreateListMeta = ({ shown, onSave, onBack }: CreateListMetaProps) => ( 17 | 22 | Save 23 | 24 | } 25 | secondaryAction={ 26 | 30 | } 31 | > 32 | Member Permissions 33 | 34 | 35 |