Skip to main content
This is part 4 of the Your First Plugin tutorial. Make sure you’ve completed 3. First Integration first.
Now let’s connect the node to the integration so it uses real credentials to call an external API.

Declare the integration dependency

Update the node class to reference the integration:
class GetWeatherNode(BaseNode[GetWeatherConfig]):
    node_name = "get_weather"
    title = "Get Weather"
    description = "Returns weather data for a given city"
    category = NodeCategory.DATA
    color = "#4A90E2"
    integrations = {"weather_api": ["api_key"]}  # integration_type: [required_fields]

    # ... same inputs/outputs ...

    async def call(self, ctx: RemoteExecutionContext, city: str) -> dict:
        import httpx

        # Get credentials from the execution context
        creds = ctx.get_integration_credentials("weather_api")
        api_key = creds.get("api_key", "")

        if not api_key:
            raise ValueError("Weather API key not configured")

        # Call the real API
        async with httpx.AsyncClient() as client:
            response = await client.get(
                "https://api.openweathermap.org/data/2.5/weather",
                params={"q": city, "appid": api_key, "units": "metric"},
            )
            response.raise_for_status()
            data = response.json()

        return {
            "temperature": f"{data['main']['temp']}°C",
            "description": data["weather"][0]["description"].capitalize(),
        }

What changed

  1. integrations = {"weather_api": ["api_key"]} — declares this node depends on the weather_api integration. The platform will show a connection prompt in the editor if credentials aren’t configured.
  2. ctx.get_integration_credentials("weather_api") — retrieves the decrypted credentials at runtime. Returns a dict with the fields from your BaseCredentials model.

How credentials flow

Credentials are never stored in the plugin. They’re decrypted by the platform at execution time and passed through the RemoteExecutionContext for that specific run.

Using multiple integrations

A node can depend on more than one integration:
class CrossPostNode(BaseNode[NodeConfiguration]):
    node_name = "cross_post"
    integrations = {
        "twitter": ["api_key", "api_secret"],
        "linkedin": ["access_token"],
    }

    async def call(self, ctx: RemoteExecutionContext, message: str) -> dict:
        twitter_creds = ctx.get_integration_credentials("twitter")
        linkedin_creds = ctx.get_integration_credentials("linkedin")

        # Use both sets of credentials...
        return {"status": "posted"}

Error handling for credentials

Always validate that credentials exist before using them:
async def call(self, ctx: RemoteExecutionContext, city: str) -> dict:
    creds = ctx.get_integration_credentials("weather_api")

    if not creds or not creds.get("api_key"):
        raise ValueError(
            "Weather API credentials not configured. "
            "Go to Workspace Settings → Integrations to add your API key."
        )

    # Safe to use credentials...

Next: Working with Files →

Read and create files from plugin nodes.