> ## Documentation Index
> Fetch the complete documentation index at: https://docs.noxus.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# 3. First Integration

> Define credentials and an integration for an external API

<Note>
  This is **part 3** of the [Your First Plugin](/developers/plugins/your-first-plugin) tutorial. Make sure you've completed [2. First Node](/developers/plugins/tutorial/first-node) first.
</Note>

Integrations handle authentication with external services. When your node needs to talk to an API that requires credentials, you define an integration so users can configure their keys securely in the Noxus UI.

## Define credentials and integration

Add to `weather_plugin/__init__.py`:

```python theme={null}
from typing import ClassVar

from noxus_sdk.integrations.base import BaseIntegration, BaseCredentials
from noxus_sdk.ncl import ConfigText, Parameter


class WeatherAPICredentials(BaseCredentials):
    type: ClassVar[str] = "weather_api"

    api_key: str = Parameter(
        default="",
        title="API Key",
        description="Your weather API key",
        display=ConfigText(),
    )

    def is_ready(self) -> bool:
        return bool(self.api_key)


class WeatherAPIIntegration(BaseIntegration[WeatherAPICredentials]):
    type = "weather_api"
    display_name = "Weather API"
    image = "https://cdn-icons-png.flaticon.com/512/1779/1779940.png"
```

### How it works

* **`BaseCredentials`** is a Pydantic model that defines the fields users fill in (API keys, tokens, URLs, etc.)
* **`is_ready()`** returns `True` when the credentials are valid enough to use — the UI shows this status
* **`BaseIntegration`** ties the credentials to a display name and icon that appear in workspace settings
* **`type`** must match between the credentials class and the integration class — this is the identifier used throughout

## Register the integration

Update the plugin class:

```python theme={null}
class WeatherPlugin(BasePlugin[WeatherPluginConfig]):
    # ... same metadata ...

    def nodes(self):
        return [GetWeatherNode]

    def integrations(self):
        return [WeatherAPIIntegration]
```

When the plugin is installed, this integration will appear in **Workspace Settings → Integrations** where users can enter their API key. Credentials are **encrypted** and stored by the platform — your plugin code never stores them.

## Integration anatomy

| Component           | Purpose                                                           |
| ------------------- | ----------------------------------------------------------------- |
| `type`              | Unique identifier for this integration (string)                   |
| `display_name`      | Human-readable name shown in the UI                               |
| `image`             | Icon URL for the integration tile                                 |
| `credentials_class` | Pydantic model (auto-set from the generic parameter)              |
| `is_ready()`        | Validation — returns `True` when credentials are usable           |
| `scopes`            | Optional list of permission scopes (for OAuth-style integrations) |
| `properties`        | Optional dict of extra metadata                                   |

## Credential field types

You can use any NCL display type for credential fields:

```python theme={null}
class MyCredentials(BaseCredentials):
    type: ClassVar[str] = "my_service"

    # Simple text input
    api_key: str = Parameter(
        default="",
        title="API Key",
        display=ConfigText(),
    )

    # Dropdown select
    region: str = Parameter(
        default="us-east-1",
        title="Region",
        display=ConfigSelect(values=["us-east-1", "eu-west-1", "ap-southeast-1"]),
    )

    # Toggle
    use_sandbox: bool = Parameter(
        default=False,
        title="Use Sandbox",
        display=ConfigToggle(),
    )
```

<Card title="Next: Use Integration in Node →" icon="arrow-right" href="/developers/plugins/tutorial/using-integrations">
  Wire the integration into your node to call a real API with credentials.
</Card>
