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

# Leaf Link

> Embed Leaf Link widgets to let growers connect their John Deere, Climate FieldView, CNHi, CNHI FieldOps, AgLeader, Trimble, and other provider accounts and upload files.

Leaf Link is a set of drop-in UI widgets that handle two tasks: connecting your users' provider accounts and uploading machine files. Leaf provides React and Angular packages, with provider availability depending on the package and widget runtime.

## Widgets

Leaf Link includes two widgets:

* **Provider Connection** lets your users authenticate with CNHi, CNHI FieldOps, John Deere, Trimble, Climate FieldView, AgLeader, Raven Slingshot, Lindsay, and Stara from inside your application.
* **File Upload** lets your users drag-and-drop or browse for `.zip` files containing machine data. Leaf processes these files through the standard conversion pipeline.

Both widgets authenticate using a per-Leaf-user API key (not your API Owner bearer token). Create API keys via the [API Key endpoints](/api-reference/leaf-link).

## Prerequisites

1. A Leaf account with at least one Leaf user created.
2. A Leaf user API key (created via `POST /api-keys`).
3. For provider connection: provider app credentials registered with Leaf for each provider you want to enable.

## Provider setup

Each provider requires a one-time registration of your application credentials with Leaf. You also need to add `https://widget.withleaf.io` as a redirect/callback URL in the provider's developer portal.

| Provider                    | Redirect URL field          | Credentials needed                            |
| --------------------------- | --------------------------- | --------------------------------------------- |
| John Deere                  | Redirect URI                | `clientKey`, `clientSecret`                   |
| Climate FieldView           | (none required)             | `apiKey`, `clientId`, `clientSecret`          |
| CNHI (AFS Connect - Legacy) | App OAuth Callback URL(s)   | `clientId`, `clientSecret`, `subscriptionKey` |
| CNHI FieldOps               | App OAuth Callback URL(s)   | `clientId`, `clientSecret`, `subscriptionKey` |
| AgLeader                    | Redirection URL             | `privateKey`, `publicKey`                     |
| Trimble                     | Authentication Callback URL | `applicationName`, `clientId`, `clientSecret` |
| Raven Slingshot             | (none required)             | `apiKey`, `sharedSecret`                      |
| Lindsay                     | Redirect URI                | `clientId`, `clientSecret`                    |
| Stara                       | (none required)             | `user`, `pwd`                                 |

Register credentials by calling `POST /usermanagement/api/app-keys/{Provider}/{appName}` with the provider-specific fields.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST \
    -H 'Content-Type: application/json' \
    -H 'Authorization: Bearer YOUR_TOKEN' \
    -d '{"clientKey": "your-app-id", "clientSecret": "your-secret"}' \
    'https://api.withleaf.io/services/usermanagement/api/app-keys/JohnDeere/MyApp/PRODUCTION'
  ```

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

  TOKEN = "YOUR_TOKEN"
  endpoint = "https://api.withleaf.io/services/usermanagement/api/app-keys/JohnDeere/MyApp/PRODUCTION"
  headers = {"Authorization": f"Bearer {TOKEN}"}
  data = {"clientKey": "your-app-id", "clientSecret": "your-secret"}

  response = requests.post(endpoint, headers=headers, json=data)
  print(response.json())
  ```

  ```javascript JavaScript theme={null}
  const axios = require("axios");

  const TOKEN = "YOUR_TOKEN";
  const endpoint = "https://api.withleaf.io/services/usermanagement/api/app-keys/JohnDeere/MyApp/PRODUCTION";
  const headers = { Authorization: `Bearer ${TOKEN}` };
  const data = { clientKey: "your-app-id", clientSecret: "your-secret" };

  axios.post(endpoint, data, { headers }).then(res => console.log(res.data));
  ```
</CodeGroup>

## Installation

### React

```shell theme={null}
npm i @withleaf/leaf-link-react
```

**Provider Connection:**

```javascript theme={null}
import { Providers } from "@withleaf/leaf-link-react";

function App() {
  return (
    <Providers
      isDarkMode={false}
      companyName="Acme Ag"
      companyLogo="https://example.com/logo.svg"
      leafUser="your-leaf-user-id"
      apiKey="your-leaf-user-api-key"
    />
  );
}
```

**File Upload:**

```javascript theme={null}
import { FileUpload } from "@withleaf/leaf-link-react";

function App() {
  return (
    <FileUpload
      isDarkMode={false}
      companyName="Acme Ag"
      companyLogo="https://example.com/logo.svg"
      leafUser="your-leaf-user-id"
      apiKey="your-leaf-user-api-key"
      filesTimeRange={30}
    />
  );
}
```

### Angular

```shell theme={null}
npm i @withleaf/leaf-link-angular
```

**Provider Connection:**

```javascript theme={null}
import { ProvidersModule } from "@withleaf/leaf-link-angular";
```

```html theme={null}
<providers
  apiKey="your-leaf-user-api-key"
  leafUser="your-leaf-user-id"
  companyName="Acme Ag"
  companyLogo="https://example.com/logo.svg"
></providers>
```

**File Upload:**

```javascript theme={null}
import { FileUploadModule } from "@withleaf/leaf-link-angular";
```

```html theme={null}
<file-upload
  apiKey="your-leaf-user-api-key"
  leafUser="your-leaf-user-id"
  companyName="Acme Ag"
  companyLogo="https://example.com/logo.svg"
  [filesTimeRange]="30"
></file-upload>
```

## Properties

### Provider Connection

| Property           | Type                                                                      | Description                                                                         |
| ------------------ | ------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
| `apiKey`           | String                                                                    | Leaf user API key (required)                                                        |
| `leafUser`         | String                                                                    | Leaf user ID (required)                                                             |
| `companyName`      | String                                                                    | Your company name, displayed in the widget                                          |
| `companyLogo`      | String                                                                    | URL to your company logo (PNG, JPEG, or SVG)                                        |
| `isDarkMode`       | Boolean                                                                   | Enable dark mode. Default: `false`                                                  |
| `locale`           | String                                                                    | Force language: `en_US`, `pt_BR`, `es_ES`, or `fr_FR`. Defaults to browser language |
| `title`            | String                                                                    | Widget title. Default: "Select your integration"                                    |
| `showSearchbar`    | Boolean                                                                   | Show/hide the provider search bar. Default: `true`                                  |
| `allowedProviders` | `string[]`                                                                | Restrict the widget to a specific list of providers                                 |
| `fastMode`         | Boolean                                                                   | Enable the widget's fast mode behavior                                              |
| `applications`     | `Array<{ appName: string; provider: string; clientEnvironment: string }>` | Preload provider app settings for the widget                                        |

### File Upload

| Property         | Type    | Description                             |
| ---------------- | ------- | --------------------------------------- |
| `apiKey`         | String  | Leaf user API key (required)            |
| `leafUser`       | String  | Leaf user ID (required)                 |
| `companyName`    | String  | Your company name                       |
| `companyLogo`    | String  | URL to your company logo                |
| `isDarkMode`     | Boolean | Enable dark mode. Default: `false`      |
| `locale`         | String  | Force language                          |
| `title`          | String  | Text displayed at the top of the widget |
| `filesTimeRange` | Number  | Days of upload history to display       |

## Hooks

Both widgets expose hooks for tracking widget state in your application.

### Provider Connection hooks

Use `useLeaf()` from `@withleaf/leaf-link-react`:

| Hook                   | Type                                | Description                                       |
| ---------------------- | ----------------------------------- | ------------------------------------------------- |
| `providersConnected`   | `string[]`                          | Provider names connected after the flow completes |
| `providerWidgetStatus` | `{ code: number; message: string }` | Widget status: `-1` Error, `0` Started, `1` Done  |

### File Upload hooks

| Hook           | Type       | Description                          |
| -------------- | ---------- | ------------------------------------ |
| `leafBatchIds` | `string[]` | Batch IDs for each successful upload |

To use hooks in React, wrap your component tree with the `<Leaf>` context provider:

```javascript theme={null}
import { Leaf, Providers, useLeaf } from "@withleaf/leaf-link-react";

function StatusDisplay() {
  const { providerWidgetStatus, providersConnected } = useLeaf();
  return <pre>{JSON.stringify({ providerWidgetStatus, providersConnected }, null, 2)}</pre>;
}

function App() {
  return (
    <Leaf>
      <StatusDisplay />
      <Providers
        leafUser="your-leaf-user-id"
        apiKey="your-leaf-user-api-key"
        companyName="Acme Ag"
        companyLogo="https://example.com/logo.svg"
      />
    </Leaf>
  );
}
```

In Angular, use the `(getWidgetStatus)` output binding on the `<providers>` component.

<Note>
  The Angular package does not currently expose `Stara` in its provider list.
</Note>

## What to do next

* [Magic Link](/components/magic-link) for generating shareable authentication and upload links without embedding widgets.
* [Leaf Connect](/components/leaf-connect) for sharing data between API owners.
* [Leaf Link API Reference](/api-reference/leaf-link) for API key and app info endpoints.
