πŸ“– Looking for karrio's legacy docs? Visit docs.karrio.io

App Manifest

The app manifest is the configuration file that defines your app’s metadata, permissions, assets, and components. This guide covers all manifest options and best practices.

Basic Structure

Every Karrio app must have a manifest.ts file that exports an AppManifest object:

manifest.ts
1import { AppManifest } from "@karrio/app-store/types"; 2 3export const manifest: AppManifest = { 4 id: "my-app", 5 name: "My App", 6 version: "1.0.0", 7 description: "A description of what this app does", 8 author: { 9 name: "Your Name", 10 email: "you@example.com", 11 website: "https://yourwebsite.com", 12 }, 13 permissions: ["manage_shipments"], 14 assets: { 15 icon: "./assets/icon.svg", 16 screenshots: ["./assets/screenshot1.png"], 17 readme: "./README.md", 18 }, 19 components: { 20 main: "./component.tsx", 21 }, 22};

Manifest Properties

Required Fields

id (string)

Unique identifier for your app. Must be lowercase, alphanumeric, and may contain hyphens.

1export const manifest: AppManifest = { 2 id: "shipping-optimizer", // βœ… Good 3 // id: 'Shipping_Optimizer', // ❌ Bad: uppercase and underscore 4 // id: 'shipping optimizer', // ❌ Bad: contains space 5};

name (string)

Human-readable name displayed in the UI.

1export const manifest: AppManifest = { 2 name: "Shipping Optimizer", // βœ… Good 3 // name: '', // ❌ Bad: empty string 4};

version (string)

Semantic version number following semver format.

1export const manifest: AppManifest = { 2 version: "1.0.0", // βœ… Good 3 version: "1.2.3-beta.1", // βœ… Good: pre-release 4 // version: '1.0', // ❌ Bad: incomplete version 5};

description (string)

Brief description of your app’s functionality.

1export const manifest: AppManifest = { 2 description: 3 "Optimize shipping routes and reduce costs with AI-powered recommendations", 4};

author (object)

Information about the app developer.

1export const manifest: AppManifest = { 2 author: { 3 name: "Acme Corp", 4 email: "support@acme.com", 5 website: "https://acme.com", // Optional 6 }, 7};

Assets Configuration

assets (object)

Defines static assets used by your app.

1export const manifest: AppManifest = { 2 assets: { 3 icon: "./assets/icon.svg", // Required: app icon 4 screenshots: [ 5 // Optional: screenshots for app store 6 "./assets/screenshot1.png", 7 "./assets/screenshot2.png", 8 "./assets/demo.gif", 9 ], 10 readme: "./README.md", // Optional: detailed documentation 11 }, 12};

Asset Requirements:

  • Icon: SVG format, 64x64px recommended
  • Screenshots: PNG/JPG format, 1200x800px recommended
  • README: Markdown format with app documentation

Components Configuration

components (object)

Defines React components for different app views.

1export const manifest: AppManifest = { 2 components: { 3 main: "./component.tsx", // Required: main app component 4 configuration: "./configuration.tsx", // Optional: settings component 5 widget: "./widget.tsx", // Optional: dashboard widget 6 onboarding: "./onboarding.tsx", // Optional: setup wizard 7 }, 8};

Permissions System

permissions (array)

Defines what Karrio APIs and data your app can access.

1export const manifest: AppManifest = { 2 permissions: [ 3 // App management permissions 4 "manage_apps", 5 6 // Carrier management permissions 7 "manage_carriers", 8 9 // Order management permissions 10 "manage_orders", 11 12 // Team management permissions 13 "manage_team", 14 15 // Organization owner permissions 16 "manage_org_owner", 17 18 // Webhook management permissions 19 "manage_webhooks", 20 21 // Data management permissions (includes tracking, analytics) 22 "manage_data", 23 24 // Shipment management permissions (includes addresses, parcels, rates) 25 "manage_shipments", 26 27 // System management permissions (includes users, system configuration) 28 "manage_system", 29 ], 30};

Permission Groups:

  • manage_apps - Full access to app management
  • manage_carriers - Full access to carrier configurations
  • manage_orders - Full access to order management
  • manage_team - Full access to team member management
  • manage_org_owner - Organization owner permissions
  • manage_webhooks - Full access to webhook management
  • manage_data - Full access to data, analytics, and audit logs
  • manage_shipments - Full access to shipments, addresses, parcels, tracking
  • manage_system - Full administrative access to system settings and users

API Routes Configuration

api (object)

Defines server-side API endpoints for your app.

1export const manifest: AppManifest = { 2 api: { 3 routes: { 4 // Basic CRUD operations 5 data: "./api/data/route.ts", 6 "data/[id]": "./api/data/[id]/route.ts", 7 8 // Webhook handlers 9 "webhooks/shopify": "./api/webhooks/shopify/route.ts", 10 "webhooks/stripe": "./api/webhooks/stripe/route.ts", 11 12 // External integrations 13 "integrations/oauth": "./api/integrations/oauth/route.ts", 14 "integrations/sync": "./api/integrations/sync/route.ts", 15 16 // Background jobs 17 "jobs/sync": "./api/jobs/sync/route.ts", 18 "jobs/cleanup": "./api/jobs/cleanup/route.ts", 19 }, 20 }, 21};

Settings Configuration

settings (object)

Defines configuration options for your app.

1export const manifest: AppManifest = { 2 settings: { 3 required_metafields: [ 4 { 5 key: "api_key", 6 type: "password", 7 label: "API Key", 8 description: "Your external service API key", 9 is_required: true, 10 }, 11 { 12 key: "webhook_url", 13 type: "url", 14 label: "Webhook URL", 15 description: "URL for receiving webhooks", 16 is_required: false, 17 }, 18 { 19 key: "sync_interval", 20 type: "number", 21 label: "Sync Interval (minutes)", 22 description: "How often to sync data", 23 default: "30", 24 min: 5, 25 max: 1440, 26 }, 27 { 28 key: "enabled_features", 29 type: "multi_select", 30 label: "Enabled Features", 31 description: "Select which features to enable", 32 options: [ 33 { value: "auto_sync", label: "Automatic Sync" }, 34 { value: "notifications", label: "Email Notifications" }, 35 { value: "analytics", label: "Analytics Tracking" }, 36 ], 37 }, 38 ], 39 default_configuration: { 40 sync_interval: "30", 41 enabled_features: ["auto_sync"], 42 }, 43 }, 44};

Metafield Types:

  • string - Text input
  • password - Password input (encrypted)
  • number - Numeric input
  • boolean - Checkbox
  • url - URL validation
  • email - Email validation
  • select - Dropdown selection
  • multi_select - Multiple selection
  • textarea - Large text input
  • json - JSON object input

Categories and Tags

category (string)

Primary category for app store organization.

1export const manifest: AppManifest = { 2 category: "shipping", // Primary category 3 tags: [ 4 // Additional tags for discovery 5 "optimization", 6 "automation", 7 "ai", 8 "cost-reduction", 9 ], 10};

Available Categories:

  • shipping - Shipping and logistics
  • ecommerce - E-commerce integrations
  • analytics - Analytics and reporting
  • automation - Workflow automation
  • utilities - Utility tools
  • integrations - Third-party integrations

Lifecycle Hooks

hooks (object)

Define lifecycle event handlers.

1export const manifest: AppManifest = { 2 hooks: { 3 install: "./hooks/install.ts", // Run on app installation 4 uninstall: "./hooks/uninstall.ts", // Run on app uninstallation 5 upgrade: "./hooks/upgrade.ts", // Run on app updates 6 configure: "./hooks/configure.ts", // Run on configuration changes 7 }, 8};

Environment Configuration

environment (object)

Define environment-specific settings.

1export const manifest: AppManifest = { 2 environment: { 3 development: { 4 api_base_url: "http://localhost:3000", 5 debug: true, 6 }, 7 staging: { 8 api_base_url: "https://staging-api.myapp.com", 9 debug: false, 10 }, 11 production: { 12 api_base_url: "https://api.myapp.com", 13 debug: false, 14 }, 15 }, 16};

Advanced Configuration

Conditional Features

Use conditional logic for complex app configurations:

1const manifest: AppManifest = { 2 id: "advanced-app", 3 name: "Advanced App", 4 version: "2.0.0", 5 6 // Conditional permissions based on app type 7 permissions: [ 8 "manage_shipments", 9 ...(process.env.NODE_ENV === "development" ? ["admin:debug"] : []), 10 ], 11 12 // Dynamic component loading 13 components: { 14 main: "./component.tsx", 15 ...(process.env.FEATURE_ANALYTICS === "enabled" && { 16 analytics: "./analytics.tsx", 17 }), 18 }, 19 20 // Environment-specific API routes 21 api: { 22 routes: { 23 data: "./api/data/route.ts", 24 ...(process.env.NODE_ENV !== "production" && { 25 debug: "./api/debug/route.ts", 26 }), 27 }, 28 }, 29};

Multi-tenant Configuration

Configure apps for multi-tenant scenarios:

1export const manifest: AppManifest = { 2 id: "multi-tenant-app", 3 name: "Multi-tenant App", 4 version: "1.0.0", 5 6 // Tenant-specific settings 7 settings: { 8 tenant_configuration: { 9 subdomain_required: true, 10 custom_branding: true, 11 isolated_data: true, 12 }, 13 required_metafields: [ 14 { 15 key: "tenant_id", 16 type: "string", 17 label: "Tenant ID", 18 description: "Unique identifier for this tenant", 19 is_required: true, 20 validation: { 21 pattern: "^[a-z0-9-]+$", 22 message: "Must be lowercase alphanumeric with hyphens", 23 }, 24 }, 25 ], 26 }, 27};

Validation and Schema

Add validation to your manifest:

1import { z } from "zod"; 2 3const manifestSchema = z.object({ 4 id: z.string().regex(/^[a-z0-9-]+$/, "Invalid app ID format"), 5 name: z.string().min(1).max(50), 6 version: z.string().regex(/^\d+\.\d+\.\d+/, "Invalid semver format"), 7 description: z.string().min(10).max(500), 8 permissions: z.array(z.string()), 9 components: z.object({ 10 main: z.string(), 11 configuration: z.string().optional(), 12 }), 13}); 14 15export const manifest: AppManifest = manifestSchema.parse({ 16 // Your manifest configuration 17});

Best Practices

1. Security Considerations

1export const manifest: AppManifest = { 2 // βœ… Request only necessary permissions 3 permissions: ["manage_shipments"], // Minimal permissions 4 5 // βœ… Validate sensitive configuration 6 settings: { 7 required_metafields: [ 8 { 9 key: "api_key", 10 type: "password", // Automatically encrypted 11 validation: { 12 pattern: "^sk_[a-zA-Z0-9]{24}$", 13 message: "Invalid API key format", 14 }, 15 }, 16 ], 17 }, 18};

2. Performance Optimization

1export const manifest: AppManifest = { 2 // βœ… Lazy load optional components 3 components: { 4 main: "./component.tsx", 5 analytics: "./analytics.tsx", // Loaded only when needed 6 }, 7 8 // βœ… Optimize asset loading 9 assets: { 10 icon: "./assets/icon.svg", // SVG for scalability 11 screenshots: ["./assets/screenshot1.webp"], // WebP for compression 12 }, 13};

3. Maintainability

βœ… Use constants for reusable values
1const APP_ID = "shipping-optimizer"; 2const API_VERSION = "v1"; 3 4export const manifest: AppManifest = { 5 id: APP_ID, 6 version: "1.0.0", 7 8 api: { 9 routes: { 10 [`${API_VERSION}/data`]: "./api/v1/data/route.ts", 11 [`${API_VERSION}/sync`]: "./api/v1/sync/route.ts", 12 }, 13 }, 14};

4. Documentation

Always include comprehensive documentation:

1export const manifest: AppManifest = { 2 assets: { 3 readme: "./README.md", // Detailed setup and usage instructions 4 }, 5 6 settings: { 7 required_metafields: [ 8 { 9 key: "api_key", 10 type: "password", 11 label: "API Key", 12 description: "Get your API key from https://example.com/settings/api", // Clear instructions 13 help_url: "https://docs.example.com/api-key-setup", // Link to documentation 14 }, 15 ], 16 }, 17};

Validation and Testing

Test your manifest configuration:

manifest.test.ts
1import { describe, it, expect } from "vitest"; 2import { manifest } from "./manifest"; 3 4describe("App Manifest", () => { 5 it("has valid ID format", () => { 6 expect(manifest.id).toMatch(/^[a-z0-9-]+$/); 7 }); 8 9 it("has semantic version", () => { 10 expect(manifest.version).toMatch(/^\d+\.\d+\.\d+/); 11 }); 12 13 it("has required components", () => { 14 expect(manifest.components.main).toBeDefined(); 15 }); 16 17 it("has valid permissions", () => { 18 const validPermissions = [ 19 "manage_apps", 20 "manage_carriers", 21 "manage_orders", 22 "manage_team", 23 "manage_org_owner", 24 "manage_webhooks", 25 "manage_data", 26 "manage_shipments", 27 "manage_system", 28 ]; 29 30 manifest.permissions.forEach((permission) => { 31 expect(validPermissions).toContain(permission); 32 }); 33 }); 34});

Next Steps