Skip to main content

Actions

Looking for the product view?
The Help Center explains this surface as users see it: Using Apps.

Action endpoints perform specific operations on apps like copying, printing, and more.

POST /api/apps/{id}/_copy

Create a copy of an app, including its library and all associated resources.

Authentication: Required

Permissions Required:

  • Member+ role (copy permission) on the source app
  • Member role (create permission) for apps

Path Parameters:

ParameterTypeDescription
idstringApp UUID or natural ID

Payload:

{
"name": "Sales Dashboard (Copy)",
"progress": "optional-progress-callback-id"
}

Payload Fields:

FieldTypeRequiredDescription
namestringNoName for the copy (default: original name)
progressstringNoProgress callback ID for tracking

Returns the copied app with status 201 Created and a Location header pointing to the new app.

Copy an AppPOST /api/apps/00000000-0000-4000-8000-000000000001/_copy
Clones the app, its library files, entity bindings, and environment rows; the caller becomes the owner. The workspace schema is NOT copied; it is recreated empty by the next migrate/deploy.
Request body
{
"name": "Order Desk (Staging)"
}
Response · 201
{
"_links": {
"self": {
"href": "https://informer.example.com/api/apps/admin%3Aorder-desk-staging"
},
"inf:owner": {
"href": "https://informer.example.com/api/apps/admin%3Aorder-desk-staging/owner"
},
"inf:draft": {
"href": "https://informer.example.com/api/apps/admin%3Aorder-desk-staging/draft"
},
"inf:app-shares": {
"href": "https://informer.example.com/api/apps/admin%3Aorder-desk-staging/shares"
},
"inf:app-tags": {
"href": "https://informer.example.com/api/apps/admin%3Aorder-desk-staging/tags"
},
"inf:favorite": {
"href": "https://informer.example.com/api/apps/admin%3Aorder-desk-staging/favorite"
},
"inf:app-tag": {
"href": "https://informer.example.com/api/apps/admin%3Aorder-desk-staging/tags/{tagId}",
"templated": true
},
"inf:export-bundle": {
"href": "https://informer.example.com/api/apps/admin%3Aorder-desk-staging/_export"
},
"inf:cloud-publish": {
"href": "https://informer.example.com/api/apps/admin%3Aorder-desk-staging/_cloud-publish"
},
"inf:copy": {
"href": "https://informer.example.com/api/apps/admin%3Aorder-desk-staging/_copy"
},
"inf:print": [
{
"href": "https://informer.example.com/api/apps/admin%3Aorder-desk-staging/_print"
},
{
"href": "https://informer.example.com/api/apps/admin%3Aorder-desk-staging/_print",
"title": "Print to PDF"
}
],
"inf:migrate": {
"href": "https://informer.example.com/api/apps/admin%3Aorder-desk-staging/_migrate"
},
"inf:deploy": {
"href": "https://informer.example.com/api/apps/admin%3Aorder-desk-staging/_deploy"
},
"inf:app-tokens": {
"href": "https://informer.example.com/api/apps/admin%3Aorder-desk-staging/tokens"
},
"inf:app-roles": {
"href": "https://informer.example.com/api/apps/admin%3Aorder-desk-staging/roles"
},
"inf:app-dependencies": {
"href": "https://informer.example.com/api/apps/admin%3Aorder-desk-staging/dependencies"
},
"inf:app-dependency": {
"href": "https://informer.example.com/api/apps/admin%3Aorder-desk-staging/dependencies/{name}",
"templated": true
},
"inf:app-environment": {
"href": "https://informer.example.com/api/apps/admin%3Aorder-desk-staging/environment"
},
"inf:app-environment-var": {
"href": "https://informer.example.com/api/apps/admin%3Aorder-desk-staging/environment/{key}",
"templated": true
},
"inf:app-suggest-icon": {
"href": "https://informer.example.com/api/apps/admin%3Aorder-desk-staging/_suggest-icon"
},
"inf:app-modernize-manifest": {
"href": "https://informer.example.com/api/apps/admin%3Aorder-desk-staging/_modernize-manifest"
},
"inf:app-draft-diff": {
"href": "https://informer.example.com/api/apps/admin%3Aorder-desk-staging/draft/_diff"
},
"edit": {
"href": "https://informer.example.com/api/apps/admin%3Aorder-desk-staging/_edit"
},
"inf:app-share": {
"href": "https://informer.example.com/api/apps/admin%3Aorder-desk-staging/shares/{principalId}",
"templated": true
},
"inf:entrypoint": {
"href": "https://informer.example.com/api/apps/admin%3Aorder-desk-staging/view/",
"title": "index.html"
},
"inf:library": {
"href": "https://informer.example.com/api/libraries/00000000-0000-4000-8000-000000000002",
"title": "App Files"
},
"inf:library-contents": {
"href": "https://informer.example.com/api/libraries/00000000-0000-4000-8000-000000000002/contents/index.html",
"title": "Raw Contents"
},
"share": {
"href": "https://informer.example.com/api/apps/admin%3Aorder-desk-staging/view/?token=%7Btoken%7D",
"title": "Share Page"
}
},
"naturalId": "admin:order-desk-staging",
"isManaged": true,
"permissions": {
"assignTags": true,
"bind": true,
"changeOwner": true,
"copy": true,
"delete": true,
"edit": false,
"manage": true,
"purge": true,
"restore": true,
"run": true,
"share": true,
"switchRoles": true,
"write": true
},
"id": "00000000-0000-4000-8000-000000000003",
"type": "app",
"name": "Order Desk (Staging)",
"tenant": "acme",
"ownerId": "admin",
"slug": "order-desk-staging",
"description": "Track and fulfill open orders",
"defn": {
"entryPoint": "index.html"
},
"settings": {
"sandbox": true,
"passDatasets": true
},
"origin": "deployed",
"source": null,
"sourceId": null,
"shared": false,
"defnUpdatedAt": null,
"libraryId": "00000000-0000-4000-8000-000000000002",
"webhookSecret": "encrypted:iv:0000000000000000",
"dbRolePassword": "encrypted:iv:0000000000000000",
"deletedAt": null,
"editingId": null,
"deployedAt": "2026-01-15T16:20:00.000Z",
"editingSession": null,
"editingHeartbeatAt": null,
"editingLockedBy": null,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"folderId": null,
"contentModifiedAt": "2026-01-15T16:20:00.000Z"
}
Captured from the API examples test suite; ids and timestamps are normalized.

Copy Behavior:

The copy operation duplicates:

  • All app metadata (name, description, defn, settings)
  • The embedded library (if present) with all files
  • All entity-binding rows (app_entity: dependency slots and whitelist entries)
  • Environment variable rows, encrypted values included (same tenant, so the ciphertext stays valid)
  • The copy is owned by the current user, is not shared by default, and gets a new UUID and slug

Not Copied:

  • Shares (AppShare records)
  • Tags (TagEntity records)
  • The workspace schema and its data (recreated empty by the next migrate/deploy)
  • Agents (AppAgent records — re-created on next deploy)
  • Favorite status
  • Edit history
  • Tokens

Library Copy:

If the app has an embedded library (libraryId):

  1. A new library is created with the name "{original name} (Copy)"
  2. All files from the original library are copied to the new library
  3. The new app references the new library
  4. The copy is fully independent (editing one doesn't affect the other)

Error Responses:

  • 400 Bad Request - Invalid payload or copy operation failed
  • 404 Not Found - App doesn't exist or user lacks access
  • 403 Forbidden - User lacks copy or create permission

Transaction Safety:

The entire copy operation runs in a database transaction. If any step fails, the entire operation is rolled back.


POST /api/apps/{id}/_print

Export an app as a PDF.

Authentication: Required

Permissions Required: Member role (run permission)

Path Parameters:

ParameterTypeDescription
idstringApp UUID or natural ID

Payload:

Print configuration depends on the app driver. For report apps:

{
"format": "letter",
"orientation": "portrait",
"margins": {
"top": 0.5,
"right": 0.5,
"bottom": 0.5,
"left": 0.5
},
"headerTemplate": "<div>...</div>",
"footerTemplate": "<div>...</div>",
"displayHeaderFooter": true,
"printBackground": true
}

Common Payload Fields:

FieldTypeDefaultDescription
formatstring"letter"Paper format (letter, legal, a4, etc.)
orientationstring"portrait"Page orientation (portrait, landscape)
marginsobject{}Page margins in inches
printBackgroundbooleantrueInclude background graphics

Response:

Returns a PDF file as a binary stream.

HTTP/1.1 200 OK
Content-Type: application/pdf
Content-Disposition: attachment; filename="Sales Dashboard.pdf"

[PDF binary data]

Use Cases:

  • Export dashboards for offline viewing
  • Generate reports for email distribution
  • Archive app snapshots
  • Print physical copies

Implementation Notes:

  • Uses headless Chrome/Puppeteer for rendering
  • Captures the current state of the app
  • Respects app's CSS print styles
  • May timeout for very complex apps

Error Responses:

  • 404 Not Found - App doesn't exist or user lacks access
  • 403 Forbidden - User lacks run permission
  • 500 Internal Server Error - PDF generation failed

Other Actions

Export Bundle

Apps can be exported as bundles (not yet documented in routes).

Route: GET /api/apps/{id}/_export

Use Case: Export app and its library as a portable bundle for backup or transfer.

Cloud Publish

Apps can be published to cloud services (not yet documented in routes).

Route: POST /api/apps/{id}/_cloud-publish

Use Case: Publish app to external hosting or app marketplaces.


Common Action Patterns

Copy and Modify

// 1. Copy the app
const copy = await POST('/api/apps/analytics:sales-dashboard/_copy', {
name: 'Sales Dashboard - Modified'
});

// 2. Edit the copy
await POST(`/api/apps/${copy.id}/_edit`);

// 3. Modify files in the draft
await PUT(`/api/apps/${draftId}/contents/index.html`, {
content: modifiedHTML
});

// 4. Commit changes
await POST(`/api/apps/${copy.id}/draft/_commit`);

Create PDF Archive

// Generate PDF of current state
const pdf = await POST('/api/apps/analytics:sales-dashboard/_print', {
format: 'letter',
orientation: 'landscape',
printBackground: true
});

// Save to file or send via email
await fs.writeFile('dashboard-archive.pdf', pdf);

Copy to Different Owner

// 1. Copy the app (owned by current user)
const copy = await POST('/api/apps/analytics:sales-dashboard/_copy', {
name: 'Sales Dashboard - Marketing Copy'
});

// 2. Transfer ownership to Marketing team
await PUT(`/api/apps/${copy.id}/owner`, {
teamId: 'marketing'
});

Batch Copy

// Copy multiple apps
const sourceApps = [
'analytics:sales-dashboard',
'analytics:customer-report',
'analytics:inventory-tracker'
];

const copies = [];
for (const appId of sourceApps) {
const copy = await POST(`/api/apps/${appId}/_copy`, {
name: `${appId} (Backup ${new Date().toISOString()})`
});
copies.push(copy);
}

console.log(`Created ${copies.length} backups`);

Permissions Summary

ActionRequired PermissionDescription
CopyMember+ (copy) + Member (create)Copy source app and create new app
PrintMember (run)Generate PDF from app
Export BundleMember+ (write)Export app as bundle
Cloud PublishPublisher (share)Publish to external services