Membrane Framework
Conceptual model of Membrane
Membrane Framework is used to define how your app or agent interacts with external apps.
Membrane Elements
Your app, external apps, and everything in between is represented in Membrane as Elements.
- External Apps for apps your product interacts with.
- Connectors are use to authenticate in and interact with external apps.
 - Integrations represent relationship between your product and a given external app: connector used, your OAuth parameters, application-level (global) webhooks, etc.
 - Connections are containers for credentials, configuration, and logic for accessing external apps on behalf of a specific customer.
 
 - Packages contain integration logic organized in specialized functional elements:
- Actions are used to make synchronous requests between apps.
 - External Events and Internal Events represent things that happen in external apps and your app respectively.
- External Event Subscriptions and Internal Event Subscriptions are responsible for getting specific streams of events.
 
 - Flows handle multi-step asynchronous logic triggered by events, via API, or on schedule.
 - Data Collections let you work with data in external apps as if it was a table in a database: read and write data, explore metadata, and subscribe to data change events.
 - Data Sources act as pointers to Data Collections, letting you build data-related logic not attached to a specific collection.
 - Field Mappings transform data when reading from or writing to Data Sources.
 - Data Links let you track relationships between data objects in your product and corresponding objects in external apps.
 - Internal Data Schemas represent data structures in your app.
 
 - Customers represent users, organizations, and other similar entities in your product.
 
Membrane Functions
Membrane Functions implement business logic inside Membrane Elements. For example, things like "run an action", "subscribe to event", or "search records in a data collections" are functions.
You can think of functions as pieces of code that run inside Membrane and have access to the relevant execution context: API clients, current customer and connection, current Membrane Element and its dependencies, etc.
In many cases, functions are pieces of code that look like this:
module.exports = async function({externalApiClient, input}) {
  // Do something
  externalApiClient.post('/some-endpoint', input)
  // Log things for visibility
  console.log('I am a log')
  // Return the result
  return 'I am function output'
}Additionally to Javascript / Typescript code, there are other more structured function types that offer more guardrails and simplicity at the expense of flexibility. You can find the list of available function types here: Functions.
Membrane Layers
Membrane Elements can exist on one of three layers:
- Protocol Layer (Universal Layer): elements that work across multiple external apps in a consistent way. They let you implement both standard cross-application protocols like MCP and bespoke protocols you need for interacting with the outside world. For example, if you need a consistent way to work with users in external apps or a standard way to download files, you would implement this with Protocol-layer elements.  These elements have neither 
integrationIdnorconnectionIdproperty set. - Integration Layer: elements related to a specific integrations. Elements in this layer define how you interact with a specific External App in a context of a specific Integration. These elements always have 
integrationIdproperty. - Connection Layer: elements related to a specific customer and connection. They can be defined either by you or by your customers directly. These elements always have 
connectionIdproperty. 
Implementations
Most protocol-layer elements need to be implemented for each individual integration. For example, protocol-level Action "Create Task" can define standard inputs and outputs used when creating tasks in external apps, but each integration requires its own API request and response mapping. To achieve this, you:
- Create a protocol-level Action that defines only input and output schemas, and possibly an implementation that uses other protocol-level elements like Data Sources and Field Mappings.
 - Create any number of integration-level Actions that have 
parentIdproperty pointing to the protocol-level action andintegrationIdproperty pointing to each integration you want to implement the action for. These actions contain application-specific implementations that fit the protocol-level definition. 
Customizations
Integration-layer elements may benefit from customization for each individual connection. For example, if you implemented an integration-layer Create Task action, each of your customers may want to configure different project id and tags to create tasks with. To achieve this, you can create any number of connection-level elements that point to the integration-level element with their parentId property and have a corresponding connectionId property. They will inherit the implementation from the integration-level element by default and then could be customized by you or your customers as much as needed.
If they are not customized, they will be automatically updated when their parent integration-layer element changes. If they are customized, they will not automatically update unless you reset them.
You can have multiple customizations of a given integration-layer element and differentiate them using a special property - instanceKey. For example, if you have have multiple projects in your app, you can create an instance of create-task action for each project, let your customers configure them differently, and identify the right one using instanceKey that matches the project id on your side.
Addressing Elements
Every element has the following identifying properties:
idthat is unique to a Membrane cluster.uuidthat is unique to the workspace and can be used to identify the same element when migrating it between workspaces.
Additionally, most but not all elements have key property that is human-readable and should be used to address elements in code (your product code on Membrane functions). When addressing elements in Membrane, you need to provide a selector that can be either id, uuid, or key of a given element.
Keys
Addressing elements by key is convenient, but requires a few rules to avoid naming conflicts:
- Protocol-layer elements must have unique key among their element type (i.e. you can't have two protocol-layer Actions with key 
create-task). - Integration-layer elements must have unique key among their type and integration (i.e. you can have one Action with key 
create-taskfor each integration). - Connection-level elements don't have keys (except ones inherited from their parent elements - see below).
 
When addressing integration-layer elements, you should always prefix the element key with integration key, i.e. if Action key is create-task and it belongs to integration with key github, you should address it as github.create-task to avoid accidental naming conflicts with other integrations.
Addressing implementations and customizations
When you need to address a specific implementation of protocol-layer element or customization of integration-level element, you can use the following request parameters:
integrationKeyorintegrationIdfor getting element belonging to a given integration.connectionIdfor getting element belonging to a given connection.layerthat can have valueintegrationorconnectionto get element for a specified layer.instanceKeyto address a specific instance of a connection-level customization.
Whenever possible, Membrane will try to guess the element you need. For example, if you request a connection-layer element and provide integrationKey, Membrane will find a default connection for the specified integration for the current customer and return it. If the current customer has no connections or multiple connections for the specified integration, an error will be returned. This lets you simplify requests based on your expected Membrane configuration (i.e. whether you allow multiple connections to the same integration per customer or if you have multiple instances of connection-layer elements per connection).
Updated about 12 hours ago
