> ## 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 Climate FieldView API

> Connect Climate FieldView to Leaf: register as a developer, complete the OAuth flow, and attach credentials to a Leaf user.

This tutorial walks through connecting Climate FieldView to Leaf so you can sync field boundaries, machine files, and field operations. You'll obtain developer credentials, run the OAuth flow, and attach the resulting provider credentials to a Leaf user.

<Tip>
  [Magic Link](/components/magic-link) and [Leaf Link](/components/leaf-link) handle the OAuth UI for you. This tutorial is for developers building the flow into their own application.
</Tip>

## Before you start

* A Leaf account with a valid API token.
* A Leaf user created.
* A Climate FieldView developer account. Register at [dev.fieldview.com](https://dev.fieldview.com/join-us/).
* After approval, you'll receive a `clientId`, `clientSecret`, and `apiKey`.

<Note>
  Before proceeding, email [developer@climate.com](mailto:developer@climate.com) to verify you have the correct scopes: `asHarvested:read`, `asPlanted:read`, `asApplied:read`, `fields:read`, `resourceOwners:read`, `farmOrganizations:read`.
</Note>

## Step 1: Get the authorization URL

Leaf constructs the OAuth URL for you. Send a POST to the Climate FieldView credentials endpoint:

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://api.withleaf.io/services/usermanagement/api/users/{leafUserId}/climate-field-view-credentials" \
    -H "Authorization: Bearer YOUR_LEAF_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
      "client_id": "your-cfv-client-id",
      "redirect_uri": "https://your-app.com/callback"
    }'
  ```

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

  headers = {"Authorization": f"Bearer {leaf_token}"}

  response = requests.post(
      f"https://api.withleaf.io/services/usermanagement/api/users/{leaf_user_id}/climate-field-view-credentials",
      headers=headers,
      json={
          "client_id": "your-cfv-client-id",
          "redirect_uri": "https://your-app.com/callback"
      }
  )
  auth_url = response.json()["url"]
  ```

  ```javascript JavaScript theme={null}
  const res = await fetch(
    `https://api.withleaf.io/services/usermanagement/api/users/${leafUserId}/climate-field-view-credentials`,
    {
      method: "POST",
      headers: {
        Authorization: `Bearer ${leafToken}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        client_id: "your-cfv-client-id",
        redirect_uri: "https://your-app.com/callback",
      }),
    }
  );
  const { url } = await res.json();
  ```
</CodeGroup>

Leaf returns a URL with the minimum required scopes. If you need write access (for prescriptions, soil data, or imagery upload), add a `scope` array to the request body:

```json theme={null}
{
  "client_id": "your-cfv-client-id",
  "scope": [
    "asHarvested:read", "asPlanted:read", "asApplied:read",
    "fields:read", "resourceOwners:read", "farmOrganizations:read",
    "fields:write", "rx:write", "soil:write", "imagery:write"
  ],
  "redirect_uri": "https://your-app.com/callback"
}
```

<Warning>
  The write scopes (`fields:write`, `rx:write`, `soil:write`, `imagery:write`) may require additional permissions from Climate FieldView. Confirm you're allowed to request them before generating a URL with them.
</Warning>

Redirect the grower to the returned URL. After authorization, Climate FieldView redirects back to your `redirect_uri` with a `code` parameter.

## Step 2: Exchange the code for tokens

POST to Climate FieldView's token endpoint with the code from the redirect:

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://api.climate.com/api/oauth/token" \
    -H "Authorization: Basic $(echo -n 'clientId:clientSecret' | base64)" \
    -H "Content-Type: application/x-www-form-urlencoded" \
    -d "code=THE_CODE_FROM_REDIRECT&redirect_uri=https://your-app.com/callback&grant_type=authorization_code"
  ```

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

  auth_string = base64.b64encode(
      f"{cfv_client_id}:{cfv_client_secret}".encode()
  ).decode()

  token_response = requests.post(
      "https://api.climate.com/api/oauth/token",
      headers={"Authorization": f"Basic {auth_string}"},
      data={
          "code": "THE_CODE_FROM_REDIRECT",
          "redirect_uri": "https://your-app.com/callback",
          "grant_type": "authorization_code"
      }
  )
  refresh_token = token_response.json()["refresh_token"]
  ```

  ```javascript JavaScript theme={null}
  const authString = btoa(`${cfvClientId}:${cfvClientSecret}`);

  const tokenRes = await fetch("https://api.climate.com/api/oauth/token", {
    method: "POST",
    headers: {
      Authorization: `Basic ${authString}`,
      "Content-Type": "application/x-www-form-urlencoded",
    },
    body: new URLSearchParams({
      code: "THE_CODE_FROM_REDIRECT",
      redirect_uri: "https://your-app.com/callback",
      grant_type: "authorization_code",
    }),
  });
  const { refresh_token } = await tokenRes.json();
  ```
</CodeGroup>

Save the `refresh_token`.

## Step 3: Attach credentials to the Leaf user

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://api.withleaf.io/services/usermanagement/api/users/{leafUserId}/climate-field-view-credentials" \
    -H "Authorization: Bearer YOUR_LEAF_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
      "clientId": "your-cfv-client-id",
      "clientSecret": "your-cfv-client-secret",
      "apiKey": "your-cfv-api-key",
      "refreshToken": "the-refresh-token-from-step-2"
    }'
  ```

  ```python Python theme={null}
  response = requests.post(
      f"https://api.withleaf.io/services/usermanagement/api/users/{leaf_user_id}/climate-field-view-credentials",
      headers=headers,
      json={
          "clientId": cfv_client_id,
          "clientSecret": cfv_client_secret,
          "apiKey": cfv_api_key,
          "refreshToken": refresh_token
      }
  )
  print(response.json())
  ```

  ```javascript JavaScript theme={null}
  const res = await fetch(
    `https://api.withleaf.io/services/usermanagement/api/users/${leafUserId}/climate-field-view-credentials`,
    {
      method: "POST",
      headers: {
        Authorization: `Bearer ${leafToken}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        clientId: cfvClientId,
        clientSecret: cfvClientSecret,
        apiKey: cfvApiKey,
        refreshToken: refresh_token,
      }),
    }
  );
  console.log(await res.json());
  ```
</CodeGroup>

Leaf manages token refresh automatically from this point.

## Step 4: Confirm the credentials are attached

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

If this worked, Leaf returns the Climate FieldView credential object for the Leaf user.

## What you built

You connected Climate FieldView to a Leaf user through the OAuth flow. Leaf now syncs field boundaries, machine files, and field operations from Climate FieldView. Query the data through the [field operations quickstart](/guides/tutorials/field-operations-quickstart) or the [machine files API](/api-reference/files).

For the credentials schema and management endpoints, see the [Climate FieldView provider guide](/providers/climate-fieldview) and the [provider credentials API reference](/api-reference/providers).
