Forge Window API (moved)
This page has moved to Forge API.
The window.requestForgePermissions, window.requestMarketplaceInstall, and window.openDeveloperIntegrations globals have been consolidated under window.forge.*. See the Forge API page for the current documentation.
window.requestForgePermissions
Prompt the current user to approve additional permissions at runtime. A modal consent dialog opens over the app, and the function resolves with the list of permissions the user actually granted.
When to use it
Use this when your app needs a permission that is not declared in runtime_permissions (or the user launching the app does not currently hold it). Common patterns:
- An action that is rarely needed and should not appear in the app's default token.
- An operation that requires explicit user acknowledgement before it runs.
Signature
| Parameter | Type | Required | Description |
|---|---|---|---|
permissions |
string[] |
✅ | Permission strings to request (e.g. 'orders.create'). |
reason |
string |
❌ | Human-readable explanation shown on the consent screen. |
Returns — a Promise<string[]> that resolves with the subset of requested permissions the user approved. Rejects if the user closes or dismisses the dialog.
Example
// Ask for a single permission before placing an order
try {
const granted = await window.requestForgePermissions(
['orders.create'],
'Required to submit the order on your behalf.'
)
if (granted.includes('orders.create')) {
await placeOrder(cart)
} else {
showError('Permission was not granted.')
}
} catch {
// User closed the dialog
}
Multiple permissions
const granted = await window.requestForgePermissions(
['customers.read', 'customers.update', 'tags.write'],
'Needed to tag customers based on their purchase history.'
)
const missing = ['customers.read', 'customers.update', 'tags.write']
.filter(p => !granted.includes(p))
if (missing.length) {
console.warn('Not all permissions were granted:', missing)
}
Token update
Once the user approves, the platform mints a new token that includes the granted permissions and posts it back. The SDK picks it up automatically — you do not need to refresh the page or re-initialise anything. The next API call made through the SDK will carry the updated token.
window.requestMarketplaceInstall
Prompt the current user to install a marketplace item (integration, app, or template) from within your app. A modal install dialog opens and the function resolves once the user completes (or already has completed) the installation.
When to use it
Use this when your app depends on another marketplace item and wants to guide the user through installing it without leaving your app's context.
Signature
window.requestMarketplaceInstall(
itemId: string,
itemType: 'integration' | 'app' | 'template',
options?: { initiator?: string }
): Promise<{ id: string; type: string; already_installed: boolean }>
| Parameter | Type | Required | Description |
|---|---|---|---|
itemId |
string |
✅ | The marketplace item ID. |
itemType |
'integration' \| 'app' \| 'template' |
✅ | The item category. |
options.initiator |
string |
❌ | Override the initiating app name (defaults to the current app). |
Returns — a Promise that resolves with:
| Field | Type | Description |
|---|---|---|
id |
string |
The installed item's ID. |
type |
string |
The item type as returned by the platform. |
already_installed |
boolean |
true if the item was already installed before the user opened the dialog. |
Rejects if the user cancels or closes the dialog.
Example
// Ensure a required integration is installed before proceeding
try {
const result = await window.requestMarketplaceInstall(
'smtp-integration',
'integration'
)
if (result.already_installed) {
console.log('Integration was already installed — continuing.')
} else {
console.log('Integration installed successfully.')
}
await initSmtp()
} catch {
// User cancelled the install dialog
showError('The required integration was not installed.')
}
Checking already_installed
The already_installed flag lets you distinguish between a fresh install and a user who had the item installed before opening the dialog. You can use it to skip a "setup complete" notification, for example:
const { already_installed } = await window.requestMarketplaceInstall(
'payment-gateway',
'integration'
)
if (!already_installed) {
await showWelcomeTour()
}
window.openDeveloperIntegrations
Open the platform's developer integrations management page in a modal overlay, directly from within your Forge app. The overlay closes when the user dismisses it, and the returned Promise resolves at that point.
When to use it
Use this when your app requires one or more integrations to be activated before it can operate, and you want to guide the user to the integrations screen without leaving the app context. Common pattern:
- A preflight check detects that required integrations are not yet active.
- Your app surfaces a blocked state and offers a direct "Open integrations" action.
- After the user activates the integrations and closes the overlay, your app re-runs its preflight check.
Signature
Returns — a Promise<void> that resolves when the user closes the integrations overlay. The function does not indicate which integrations were changed; your app should re-query its state after resolution.
Example
// In a preflight check — detect missing integrations and offer a fix action
const missing = await checkRequiredIntegrations()
if (missing.length > 0) {
// Show a blocked state UI, then:
document.getElementById('open-integrations').addEventListener('click', async () => {
await window.openDeveloperIntegrations()
// User closed the overlay — re-run preflight
await runPreflight()
})
}
Behaviour in ptkl forge dev
| Scenario | Behaviour |
|---|---|
--platform-url provided |
Opens a full modal overlay with the integrations page loaded from <platform-url>/admin/developer/integrations. |
--platform-url not provided |
Logs a warning and resolves immediately — no overlay is shown. |
Availability
All globals are injected by the platform iframe host. They are not available outside a Forge app context (e.g. in a standalone browser tab or during server-side rendering).
When developing locally with the Protokol Toolkit's ptkl forge dev command, all globals are shimmed automatically so you can call them during development without hosting the full platform. Pass --platform-url <url> to ptkl forge dev to enable the full overlay implementations.
Error handling
requestForgePermissions and requestMarketplaceInstall reject the returned Promise when the user dismisses the dialog. Always wrap calls in try/catch (or .catch()) to handle cancellation gracefully:
try {
await window.requestForgePermissions(['reports.export'])
} catch (err) {
// User closed the dialog — no action needed
}
openDeveloperIntegrations always resolves (never rejects), so no error handling is required for it.
Never make permissions a hard requirement
Your app should remain usable even if the user declines. Disable or hide the relevant action rather than blocking the entire app.