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

# Connection invitations

> Create revocable, auditable invitations for external contributors to create or reconnect utility connections — the replacement for magic links.

<Tip>
  **For platform users**: See [Invitations](/platform/data-input/invitations) to understand the end-user experience.
</Tip>

<Warning>
  **Connection invitations replace the legacy [Magic link integration](/developer-guide/magic-link-integration).** Invitations are the recommended path for all new integrations — they are database-backed, revocable, auditable, and support scoped email access. The magic-link endpoints are still available for backward compatibility but are marked `deprecated` in the OpenAPI spec.
</Warning>

Connection invitations let you expose Nectar's utility connection UI to your end users. They handle [multi-factor authentication](/developer-guide/mfa-integration) and complex login workflows that can't be completed through a basic API call — and unlike magic links, every invitation is tracked in Nectar's database and can be revoked, expired, or scoped to specific email addresses.

## How it works

1. Your server calls the Nectar API to create an **invitation**. The response includes an `invitationUrl`.
2. You share the URL with your end user — by email, in an embedded iframe, or as a direct link.
3. The user completes the connection flow (or credential update) through Nectar's hosted UI.
4. Nectar maintains secure access to the utility account and continuously collects bills and usage data.
5. Your server receives `connection.created.v2` and `connection.updated.v2` webhook events as the connection progresses.

Each invitation is a row in Nectar's database, so you can list, inspect, revoke, and audit them at any time.

## Invitation types

| Type        | Purpose                                          | Endpoint                                      |
| ----------- | ------------------------------------------------ | --------------------------------------------- |
| Contributor | Create a **new connection** for a company        | `POST /invitation/company/{company_id}`       |
| Reconnect   | Update credentials on an **existing connection** | `POST /invitation/connection/{connection_id}` |

Both return an `invitationUrl` you can share with the recipient.

## Create a contributor invitation

Use this when you want an external contributor to create a new utility connection.

<Steps>
  <Step title="Create the invitation">
    Call the create-invitation endpoint for the target company. The response contains `invitationUrl` and the invitation `id`.

    <CodeGroup>
      ```bash cURL theme={null}
      curl -X POST 'https://external.nectarclimate.com/v2.2/invitation/company/{companyId}' \
        -H 'X-API-Key: YOUR_SECRET_KEY' \
        -H 'Content-Type: application/json' \
        -d '{
          "allowedEmails": ["owner@example.com"],
          "expiresInSeconds": 604800,
          "maxUses": 1,
          "sendEmail": true,
          "prefill": {
            "url": "https://www.coned.com",
            "country": "US",
            "initialSites": ["{siteId}"],
            "utilityTypes": ["ELECTRICITY"],
            "connectionOwnerEmail": "owner@example.com"
          }
        }'
      ```

      ```python Python theme={null}
      import requests

      response = requests.post(
          f"https://external.nectarclimate.com/v2.2/invitation/company/{company_id}",
          headers={
              "X-API-Key": "YOUR_SECRET_KEY",
              "Content-Type": "application/json",
          },
          json={
              "allowedEmails": ["owner@example.com"],
              "expiresInSeconds": 604_800,
              "maxUses": 1,
              "sendEmail": True,
              "prefill": {
                  "url": "https://www.coned.com",
                  "country": "US",
                  "initialSites": [site_id],
                  "utilityTypes": ["ELECTRICITY"],
                  "connectionOwnerEmail": "owner@example.com",
              },
          },
      )
      invitation = response.json()
      invitation_url = invitation["invitationUrl"]
      invitation_id = invitation["id"]
      ```
    </CodeGroup>

    Key fields:

    | Field              | Description                                                                                                               |
    | ------------------ | ------------------------------------------------------------------------------------------------------------------------- |
    | `allowedEmails`    | Optional. If set, only these addresses can complete the invitation (email gate).                                          |
    | `expiresInSeconds` | Optional. When the invitation stops being usable. Omit for no expiration.                                                 |
    | `maxUses`          | Optional. Cap the number of times the invitation can be redeemed. Omit for unlimited.                                     |
    | `sendEmail`        | If `true`, Nectar emails each address in `allowedEmails` with a pre-verified link.                                        |
    | `prefill`          | Optional. Pre-fill the provider (by `datasourceId` or `url`), country, sites, utility types, owner email, and start date. |
  </Step>

  <Step title="Share the invitation URL">
    The response's `invitationUrl` follows this shape:

    ```
    https://dash.nectarclimate.com/p/i/{token}
    ```

    Share it however you like — in your own emails, chat, or an iframe in your product.

    <Note>
      The `/p/i/` prefix indicates a public (unauthenticated) page. The token is an opaque database-backed identifier — no encrypted payload is exposed in the URL.
    </Note>
  </Step>

  <Step title="Embed in an iframe (optional)">
    Display the invitation inside your product. Nectar's connection UI currently requires desktop-sized dimensions.

    ```html theme={null}
    <iframe
      src="https://dash.nectarclimate.com/p/i/{token}"
      width="1152"
      height="648"
      style="border: 0;"
    ></iframe>
    ```
  </Step>
</Steps>

## Create a reconnect invitation

Use this when an existing connection enters an error state (`PASSWORD_INCORRECT`, `MFA_TOKEN_EXPIRED`, `NEW_PASSWORD_NEEDED`, etc.) and you want the account owner to update credentials or refresh MFA forwarding.

<Note>
  For `MFA_TOKEN_EXPIRED`, the reconnect wizard opens the MFA setup flow — not the password screen. It lets the end customer pick from the [MFA recommendation ladder](/developer-guide/mfa-integration#recommendation-ladder) (upload bills, disable MFA on the portal, or configure one of the forwarding strategies). The shareable one-pager in [MFA integration](/developer-guide/mfa-integration#shareable-one-pager) is written for end customers and can be forwarded directly.
</Note>

<Steps>
  <Step title="Create the reconnect invitation">
    Call the reconnect endpoint for the existing connection.

    <CodeGroup>
      ```bash cURL theme={null}
      curl -X POST 'https://external.nectarclimate.com/v2.2/invitation/connection/{connectionId}' \
        -H 'X-API-Key: YOUR_SECRET_KEY' \
        -H 'Content-Type: application/json' \
        -d '{
          "allowedEmails": ["owner@example.com"],
          "expiresInSeconds": 604800,
          "sendEmail": true
        }'
      ```

      ```python Python theme={null}
      import requests

      response = requests.post(
          f"https://external.nectarclimate.com/v2.2/invitation/connection/{connection_id}",
          headers={
              "X-API-Key": "YOUR_SECRET_KEY",
              "Content-Type": "application/json",
          },
          json={
              "allowedEmails": ["owner@example.com"],
              "expiresInSeconds": 604_800,
              "sendEmail": True,
          },
      )
      invitation = response.json()
      invitation_url = invitation["invitationUrl"]
      ```
    </CodeGroup>
  </Step>

  <Step title="Share the reconnect URL">
    The returned `invitationUrl` uses the same `/p/i/{token}` format as contributor invitations. The recipient lands on the edit-credentials flow for the existing connection — all historical data, account mappings, and site associations are preserved.
  </Step>
</Steps>

## Listing, inspecting, and revoking

```bash theme={null}
# List connection invitations for a company (filter by status and type)
GET /v2.2/invitation/company/{company_id}?status=ACTIVE

# Get full detail for a single invitation, including the activity log
GET /v2.2/invitation/{invitation_id}

# Revoke an active invitation (idempotent)
POST /v2.2/invitation/{invitation_id}/revoke
```

Invitation statuses:

| Status      | Meaning                                                        |
| ----------- | -------------------------------------------------------------- |
| `ACTIVE`    | The invitation can still be redeemed.                          |
| `EXPIRED`   | Past `expiresAt`. The recipient sees an "expired" message.     |
| `REVOKED`   | Explicitly revoked by your team or via `/revoke`.              |
| `FULFILLED` | All permitted uses have been consumed (`useCount == maxUses`). |

The detail endpoint returns an **event log** — every view, email verification, and submission — so you can audit what happened with each invitation.

## Prefilling data

The `prefill` object on contributor invitations supports:

| Field                     | Description                                                                                                                                                      |
| ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `datasourceId`            | UUID of a utility provider in the Nectar catalog. Locks the recipient to that provider. Discover IDs with `GET /v2.2/datasource`. Mutually exclusive with `url`. |
| `url`                     | Utility portal URL to preselect in the wizard. Use when the provider isn't in the catalog. Mutually exclusive with `datasourceId`.                               |
| `country`                 | ISO country code (e.g., `US`, `GB`).                                                                                                                             |
| `initialSites`            | Array of site UUIDs to pre-associate with the resulting connection.                                                                                              |
| `utilityTypes`            | Array of commodity types (`ELECTRICITY`, `GAS`, `WATER`, `WASTE`, `FUEL`, …).                                                                                    |
| `connectionOwnerEmail`    | Owner email used for notifications on the resulting connection.                                                                                                  |
| `dataCollectionStartDate` | ISO date for how far back to collect bills.                                                                                                                      |

Prefill data is stored in the invitation record and used to pre-populate the connection form — your recipient sees the values already filled in but can still change them.

<Note>
  Prefer `datasourceId` when the provider already exists in Nectar's catalog — it guarantees the recipient lands on the correct provider configuration (including any MFA handling Nectar has set up for that utility). Fall back to `url` only when the provider isn't in the catalog.
</Note>

### Find a datasource ID

Use the datasource search endpoint to look up a provider by name or URL. It returns a paginated list of `{ id, name, url }` entries — pass `id` as `prefill.datasourceId` when creating an invitation.

<CodeGroup>
  ```bash cURL theme={null}
  curl -G 'https://external.nectarclimate.com/v2.2/datasource' \
    -H 'X-API-Key: YOUR_SECRET_KEY' \
    --data-urlencode 'search=coned'
  ```

  ```python Python theme={null}
  import requests

  response = requests.get(
      "https://external.nectarclimate.com/v2.2/datasource",
      headers={"X-API-Key": "YOUR_SECRET_KEY"},
      params={"search": "coned"},
  )
  datasources = response.json()["datasources"]
  datasource_id = datasources[0]["id"]
  ```
</CodeGroup>

Query parameters:

| Parameter  | Description                                                                  |
| ---------- | ---------------------------------------------------------------------------- |
| `search`   | Optional. Case-insensitive substring match against the provider name or URL. |
| `page`     | Optional. Page number (default `1`).                                         |
| `pageSize` | Optional. Items per page (default `100`, max `500`).                         |

If you can't find a provider you expect to see, contact [support@nectarclimate.com](mailto:support@nectarclimate.com) — we can add it to the catalog.

## Migration from magic links

If you have an existing integration using magic links, switch the endpoints you call — the embed pattern on the page is unchanged.

| Legacy magic-link endpoint                      | Invitation replacement                        |
| ----------------------------------------------- | --------------------------------------------- |
| `POST /connection/company/{company_id}/link`    | `POST /invitation/company/{company_id}`       |
| `POST /connection/{connection_id}` (edit link)  | `POST /invitation/connection/{connection_id}` |
| (no equivalent — revocation not supported)      | `POST /invitation/{invitation_id}/revoke`     |
| (no equivalent — list not supported)            | `GET /invitation/company/{company_id}`        |
| (no equivalent — detail + events not supported) | `GET /invitation/{invitation_id}`             |

The old response `magicLinkUrl` is replaced with `invitationUrl` on the invitation responses. URLs now use `https://dash.nectarclimate.com/p/i/{token}` instead of the legacy `p/connect/...` path. Existing magic links continue to work — you do not need to migrate live links, only the endpoints your server calls when creating new links.

## Customization

Nectar supports white-label branding of the invitation iframe, including custom fonts, colors, and language localization. See the [White-label](/platform/premium/white-label) documentation or contact [support@nectarclimate.com](mailto:support@nectarclimate.com) for setup details.

## Security

Invitation tokens are opaque random identifiers stored in Nectar's database — they contain no payload and cannot be decoded. Authorization decisions (is it still active? is this email allowed?) happen server-side on every request, which is why revocation takes effect immediately.

* **Email gate.** When `allowedEmails` is set, the recipient must verify ownership of one of those addresses (via a one-click email link) before the invitation is redeemable.
* **Expiration.** `expiresAt` is enforced server-side.
* **Max uses.** `maxUses` is enforced atomically; concurrent redemptions don't race.
* **Audit trail.** Every view, email verification, and submission is logged and surfaced on the invitation detail endpoint.

## Next steps

<CardGroup cols={3}>
  <Card title="MFA integration" icon="shield-halved" href="/developer-guide/mfa-integration">
    Decision tree for MFA-protected utility accounts.
  </Card>

  <Card title="Webhooks" icon="bell" href="/developer-guide/webhooks">
    Get notified when a connection is created or updated.
  </Card>

  <Card title="Connection statuses" icon="circle-info" href="/developer-guide/connection-statuses">
    Understand the connection lifecycle.
  </Card>
</CardGroup>
