List your owned and shared apps, newest first
Paginated newest-first listing of apps the caller owns or has been granted access to. Use cursor (from the previous page) and limit to iterate. Each row carries its server revision, the role (owner | collaborator | end-user | viewer | team-admin | team-member), and a UUID-form url that redirects to the friendly owner-canonical URL.
GET
/appAuthorization
AuthorizationBearer token (chrm_user_*) · headerrequiredUser-scoped personal access token. Mint via `POST /api/token` after signing in, or via the device-pairing flow at `POST /api/pair/start`. Authorises everything the user can do.
Query parameters
limitintegermin 1 · max 100 · default: 50
cursorstringOpaque cursor returned as `nextCursor` from the previous page.
Responses
200Page of apps
appsobject[]requiredShow propertiesHide properties
Array of
objectidstring<uuid>rolestring`owner` = your app. `collaborator` = shared with you via an accepted invite (edit and run, never share/delete/transfer). `end-user` = shared use-and-write-data (run the app and write its data, but cannot edit the app source). `viewer` = shared read-only. `team-admin` / `team-member` = owned by a team you belong to. Non-owner rows carry the UUID-form `url`, which redirects to the owner-canonical URL.
Allowed:
ownercollaboratorend-userviewerteam-adminteam-membermanifestIdstringdisplayNamestringrevisionRevisionrequiredServer-owned app source revision. New apps start at 1, each successful source write advances it once, and historical null counters project as 0. `If-Match: "<N>"` and `expected_revision` carry this revision through its canonical concurrency grammar.
min 0
capabilitiescapabilitiesShow propertiesHide properties
capabilitiesurlstring<uri>createdAtstring<date-time>updatedAtstring<date-time>nextCursorstring | nullPass back as `cursor` query param to fetch the next page.
401Listing requires user-scoped auth (`chrm_user_*` or session).
okbooleanrequiredAllowed:
falseerrorobjectrequiredShow propertiesHide properties
kindstringrequiredStable enum-shaped error key. Branch on this for recovery flows.
Allowed:
not_foundunknown_operationoperation_not_foundoperation_failedunauthorizedsign_in_requiredtoken_expiredforbiddenforbidden_writestored_value_too_largestorage_fullinvalid_moduleinvalid_uiinvalid_route_schemainvalid_routes_shapecontract_migration_requiredinvalid_manifest_schemainvalid_manifest_exportsinvalid_requestinvalid_inputinvalid_outputunexpected_keyscapability_deniedcapability_errorexecutor_errorinvalid_call_shapealready_claimedduplicate_remixmanifest_not_foundpayload_too_largemodule_too_largeui_too_largedescription_too_longmissing_descriptioninvalid_descriptionrate_limitedimage_origin_deniedtoo_many_requestsexpiredalready_approvedanon_not_remixabletemplate_listing_incompletetemplate_media_invalidforbidden_template_editinvalid_if_matchprecondition_requiredrevision_mismatchinvalid_revisioncandidate_effects_unsupportedold_string_not_foundold_string_not_uniqueedits_too_largemanifest_id_conflictmanifest_id_immutabletext_too_largestructured_data_too_largeapp_not_foundfeedback_not_foundfeedback_has_no_reply_recipientasset_too_largeasset_count_exceededasset_quota_exceededasset_invalid_keyasset_invalid_content_typeasset_errorinvalid_idsse_cookie_expiredinvalid_secret_namesecret_too_largesecret_already_existssecret_not_foundinvalid_iconteam_slug_takenalready_membergrantee_not_foundinvite_cap_reachedread_onlyhandle_takeninvalid_handlename_takenapp_unclaimedlink_cap_reachedgrantee_is_ownergrantee_is_selfgrantee_already_has_accessalready_invitedroutine_limit_exceededinvalid_intervalop_requires_inputduplicate_routinemessagestringreasonstringSet on 401s to distinguish token failure modes when finer detail is needed. `token_revoked_post_claim` is the post-#1284 surface for a chrm_app_* that was invalidated by a claim — the `recovery` field on the same `error` object carries the self-contained pairing-recovery hint the agent should follow instead of creating a new app.
Allowed:
token_malformedtoken_unknowntoken_revokedtoken_revoked_post_claimrecoveryRecoveryPair | RecoveryRetry | RecoveryShrink | RecoveryRefetch | RecoveryFixRouteLabel | RecoveryOpenExisting | RecoveryRename | RecoveryMigrateContractSelf-contained recovery hint, branching on `kind`. Attached to error envelopes the agent can self-correct on: `pair` for `token_revoked_post_claim` 401s (#1284), `retry` for 429s, `shrink` for too-large / quota-exceeded 413s, `refetch` for 412 `revision_mismatch` / `invalid_if_match` / 428 `precondition_required`, `fix_route_label` for 403 `forbidden_write`, `open_existing` for 409 `duplicate_remix`, `rename` for 409 `manifest_id_immutable` / `manifest_id_conflict`, and `migrate_contract` for 422 `contract_migration_required`. Every `instructions` string is a single-paragraph, action-first walk-through. Inlined per ADR 2026-05-06-agent-facing-error-surfaces-self-contain-the-fix.
Show propertiesHide properties
One of:
RecoveryPair
kindstringrequiredAllowed:
pairstartstring<uri>requiredverification_urlstring<uri>requiredinstructionsstringrequiredRecoveryRetry
kindstringrequiredAllowed:
retryretry_after_secintegerrequiredSeconds to wait before retrying. Matches the `RateLimit-Reset` and `Retry-After` headers on the same response.
min 0
retry_after_urlstring<uri>requiredAbsolute URL to retry verbatim once the wait elapses.
instructionsstringrequiredRecoveryShrink
kindstringrequiredAllowed:
shrinkfieldstringrequiredWhich input tripped the cap.
Allowed:
moduleuistylesdescriptiontextstructured_dataasseteditssecretpayloadsize_bytesintegerrequiredmin 0
cap_bytesintegerrequiredmin 0
instructionsstringrequiredRecoveryRefetch
kindstringrequiredAllowed:
refetchrefetch_urlstring<uri>requiredAbsolute URL to GET for the fresh ETag before retrying with a corrected If-Match.
instructionsstringrequiredRecoveryFixRouteLabel
kindstringrequiredAllowed:
fix_route_labelinstructionsstringrequiredApp-code recovery: the fix is in the route declaration, NOT in the request. Retrying the same request will fail again.
RecoveryOpenExisting
kindstringrequiredAllowed:
open_existingexisting_app_idstringrequiredexisting_urlstring<uri>requiredinstructionsstringrequiredRecoveryRename
kindstringrequiredAllowed:
renameinstructionsstringrequiredRecoveryMigrateContract
kindstringrequiredAllowed:
migrate_contractinstructionsstringrequiredTry it
Server
Authorization
Parameters
Request
curl -X GET "https://charm.ing/app" \
-H "Authorization: Bearer YOUR_TOKEN"const response = await fetch("https://charm.ing/app", {
method: "GET",
headers: {
"Authorization": "Bearer YOUR_TOKEN"
}
});import requests
response = requests.get(
"https://charm.ing/app",
headers={
"Authorization": "Bearer YOUR_TOKEN"
},
)Response
{
"apps": [
{
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"role": "owner",
"manifestId": "string",
"displayName": "string",
"revision": 4,
"capabilities": {
"imports": [
"charming:storage/[email protected]"
]
},
"url": "http://example.com",
"createdAt": "2019-08-24T14:15:22Z",
"updatedAt": "2019-08-24T14:15:22Z"
}
],
"nextCursor": "string"
}{
"ok": false,
"error": {
"kind": "not_found",
"message": "string",
"reason": "token_malformed",
"recovery": {
"kind": "pair",
"start": "http://example.com",
"verification_url": "http://example.com",
"instructions": "string"
}
}
}