Skip to content
Developer docs

App manifest

The manifest is your listing and your app's settings in one JSON object: the fields the listing form in the developer portal saves to your draft.

The form saves as you type, and only what changed: every field is optional on a save. Saving never submits.

Fields

Types and limits below are the ones the API enforces when you save. “Required to submit” rules are listed after the table.

FieldType and limitsWhat it is
namestring1 to 80 charactersThe app’s name on the store.
categorySlugstringup to 48 charactersOne of GET /api/public/store/v1/categories (bookings, food, selling, learning, events, listings, business, websites).
taglinestring | nullup to 60 charactersOne line under the name. Required to submit.
descriptionstring | nullup to 5000 charactersWhat the app does, in plain words. At least 40 characters to submit.
dataNotestring | nullup to 2000 charactersWhat the app stores about the owner’s customers and why. Shown under “Your data”. At least 20 characters to submit.
supportEmailstring | nullup to 254 characters, emailWhere buyers reach you. Falls back to your developer profile’s support email.
languagesstring[] | nullup to 30 itemsLanguage codes the app works in, e.g. en, es.
plans"website" | "app" | "business"[]up to 3 itemsEzyStudio plans the app works on. At least one to submit.
pricingModel"free" | "one_time" | "monthly" | "included"free, one_time or monthly. included is for EzyStudio’s own apps only (422 otherwise).
priceCentsinteger | null0 to 99900Price in cents for one_time and monthly: from the minimum paid app price (priceMinimum on the app, set by EzyStudio; $3 by default) to $999 (99900). A lower price is refused with E_PRICE_BELOW_MINIMUM (meta.minimumCents). An app already live below the minimum may keep or raise its price, never lower it. Cleared for free.
currency"USD"USD only for now.
customizationobjectWhat a buyer’s one-sentence customization may change. Defaults: colors, text and fields on, layout off.
customization.colorsbooleanColors and fonts.
customization.textbooleanNames, labels and copy.
customization.fieldsbooleanForm fields.
customization.layoutbooleanLayout and order of sections.
customization.samplestringup to 500 charactersAn example sentence for buyers.
includedany[]up to 50 itemsListing bullets: what the app includes (strings or objects, up to 50).
featuresany[]up to 50 itemsFeature cards on the listing, e.g. {icon, group, title, description} (up to 50).
setupStepsany[]up to 50 itemsSteps shown while the app installs. Strings or {title} / {label} objects; the first 6 are used.
madeForany[]up to 50 itemsKinds of businesses it is for (up to 50).
trySayingany[]up to 50 itemsExample customization sentences (up to 50).
changelogstring | nullup to 2000 charactersWhat’s new: release notes customers see on the listing’s changelog. Up to 2,000 characters. Required for every version after the first, optional on the first.
customerImpactstring | nullup to 2000 charactersWhat customers might lose: removed features, changed or deleted data, breaking changes. Up to 2,000 characters. Required after the first version unless customerImpactNone is true.
customerImpactNonebooleanTrue when nothing is removed or changed in a way customers lose (instead of customerImpact).
aiUpdateNotesstring | nullup to 8000 charactersUpdate instructions for the AI that applies the update to each customer’s customised copy: what changed since the previous version, data migrations, moved files, how to carry customisations over. Up to 8,000 characters. Required after the first version.
versionstringpattern ^\d{1,4}\.\d{1,4}(\.\d{1,4})?$The version number you propose: major.minor or major.minor.patch. Unique per app, and higher than the live version. A new draft starts at the next minor (1.0 → 1.1). EzyStudio confirms the final number when it publishes the version.
repoobject | nullWhere the app’s code comes from: a GitHub repository and branch of your developer team’s GitHub connection (connect it on the submit form). Saving it checks the branch’s latest commit against the bundle rules (422 E_BUNDLE_INVALID, meta.field: repo). At submit we freeze the branch’s latest commit: its files are what reviewers test and customers install. Required to submit. null clears it.
repo.installationIdRequiredinteger0 to 9007199254740991GitHub’s installation id, from the GitHub connection’s installations.
repo.repositoryIdRequiredinteger0 to 9007199254740991GitHub’s repository id (one the installation covers).
repo.branchRequiredstring1 to 255 charactersThe branch to take the code from.
repo.recheckbooleanCheck the branch’s latest commit again even when the pick is unchanged.
mediaobject[]up to 10 itemsReplaces the whole list. Up to 1 icon, 1 cover and 8 screenshots; order = position within each kind.
media[].kindRequired"icon" | "cover" | "screenshot"icon, cover or screenshot.
media[].keystringup to 512 charactersThe key from the presign answer (preferred).
media[].urlstringup to 1024 characters, uriOnly a URL this API returned for one of this app’s files. New outside URLs are refused.
media[].altTextstringup to 250 charactersRequired on every image to submit.
media[].titlestringup to 120 charactersOptional caption.
media[].widthinteger1 to 20000Pixels.
media[].heightinteger1 to 20000Pixels.

What submit needs

Saving accepts an unfinished draft. Submitting checks the draft and answers 422 E_DRAFT_INCOMPLETE with every problem in meta.problems, each with its field (first column; the manifest field it checks is in brackets when the name differs), the form step to fix it in and the message:

FieldRule to submitMessage
nameNot emptyGive your app a name
category (categorySlug)A category is setPick a category
taglineNot empty, 60 characters at mostAdd a short tagline
descriptionAt least 40 charactersDescribe what the app does in a sentence or two
dataNoteAt least 20 charactersSay what your app stores and why
plansAt least one planPick at least one plan
supportEmailSet here or on your developer profileAdd a support email so buyers can reach you
screenshots (media)1 to 8 screenshots, alt text on every imageAdd at least one screenshot · Add alt text to every screenshot
repoA GitHub repository and branch are picked under App code. Saving them checks the branch's latest commit against the bundle rules (E_BUNDLE_INVALID); submit freezes the latest commit.Connect GitHub and pick the repository and branch of your app's code
changelogAfter the first version: not empty (2,000 characters at most)Say what's new in this version
customerImpactAfter the first version: not empty (2,000 characters at most), or customerImpactNone is trueSay what customers might lose, or tick that nothing is removed
aiUpdateNotesAfter the first version: not empty (8,000 characters at most)Write the update instructions for the AI
versionAfter the first version: higher than the live versionUse a version number higher than 1.0
price (priceCents)For one_time and monthly: at least the minimum paid price EzyStudio sets ($3, 300, by default). Saving a lower price is refused (E_PRICE_BELOW_MINIMUM), and so is more than $999 (99900).Enter a price of $3 or more

Pricing fields

  • free: no price and no checkout. It installs on the plans you list in plans.
  • one_time: the buyer pays priceCents once.
  • monthly: the buyer pays priceCents every month until they cancel.
  • included: part of an EzyStudio plan. Only EzyStudio's own apps can use it; anything else answers 422 E_INVALID_PRICING.

plans lists the EzyStudio plans the app works on (website, app, business). It is shown on the listing and an install on any other plan is refused. Read more in Pricing and payouts.

Customization

Owners customize your app with one sentence. customization says which parts that sentence may touch: colors, text, fields, layout. Anything you switch off is skipped, and payments and stored customer data are always left alone. New apps start with colors, text and fields on and layout off. Try a sentence on the Customization step of the listing form before you submit: reviewers do the same.

How it is applied: EzyStudio installs your files as they are, then hands the sentence to the owner's own AI in their editor, with the parts it may change. The AI edits your settings file first (named in your bundle's ezystudio-app.json), so keep colors, text, fields and layout options there. An owner can change the sentence later; the same rules apply. See The bundle.

Example

A draft, as JSON
{
  "name": "Clinic Intake Forms",
  "categorySlug": "bookings",
  "tagline": "Friendly check-in forms patients fill in before their visit.",
  "description": "Send new patients a link to a friendly check-in form before their visit. They add their details and consent on their phone.",
  "dataNote": "Patient answers are stored in the clinic's own EzyStudio database, visible only to logged-in staff.",
  "supportEmail": "help@kilnlabs.test",
  "languages": ["en"],
  "plans": ["app", "business"],
  "pricingModel": "monthly",
  "priceCents": 1500,
  "currency": "USD",
  "customization": {"colors": true, "text": true, "fields": true, "layout": false,
                    "sample": "We're a family dental practice in Leeds, open Monday to Saturday."},
  "included": ["Check-in form", "Consent capture", "Staff inbox"],
  "features": [{"icon": "clipboard-list", "group": "Forms", "title": "Check-in form", "description": "Details, history and consent on any phone."}],
  "setupSteps": ["Install", "Describe your clinic", "Publish"],
  "madeFor": ["Clinics", "Dentists", "Physiotherapists"],
  "trySaying": ["Add a field for insurance number."],
  "version": "1.1",
  "changelog": "Patients can now sign the consent form on their phone.",
  "customerImpact": "The printable PDF form is gone. Forms already saved stay as they are.",
  "customerImpactNone": false,
  "aiUpdateNotes": "The consent step moved from Booking.astro into src/apps/clinic-intake/Consent.astro. Migration 20261029120000 adds app_clinic_intake_consents. Keep each clinic's colours and extra fields.",
  "repo": {"installationId": 51234567, "repositoryId": 81234567, "branch": "main"},
  "media": [
    {"kind": "icon", "key": "apps/42/icon/01jb2x4c1d.png", "altText": "Clinic Intake Forms icon"},
    {"kind": "screenshot", "key": "apps/42/screenshot/01jb2x5m3a.png", "altText": "The check-in form on a phone", "width": 1290, "height": 2796}
  ]
}
Media keys and your code

media[].key are the keys of images uploaded to EzyStudio, never links to images hosted elsewhere. The listing form fills them in when you add your images. Your code is not uploaded: repo names a repository and branch of your GitHub connection, and submit freezes that branch's latest commit. The repository's layout (ezystudio-app.json, files/, where files may go) is in The bundle; saving repo checks the latest commit, and so does submit; both answer 422 E_BUNDLE_INVALID with the reason.

Sample data for your review test site is not a listing field: name it in the bundle's ezystudio-app.json as sampleData. See Sample data for review.