Skip to main content
The manifest tells Zend where your app lives, what it may do, and how its interactions behave. Keep it in your repo as zapp.json and deploy it with zend apps deploy. Each upload creates a new version and makes it active. Zend checks the whole file and returns every problem at once as 422 INVALID_MANIFEST with an errors[] list. Unknown fields are rejected at every level, so a typo fails loudly instead of being ignored.

Example

zapp.json

Fields

string
required
Your app slug. 2–31 characters of a-z, 0-9 and -, starting with a letter or digit. Must match the slug you created.
string
required
Shown to users. 1–24 characters, plain language (see Plain-language check).
string
required
Your own version label. Zend numbers uploads separately (v1, v2, …).
string[]
required
1–5 origins in the form https://host[:port]. No path, query or fragment, and not on usezend.app. Pages outside these origins open in the browser instead of inside Zend.
string
default:"/"
Path Zend opens by default. Must start with /.
"private" | "public"
default:"private"
public sends the app to review. See Public apps.
string[]
default:"[]"
What your app may ask for. See Permissions.
object[]
default:"[]"
Entries in the chat Apps tray. See chatActions.
string[]
default:"[]"
Card templates you post: result, invite, status. Needs post_card.
object
default:"{}"
Map of interaction type name to its state machine. See interactionTypes.
"contract" | "creator"
default:"contract"
Where group, event and prize money sits before payout. Public apps must use contract. See Custody.
string
https URL that receives webhooks.
object
Only cardsPerUserPerDay is supported. It can lower your tier’s cap, not raise it.
string
One line for Discover, up to 140 characters, plain language. Required for public apps.
string
Discover section: games, friends, events, community or tools.
object
{ name, support, privacy }. Required for public apps. support is an email or https URL; privacy is an https URL.
"none" | "app" | "checked"
default:"none"
How results are decided, shown on your listing. Must be app or checked if you use prize. See Public apps.
string
32-byte hex Ed25519 public key that signs prize results. Required with the prize permission. Generate one with zend apps resolver-key.
string[]
Reserved. Must be empty.

Permissions

Consent toggles start off. Users can change them later in Settings → Connected apps.

chatActions

When interaction is set, Zend creates that interaction with the other person in the chat and opens sheet?interaction=<id>.

interactionTypes

  • 1–12 unique states. initial and every terminal state must be in states.
  • At least one terminal state. Terminal states can’t have transitions.
  • Transitions reference known states only, and each move can be listed once.
  • A transition is either a state name, which any participant may make, or { "to": "<state>", "serverOnly": true }, which only your server may make with your app key. A page that tries it gets TRANSITION_SERVER_ONLY.
  • If you declare a state named expired, Zend moves unfinished interactions there at their deadline.
Use serverOnly for any move a player could fake by editing the page, such as declaring a winner. zend apps check lists every server-only move and catches a misspelt serverOnly, which would otherwise leave the move open to every player.

Plain-language check

name, chat action labels, description, developer.name and card text can’t contain these words: sui, blockchain, chain, crypto, token, usdc, stablecoin, gas, wallet, escrow, contract, zklogin, seed. Your users shouldn’t need to know how money moves. See the copy guide.

Check before you deploy

check runs the interaction-rule checks locally without uploading. deploy runs the same checks first. The server validates everything else on upload.