---
title: "App Manifest Reference | Tajo"
description: "Complete schema reference for the stripe-app.json manifest file used to configure Stripe Apps"
url: https://tajo.io/docs/stripe-apps/app-manifest/
markdown: https://tajo.io/docs/stripe-apps/app-manifest.md
lang: en-US
author: "Set Noa"
author_url: https://tajo.io/set-noa/
---

# App Manifest Reference

[Set Noa](https://tajo.io/set-noa/)

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.

Caution

**Status: planned, not built.** Tajo has no Stripe App, so nothing in this section can be installed today. The app identifiers, URLs and credentials on this page are illustrative placeholders, not live endpoints.

## Full Manifest Example

```json
{
  "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": "Read 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.example.com",
        "https://api.brevo.com"
      ],
      "image-src": [
        "https://cdn.example.com",
        "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.example.com/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:

```json
"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:

```json
"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:

```json
{
  "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](https://tajo.io/docs/stripe-apps/permissions)) |
| `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:

```json
{
  "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:

```json
{
  "viewport": "stripe.dashboard.customer.detail",
  "component": "CustomerDetailView"
}
```

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `viewport` | string | Yes | The Dashboard location where this view renders (see [Viewports Reference](https://tajo.io/docs/stripe-apps/viewports)) |
| `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:

```json
"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:

```json
{
  "content_security_policy": {
    "connect-src": [
      "https://api.example.com",
      "https://api.brevo.com"
    ],
    "image-src": [
      "https://cdn.example.com"
    ],
    "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:

```json
{
  "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:

```json
// 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](https://tajo.io/docs/stripe-apps/post-install) for detailed implementation patterns.

## Constants

Define static key-value pairs accessible at runtime in your app:

```json
{
  "constants": {
    "API_BASE_URL": "https://api.example.com/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:

```typescript
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:

```json
{
  "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:

```bash
# Validate manifest syntax and schema
stripe apps validate

# Check for common issues
stripe apps check
```

Common validation errors:

| Error | Cause | Fix |
| --- | --- | --- |
| `Invalid permission` | Unknown permission identifier | Check the [Permissions Reference](https://tajo.io/docs/stripe-apps/permissions) |
| `Invalid viewport` | Unknown viewport identifier | Check the [Viewports Reference](https://tajo.io/docs/stripe-apps/viewports) |
| `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 |
