This feature is only available in the Enterprise version

Apps

Set Up Install and Uninstall Events

Handle install and uninstall events for your Custom App.

A user finds your app in the Apps library, reviews the permissions it requests, and confirms the install. After that, Blnk Cloud sends an event to your app so you can provision the installation on your side.

Here’s what happens during installation:

  1. The user clicks Install from the app details page.
  2. The user reviews and approves the permissions.
  3. Blnk Cloud creates a scoped API key for the installation.
  4. Blnk Cloud sends the install event to your backend via the callback URL.
  5. Your app stores the install details and returns a 2xx response.
  6. If the response succeeds, the app becomes active in Cloud.

Handling the install event

An install event tells your app that a user has connected it to a specific workspace and Cloud instance. The install is already scoped to that context in Blnk. You do not receive a separate organization field in the callback.

Blnk Cloud sends a payload like this:

{
  "installed_app_id": "instapp_...",
  "app_id": "app_...",
  "instance_id": "inst_...",
  "api_key": "blnk_...",
  "api_key_prefix": "blnk_abc",
  "granted_permissions": ["data:read", "data:write"],
  "idempotency_key": "install:instapp_..."
}
FieldDescription
installed_app_idThe ID for this specific app installation.
app_idThe ID of the app that was installed.
instance_idThe Cloud instance where the app was installed.
api_keyThe scoped API key your backend uses to call Cloud APIs for this install.
api_key_prefixA safe prefix for identifying the key without exposing the full secret.
granted_permissionsThe permissions the user approved during installation.
idempotency_keyA unique key for this install event. Use it to avoid processing the same event twice.

Once you receive the install event, you need to save the install details so your backend can use them later.

For our Stripe Sync app, our install handler looks like this:

app.post("/api/callback", async (req, res) => {
  const event = req.body;

  if (event.idempotency_key?.startsWith("install:")) {

    // Never persist the raw api_key in your database. Encrypt it at rest (see Codebase setup).
    await installs.save({
      installed_app_id: event.installed_app_id,
      app_id: event.app_id,
      instance_id: event.instance_id,
      api_key_encrypted: encryptSecret(event.api_key),
      api_key_prefix: event.api_key_prefix,
      granted_permissions: event.granted_permissions,
      status: "active",
      idempotency_key: event.idempotency_key
    });

    return res.status(200).json({ ok: true });
  }
});

Handling the uninstall event

When a user uninstalls your app, Blnk Cloud sends an uninstall event to the same callback URL. If your app returns 2xx, Cloud marks the install uninstalled and revokes the app’s API key. If the callback fails, the uninstall does not complete and the API key remains valid.

Your app should use this event to stop treating the installation as active. You can also clean up any resources you created for that organization or instance.

{
  "installed_app_id": "instapp_...",
  "app_id": "app_...",
  "instance_id": "inst_...",
  "uninstalled_at": "2026-04-21T12:00:00Z",
  "idempotency_key": "uninstall:instapp_..."
}

For the Stripe Sync app, uninstalling should mark the installation as inactive so the backend stops using the stored install record.

app.post("/api/callback", async (req, res) => {
  const event = req.body;

  if (event.idempotency_key?.startsWith("uninstall:")) {
    await installs.update({
      installed_app_id: event.installed_app_id,
      status: "inactive"
    });

    return res.status(200).json({ ok: true });
  }
});

Handling duplicate events

Cloud sends one install or uninstall request per event, with a 10 second timeout. Your handler should still be safe to run more than once.

Use the idempotency_key to check whether you have already processed the event. If you have already processed the event, return a 200 response to avoid processing the event again:

app.post("/api/callback", async (req, res) => {
  const event = req.body;

  const existingEvent = await checkIfEventProcessed(event.idempotency_key);

  if (existingEvent) {
    return res.status(200).json({ ok: true });
  }

  // Process the event
});

Test the installation flow

Before moving to app development, test the install and uninstall flow from Cloud.

  1. Register your app.
  2. Install the app from the Apps library.
  3. Confirm your callback URL receives the install event.
  4. Confirm your callback URL returns a 2xx response.
  5. Confirm the install is active in your database.
  6. Uninstall the app from Cloud.
  7. Confirm your callback URL receives the uninstall event.
  8. Confirm the install is no longer active in your database.