Manifest
Every Appnest app includes a manifest.json at the project root. It tells the platform where the UI runs, which server functions exist, which events they handle, what to collect at install via installation_parameters, OAuth needs, and which outbound URLs are allowed.
This page is the canonical reference for that file: required shape, rules, field definitions, and a full structural example. Keep the manifest aligned with app-backend/server.js—every backend_api_functions key and every event handler must name a real export from that file.
Structure (summary)
| Level | Keys |
|---|---|
| Top-level | Only platform_version, parent_product, and product_config. |
product_config.<product> | frontend_locations, whitelisted_domains, event_listener_functions, backend_api_functions, installation_parameters, oauth_config. |
<product>must matchparent_product(e.g.surveysparrow).- Do not duplicate the product-level keys at the top level.
product_configmay contain more than one product key in multi-product setups; each app still follows the same nested shape per key.
Use installation_parameters for install-time fields (values the admin provides when installing the app).
Rules
1. Event listeners
Declare handlers under product_config.<product>.event_listener_functions. Each object’s handler value must match an export from app-backend/server.js.
2. Scheduled functions
Scheduled jobs are configured in code (for example via $schedule) and validated at runtime. Ensure scheduler usage aligns with Scheduler (and platform) expectations; the manifest does not replace those declarations.
3. Backend API functions
Declare invokable server functions under product_config.<product>.backend_api_functions. Each key must match an export from app-backend/server.js. Use timeout (seconds) when the platform supports it.
4. OAuth
Apps that use OAuth MUST declare product_config.<product>.oauth_config with provider id(s) and the fields the platform expects (client_id, client_secret, authorize_url, token_url, and options such as scope).
5. Consistency
The manifest must reflect only real exports from app-backend/server.js. Mismatches between manifest and code are invalid.
Schema
Top-level keys
| Key | Type | Description |
|---|---|---|
platform_version | string | Platform version string the tooling expects (see templates and CLI output for the current value). |
parent_product | string | Parent product id (e.g. "surveysparrow"). |
product_config | object | Map of product id → config object. Keys should match products you target; primary app config usually sits under parent_product. |
product_config.<product>
All product-specific manifest content lives under one object per product id. Prefer snake_case for manifest keys.
| Key | Type | Description |
|---|---|---|
frontend_locations | object | Where the app is rendered. See Product Location. |
whitelisted_domains | string[] | Regex strings for allowed outbound URLs. See whitelisted_domains. |
event_listener_functions | object | Platform events → { handler }. See event_listener_functions. |
backend_api_functions | object | Exported function names → options (e.g. timeout). See backend_api_functions. |
installation_parameters | object | Install-time parameters. See installation_parameters. |
oauth_config | object | OAuth providers and credentials shape. See oauth_config. |
frontend_locations
Under product_config.<product>.frontend_locations. For screenshots and where each location id appears in the product UI, see Product Location.
"frontend_locations": {
"full_page_app": {
"url": "index.html",
"icon": "styles/images/icon.svg"
}
}
- Keys: Location ids where the product embeds your app, for example
full_page_app,builder_integrations_list,response_details,contact_details,new_survey_shares,contact_import,response_import,home_navigation,home_left_panel,survey_settings, and other ids the platform defines for your product. url: Relative path to the HTML entry (oftenindex.html).icon: Optional; relative path to an icon asset (e.g. SVG), typically used where the UI shows an app tile—use a square image (commonly 64×64) unless your team specifies otherwise.
whitelisted_domains
Under product_config.<product>.whitelisted_domains.
- Array of strings, usually regex patterns for allowed outbound URLs.
- Escape dots in hostnames when needed (e.g.
https://api\\.surveysparrow\\.com(/.*)?). - Include product domains, APIs, webhooks (e.g. Slack), and test hosts your app calls.
event_listener_functions
Under product_config.<product>.event_listener_functions.
"event_listener_functions": {
"onSubmissionComplete": {
"handler": "onSubmissionComplete"
},
"onContactCreate": {
"handler": "onSubmissionComplete"
}
}
- Keys: Platform event names.
- Values:
{ "handler": "<exportedFunctionName>" }. - The handler receives
{ payload }(shape depends on the event). - Multiple events, one function: reuse the same
handlerstring (second example above).
backend_api_functions
Under product_config.<product>.backend_api_functions.
"backend_api_functions": {
"getMappings": { "timeout": 10 },
"saveMapping": { "timeout": 15 }
}
- Keys: Names exported from
app-backend/server.js. - Values: Object with optional
timeout(number, seconds). Other options may exist per platform.
installation_parameters
Under product_config.<product>.installation_parameters.
"installation_parameters": {
"surveysparrow_api_key": {
"data-bind": "product.api_key",
"display_name": "SurveySparrow API Key",
"description": "Enter your SurveySparrow API key. You can find it under Settings → Apps & Integrations.",
"required": true,
"secure": true,
"type": "api_key"
},
"survey_api_base_url": {
"display_name": "SurveySparrow API base URL",
"description": "Optional. For example https://api.surveysparrow.com or your regional endpoint.",
"type": "text",
"required": false,
"default_value": "https://api.surveysparrow.com"
}
}
Each entry under installation_parameters is keyed by your parameter id (e.g. surveysparrow_api_key). Object fields:
| Field | Required | Values / notes |
|---|---|---|
| (parameter key) | Yes | String key identifying this install field. Your app reads values by this key after install (per platform APIs). |
display_name | Yes | String. Short label shown in the installation UI. |
description | Yes | String. Help text explaining what the installer should enter. |
type | Yes | String. Common values: api_key (product API key field), text (plain text). The platform may define other types—use what your tooling documents. |
required | Yes | Boolean. true if the installer must supply a value; false if optional. |
secure | No | Boolean. When true, the value is treated as sensitive (e.g. masked). Typical for secrets and api_key fields. |
default_value | No | String, number, or boolean (JSON). Prefilled value when the field is optional or you want a suggested default (e.g. a default API base URL). |
data-bind | No | String. Binding hint for the platform, e.g. product.api_key so the field is tied to the product’s stored API key. Use when documented for your product. |
oauth_config
Under product_config.<product>.oauth_config.
"oauth_config": {
"googleCalendar": {
"client_id": "...",
"client_secret": "...",
"authorize_url": "https://accounts.google.com/o/oauth2/auth",
"token_url": "https://oauth2.googleapis.com/token",
"options": {
"response_type": "code",
"access_type": "offline",
"prompt": "consent",
"scope": ["https://www.googleapis.com/auth/calendar"]
}
}
}
Each value under oauth_config is one provider configuration. Fields:
| Field | Required | Description |
|---|---|---|
| (provider key) | Yes | Object key is your provider id (e.g. googleCalendar). It must match how your app reads OAuth config at runtime. |
client_id | Yes | OAuth client identifier from the provider. |
client_secret | Yes | OAuth client secret from the provider. |
authorize_url | Yes | URL where the user is sent to authorize the app (authorization endpoint). |
token_url | Yes | URL used to exchange an authorization code for tokens (token endpoint). |
options | No | Nested object for extra OAuth query/body parameters. |
options.response_type | No | Typical value code for the authorization code flow. |
options.access_type | No | Provider-specific; e.g. offline so refresh tokens may be issued (Google). |
options.prompt | No | Provider-specific; e.g. consent to force the consent screen. |
options.scope | No | Array of scope strings the app requests (e.g. calendar API access). |
Provider keys are your ids (e.g. googleCalendar); each value is an object shaped like the table. Some providers or platform versions may support additional fields—use their docs when in doubt.
Quick reference
| Where | Key | Type | Purpose |
|---|---|---|---|
| Top-level | platform_version | string | "2.0" |
| Top-level | parent_product | string | e.g. "surveysparrow" |
| Top-level | product_config | object | Product id → config |
| Under product | frontend_locations | object | Location id → { url, icon? } |
| Under product | whitelisted_domains | string[] | URL regex patterns |
| Under product | event_listener_functions | object | { "<event>": { "handler": "<export>" } } |
| Under product | backend_api_functions | object | { "<export>": { "timeout"?: number } } |
| Under product | installation_parameters | object | Install-time parameter definitions |
| Under product | oauth_config | object | Per-provider OAuth fields |
Full example
Illustrative only—replace domain patterns, function names, param keys, and OAuth values for your app.
{
"platform_version": "2.0",
"parent_product": "surveysparrow",
"product_config": {
"surveysparrow": {
"frontend_locations": {
"full_page_app": {
"url": "index.html"
}
},
"whitelisted_domains": [
"https://(.*).signsparrow.com(.*)",
"https://(.*).surveysparrow.com(.*)",
"http://(.*).surveysparrow.test(.*)",
"https://hooks\\.slack\\.com(/.*)?",
"https://api\\.surveysparrow\\.com(/.*)?",
"https://api\\.signsparrow\\.com(/.*)?"
],
"event_listener_functions": {
"onSubmissionComplete": {
"handler": "onSubmissionComplete"
},
"onContactCreate": {
"handler": "onContactCreateHandler"
}
},
"backend_api_functions": {
"getMappings": { "timeout": 30 },
"saveMapping": { "timeout": 30 }
},
"installation_parameters": {
"surveysparrow_api_key": {
"data-bind": "product.api_key",
"display_name": "SurveySparrow API Key",
"description": "Enter your SurveySparrow API key.",
"required": true,
"secure": true,
"type": "api_key"
},
"survey_api_base_url": {
"display_name": "SurveySparrow API base URL",
"description": "Optional. For example https://api.surveysparrow.com",
"type": "text",
"required": false,
"default_value": "https://api.surveysparrow.com"
}
},
"oauth_config": {
"googleCalendar": {
"client_id": "...",
"client_secret": "...",
"authorize_url": "https://accounts.google.com/o/oauth2/auth",
"token_url": "https://oauth2.googleapis.com/token",
"options": {
"response_type": "code",
"access_type": "offline",
"prompt": "consent",
"scope": ["https://www.googleapis.com/auth/calendar"]
}
}
}
}
}
}
The onContactCreate example uses onContactCreateHandler to show a distinct export; you can point several events at the same handler name if one function handles them.