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.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.
initialand everyterminalstate must be instates. - 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 getsTRANSITION_SERVER_ONLY. - If you declare a state named
expired, Zend moves unfinished interactions there at their deadline.
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.