> ## 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.

# Connect to John Deere Operations Center API

> Connect John Deere Operations Center to Leaf. Create a developer app, complete the OAuth flow, and attach credentials to a Leaf user.

This tutorial walks through the John Deere OAuth flow: creating a developer application, obtaining user tokens, and attaching credentials to a Leaf user so Leaf can sync field boundaries, machine files, and field operations from John Deere Operations Center.

<Tip>
  The fastest way to connect John Deere is through [Magic Link](/components/magic-link) or [Leaf Link](/components/leaf-link), which handle the OAuth UI for you. This tutorial is for developers who need to build the OAuth flow into their own application.
</Tip>

## Before you start

* A Leaf account with API credentials and a valid token.
* A Leaf user created (see [Field Operations Quickstart](/guides/tutorials/field-operations-quickstart)).
* A John Deere developer account. Register at [developer.deere.com](https://developer.deere.com/) if you don't have one.

## Step 1: Create a John Deere application

Sign in to the [John Deere developer portal](https://developer.deere.com/), navigate to **My Applications**, and click **Create Application**.

Fill in your company information and select the APIs you need:

| Leaf product                     | Required John Deere APIs         |
| -------------------------------- | -------------------------------- |
| Base                             | Organizations, Webhook           |
| Field boundaries                 | Clients, Farm, Field, Boundaries |
| Machine files / field operations | Field Operations, Files          |
| Prescriptions (beta)             | Files                            |
| Machines (beta)                  | Machines                         |

After creation, note your **App ID** and **Shared Secret**. John Deere may take some time to approve API access.

### Enable webhook permissions

Leaf uses John Deere webhooks to receive real-time notifications when grower data changes, which means faster data delivery than polling alone. You need to explicitly request webhook access for your application:

1. In **My Applications**, select your application and click **Request Access**.
2. Navigate to **Precision Tech → Application**, open the **Operations Center - Webhook** menu.
3. Check both **Webhook Read** and **Webhook Write**.
4. Click **Submit Request**. Approval typically takes a few hours.

Without webhook permissions, Leaf still syncs data on a polling schedule (at least every 24 hours), but new data won't arrive in near-real-time.

## Step 2: Get the authorization URL

Redirect the grower to John Deere's OAuth consent page. Leaf provides a helper endpoint that constructs the URL:

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://johndeere-oauth2-helper.withleaf.io/get_url" \
    -H "Content-Type: application/json" \
    -d '{
      "clientKey": "your-john-deere-app-id",
      "clientSecret": "your-john-deere-secret",
      "clientRedirectUrl": "https://your-app.com/callback"
    }'
  ```

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

  response = requests.post(
      "https://johndeere-oauth2-helper.withleaf.io/get_url",
      json={
          "clientKey": "your-john-deere-app-id",
          "clientSecret": "your-john-deere-secret",
          "clientRedirectUrl": "https://your-app.com/callback"
      }
  )
  auth_url = response.json()["url"]
  ```

  ```javascript JavaScript theme={null}
  const res = await fetch("https://johndeere-oauth2-helper.withleaf.io/get_url", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      clientKey: "your-john-deere-app-id",
      clientSecret: "your-john-deere-secret",
      clientRedirectUrl: "https://your-app.com/callback",
    }),
  });
  const { url } = await res.json();
  ```
</CodeGroup>

Send the grower to the returned URL. After they authorize, John Deere redirects them to your `clientRedirectUrl` with a `code` parameter in the URL.

## Step 3: Exchange the code for tokens

Use the redirect URL (including the `code`) to get the user's tokens:

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://johndeere-oauth2-helper.withleaf.io/get_token" \
    -H "Content-Type: application/json" \
    -d '{
      "clientKey": "your-john-deere-app-id",
      "clientSecret": "your-john-deere-secret",
      "responseUrl": "https://your-app.com/callback?code=abc123",
      "clientRedirectUrl": "https://your-app.com/callback"
    }'
  ```

  ```python Python theme={null}
  tokens = requests.post(
      "https://johndeere-oauth2-helper.withleaf.io/get_token",
      json={
          "clientKey": "your-john-deere-app-id",
          "clientSecret": "your-john-deere-secret",
          "responseUrl": "https://your-app.com/callback?code=abc123",
          "clientRedirectUrl": "https://your-app.com/callback"
      }
  ).json()
  refresh_token = tokens["refreshToken"]
  ```

  ```javascript JavaScript theme={null}
  const tokenRes = await fetch(
    "https://johndeere-oauth2-helper.withleaf.io/get_token",
    {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        clientKey: "your-john-deere-app-id",
        clientSecret: "your-john-deere-secret",
        responseUrl: "https://your-app.com/callback?code=abc123",
        clientRedirectUrl: "https://your-app.com/callback",
      }),
    }
  );
  const { refreshToken } = await tokenRes.json();
  ```
</CodeGroup>

Save the `refreshToken`. You'll attach it to the Leaf user in the next step.

## Step 4: Grant organization access

The grower must explicitly share their organizations with your application. Redirect them to:

```
https://connections.deere.com/connections/{yourJohnDeereAppId}/select-organizations?redirect_uri={yourRedirectUrl}
```

On this page, the grower toggles on the organizations they want to share. Leaf can only sync data from allowed organizations.

## Step 5: Attach credentials to the Leaf user

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://api.withleaf.io/services/usermanagement/api/users/{leafUserId}/john-deere-credentials" \
    -H "Authorization: Bearer YOUR_LEAF_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
      "clientKey": "your-john-deere-app-id",
      "clientSecret": "your-john-deere-secret",
      "refreshToken": "the-refresh-token-from-step-3",
      "clientEnvironment": "STAGE"
    }'
  ```

  ```python Python theme={null}
  headers = {"Authorization": f"Bearer {leaf_token}"}

  response = requests.post(
      f"https://api.withleaf.io/services/usermanagement/api/users/{leaf_user_id}/john-deere-credentials",
      headers=headers,
      json={
          "clientKey": "your-john-deere-app-id",
          "clientSecret": "your-john-deere-secret",
          "refreshToken": refresh_token,
          "clientEnvironment": "STAGE"
      }
  )
  print(response.json())
  ```

  ```javascript JavaScript theme={null}
  const res = await fetch(
    `https://api.withleaf.io/services/usermanagement/api/users/${leafUserId}/john-deere-credentials`,
    {
      method: "POST",
      headers: {
        Authorization: `Bearer ${leafToken}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        clientKey: "your-john-deere-app-id",
        clientSecret: "your-john-deere-secret",
        refreshToken: refreshToken,
        clientEnvironment: "STAGE",
      }),
    }
  );
  console.log(await res.json());
  ```
</CodeGroup>

Set `clientEnvironment` to `STAGE` for sandbox testing or `PRODUCTION` once John Deere has approved your app for production. Leaf manages token refresh automatically after this point.

## Step 6: Confirm the credentials are attached

```bash theme={null}
curl "https://api.withleaf.io/services/usermanagement/api/users/{leafUserId}/john-deere-credentials" \
  -H "Authorization: Bearer YOUR_LEAF_TOKEN"
```

If this worked, Leaf returns the John Deere credential object for the Leaf user.

<Warning>
  John Deere sandbox rules: one test account, no more than five connected organizations, under 150,000 API calls/month, and no longer than 18 months in sandbox. Violating these can get your app revoked.
</Warning>

## What you built

You completed the John Deere OAuth flow and attached credentials to a Leaf user. Leaf now syncs field boundaries, machine files, and field operations from John Deere Operations Center. Data will appear in [field operations](/guides/tutorials/field-operations-quickstart) queries once processing completes.

For more details on the credentials schema and endpoints, see the [John Deere provider guide](/providers/john-deere) and the [provider credentials API reference](/api-reference/providers).
