App Manifest Reference
The stripe-app.json manifest file is the central configuration for your Stripe App. It declares your app’s identity, permissions, UI views, security policies, and post-install behavior.
Full Manifest Example
{ "id": "com.tajo.brevo-integration", "version": "1.2.0", "name": "Tajo for Brevo", "icon": "./assets/icon.png", "distribution_type": "public", "sandbox_install_compatible": true, "stripe_api_access_type": "oauth", "allowed_redirect_uris": [ "https://tajo.io/stripe/callback", "https://tajo.io/stripe/oauth/complete" ], "permissions": [ { "permission": "customer_read", "purpose": "Read customer profiles to sync with Brevo contacts" }, { "permission": "customer_write", "purpose": "Update customer metadata with Brevo sync status" }, { "permission": "charge_read", "purpose": "Access payment history for Brevo event tracking" }, { "permission": "product_read", "purpose": "Sync product catalog to Brevo for personalized campaigns" }, { "permission": "event_read", "purpose": "Subscribe to real-time events for Brevo automation triggers" }, { "permission": "invoice_read", "purpose": "Track invoice lifecycle events in Brevo" } ], "ui_extension": { "views": [ { "viewport": "stripe.dashboard.customer.detail", "component": "CustomerDetailView" }, { "viewport": "stripe.dashboard.customer.list", "component": "CustomerListView" }, { "viewport": "stripe.dashboard.home.overview", "component": "OverviewView" }, { "viewport": "stripe.dashboard.drawer.default", "component": "DrawerView" }, { "viewport": "stripe.dashboard.settings", "component": "SettingsView" }, { "viewport": "stripe.dashboard.onboarding", "component": "OnboardingView" } ], "content_security_policy": { "connect-src": [ "https://api.tajo.io", "https://api.brevo.com" ], "image-src": [ "https://cdn.tajo.io", "https://assets.brevo.com" ], "purpose": "Connect to Tajo API for data sync and Brevo API for contact management" } }, "post_install_action": { "type": "onboarding" }, "constants": { "API_BASE_URL": "https://api.tajo.io/v1", "SYNC_INTERVAL_SECONDS": "300" }}Schema Reference
Top-Level Fields
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Unique app identifier in reverse domain notation (slug format) |
version | string | Yes | Semantic version string (e.g., "1.2.0") |
name | string | Yes | Display name shown in the marketplace (max 35 characters) |
icon | string | Yes | Relative path to the app icon file (300x300 PNG or SVG) |
distribution_type | string | Yes | "public" for marketplace or "private" for internal use |
sandbox_install_compatible | boolean | No | Whether the app can be installed in sandbox/test mode |
stripe_api_access_type | string | No | API access method: "oauth" or "api_key" |
allowed_redirect_uris | string[] | No | Allowed OAuth redirect URIs for install flow |
permissions | PermissionRequest[] | Yes | Array of permission requests |
ui_extension | UIExtensionManifest | No | UI extension configuration |
post_install_action | PostInstallAction | No | Action to take after app installation |
constants | object | No | Key-value pairs accessible in the app at runtime |
id
The app identifier is a slug-format string, typically in reverse domain notation:
"id": "com.tajo.brevo-integration"- Must be globally unique across all Stripe Apps
- Use lowercase letters, numbers, hyphens, and dots only
- Cannot be changed after the app is created
- Determines the app’s URL on the marketplace
version
Follows semantic versioning:
"version": "1.2.0"- MAJOR: Breaking changes or significant feature additions
- MINOR: New features, backward compatible
- PATCH: Bug fixes and minor improvements
- Must be incremented for each upload
distribution_type
Controls who can install your app:
| Value | Description |
|---|---|
"public" | Available on the Stripe App Marketplace to all users |
"private" | Only installable by your own Stripe account |
stripe_api_access_type
Determines how your app authenticates with the Stripe API:
| Value | Description |
|---|---|
"oauth" | Uses OAuth 2.0 flow for authentication (recommended for public apps) |
"api_key" | Uses restricted API keys (suitable for private apps) |
PermissionRequest
Each permission request declares a specific Stripe API permission your app needs:
{ "permission": "customer_read", "purpose": "Read customer profiles to sync with Brevo contacts"}| Field | Type | Required | Description |
|---|---|---|---|
permission | string | Yes | The permission identifier (see Permissions Reference) |
purpose | string | Yes | Human-readable explanation of why this permission is needed |
Purpose guidelines:
- Write clear, specific explanations that merchants can understand
- Explain what the permission is used for, not just what it grants
- Keep descriptions concise (one sentence)
- Avoid technical jargon
UIExtensionManifest
Configures the UI components of your app:
{ "ui_extension": { "views": [...], "content_security_policy": {...} }}| Field | Type | Required | Description |
|---|---|---|---|
views | ViewManifest[] | Yes | Array of view declarations |
content_security_policy | CSPRequest | No | Content Security Policy for external resources |
ViewManifest
Each view maps a React component to a Stripe Dashboard viewport:
{ "viewport": "stripe.dashboard.customer.detail", "component": "CustomerDetailView"}| Field | Type | Required | Description |
|---|---|---|---|
viewport | string | Yes | The Dashboard location where this view renders (see Viewports Reference) |
component | string | Yes | Name of the React component to render (must match the exported component name) |
A single app can declare multiple views for different viewports:
"views": [ { "viewport": "stripe.dashboard.customer.detail", "component": "CustomerDetailView" }, { "viewport": "stripe.dashboard.payment.detail", "component": "PaymentDetailView" }, { "viewport": "stripe.dashboard.home.overview", "component": "OverviewView" }]CSPRequest
The Content Security Policy controls which external domains your app can connect to:
{ "content_security_policy": { "connect-src": [ "https://api.tajo.io", "https://api.brevo.com" ], "image-src": [ "https://cdn.tajo.io" ], "purpose": "Connect to Tajo API for data sync and load images from CDN" }}| Field | Type | Required | Description |
|---|---|---|---|
connect-src | string[] | No | Domains the app can make network requests to |
image-src | string[] | No | Domains the app can load images from |
purpose | string | Yes | Explanation of why these external connections are needed |
Caution
Only include domains that your app actually needs to connect to. Excessive CSP entries may trigger additional review scrutiny.
PostInstallAction
Configures what happens immediately after a user installs your app:
{ "post_install_action": { "type": "onboarding" }}| Field | Type | Required | Description |
|---|---|---|---|
type | string | Yes | The action type (see below) |
url | string | Conditional | URL for external type actions |
Action Types
| Type | Behavior |
|---|---|
"onboarding" | Opens the app’s onboarding view in the Dashboard |
"settings" | Opens the app’s settings view in the Dashboard |
"external" | Redirects the user to an external URL (requires url field) |
Examples:
// Open onboarding flow{ "post_install_action": { "type": "onboarding" }}
// Open settings page{ "post_install_action": { "type": "settings" }}
// Redirect to external setup{ "post_install_action": { "type": "external", "url": "https://app.tajo.io/stripe/setup" }}See the Post-Install Actions guide for detailed implementation patterns.
Constants
Define static key-value pairs accessible at runtime in your app:
{ "constants": { "API_BASE_URL": "https://api.tajo.io/v1", "SYNC_INTERVAL_SECONDS": "300", "MAX_BATCH_SIZE": "100" }}- All values must be strings
- Constants are embedded in the app at build time
- Use constants for configuration that varies between environments
- Never store secrets or API keys as constants — use the Secret Store API instead
Access constants in your app code:
import { constants } from '@stripe/ui-extension-sdk/constants';
const apiUrl = constants.API_BASE_URL;Extended Manifest for Development
During local development, additional fields are available:
{ "id": "com.tajo.brevo-integration", "version": "0.1.0", "name": "Tajo for Brevo (Dev)", "icon": "./assets/icon-dev.png", "distribution_type": "private", "sandbox_install_compatible": true, "dev": { "hot_reload": true, "port": 4242 }}The dev section is stripped during production builds and app uploads. Use it for local development convenience settings only.
Validation
Validate your manifest before uploading:
# Validate manifest syntax and schemastripe apps validate
# Check for common issuesstripe apps checkCommon validation errors:
| Error | Cause | Fix |
|---|---|---|
Invalid permission | Unknown permission identifier | Check the Permissions Reference |
Invalid viewport | Unknown viewport identifier | Check the Viewports Reference |
Missing purpose | Permission without purpose field | Add a purpose string to each permission |
Invalid version | Non-semver version string | Use format MAJOR.MINOR.PATCH |
Icon not found | Icon path doesn’t resolve | Verify the icon file exists at the specified path |