> ## 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 FarmEngage API

> Connect PTx FarmEngage (AGCO) data to Leaf. Request AGCO credentials, complete the OAuth flow, and attach credentials to a Leaf user.

This tutorial shows you how to connect PTx FarmEngage to Leaf so you can sync field boundaries, machine files, and field operations. You request AGCO developer credentials, run the OAuth flow, and attach the resulting provider credentials to a Leaf user.

> [!TIP]
>
> [Magic Link](https://docs.withleaf.io/components/magic-link.md) and [Leaf Link](https://docs.withleaf.io/components/leaf-link.md) handle the OAuth UI for you. This tutorial covers the manual flow for developers building it into their own application.

> [!NOTE]
>
> PTx has two API platforms. This tutorial covers connecting FarmEngage without an existing Trimble Agriculture connection. If you already have Trimble Agriculture connections, use [Migrate from Trimble to FarmEngage](https://docs.withleaf.io/guides/tutorials/migrate-trimble-to-farmengage.md). Attaching `farm-engage-credentials` beside `trimble-credentials` duplicates fields and files until you remove the Trimble credential. For the legacy Trimble API itself, see [Connect Trimble](https://docs.withleaf.io/guides/tutorials/connect-trimble.md).

## Before you start

* A Leaf account with a valid API token.
* An existing Leaf user.
* FarmEngage API access from PTx. Submit [PTx's API request form](https://www.ptxag.com/us/en/partners/developers/resources/request-apis.html). PTx sends an AGCO Client ID and Client Secret after approval.
* Your FarmEngage application's redirect URL registered with PTx. It must match `client_redirect_url` / `redirect_url` exactly, including trailing slashes.
* PTx API docs for the data plane: [api-docs.farmengage.com](https://api-docs.farmengage.com/).

> [!WARNING]
>
> These credentials are AGCO ID credentials. Existing Trimble Agriculture client IDs, secrets, and refresh tokens do not work.

## Step 1: Get the authorization URL

Leaf constructs the FarmEngage (AGCO ID) OAuth URL for you. The helper lives on the same host as the Trimble helper, under a `/farmengage` prefix:

```bash cURL theme={null}
curl -X POST "https://trimble-oauth2-helper.withleaf.io/farmengage/get_url" \
  -H "Content-Type: application/json" \
  -d '{
    "client_id": "your-agco-client-id",
    "client_redirect_url": "https://your-app.com/callback"
  }'
```

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

response = requests.post(
    "https://trimble-oauth2-helper.withleaf.io/farmengage/get_url",
    json={
        "client_id": "your-agco-client-id",
        "client_redirect_url": "https://your-app.com/callback"
    }
)
auth_url = response.json()["url"]
```

```javascript JavaScript theme={null}
const res = await fetch("https://trimble-oauth2-helper.withleaf.io/farmengage/get_url", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    client_id: "your-agco-client-id",
    client_redirect_url: "https://your-app.com/callback",
  }),
});
const { url } = await res.json();
```

The helper returns `{ "url": "..." }`. That URL sends the grower to AGCO ID (`onelogin.agcocorp.com`) with the `b2c_1a_signin_ptx` policy.

> [!NOTE]
>
> The redirect URL must match what PTx authorized for your application. Trailing slashes can cause failures.

Send a caller-generated `pass_through` string and persist it with the grower session. Leaf uses it as the OAuth `state` value. If the returned `state` query parameter does not match, reject the callback. If you omit `pass_through`, the helper generates one and you cannot verify the callback.

Redirect the grower to the returned URL. That URL sends them to AGCO ID sign-in only. Organization access is a separate FarmEngage ThirdPartyAccess step, not part of the OAuth URL. After attaching credentials, always `GET /users/{leafUserId}/organizations/FarmEngage`. If `connectedOrganizations` is empty, send the grower the `managementUri` from that response — that is the required grant step. See [provider organizations](https://docs.withleaf.io/providers/organizations.md).

After authorization, FarmEngage redirects to your `client_redirect_url` with a `code` parameter.

## Step 2: Exchange the code for tokens

> [!WARNING]
>
> The token helper field is `redirect_url`, not `client_redirect_url`. The value must still be the same registered callback URL you used in Step 1. `POST /farmengage/get_token` and `POST /users/{leafUserId}/farm-engage-credentials` must run on your server. Do not put `client_secret` or `refresh_token` in browser or mobile client code. The helper host is an unauthenticated Leaf-operated endpoint; `get_token` receives your AGCO `client_secret` and authorization code.

```bash cURL theme={null}
curl -X POST "https://trimble-oauth2-helper.withleaf.io/farmengage/get_token" \
  -H "Content-Type: application/json" \
  -d '{
    "client_id": "your-agco-client-id",
    "client_secret": "your-agco-client-secret",
    "code": "the-code-from-redirect",
    "redirect_url": "https://your-app.com/callback"
  }'
```

```python Python theme={null}
tokens = requests.post(
    "https://trimble-oauth2-helper.withleaf.io/farmengage/get_token",
    json={
        "client_id": "your-agco-client-id",
        "client_secret": "your-agco-client-secret",
        "code": "the-code-from-redirect",
        "redirect_url": "https://your-app.com/callback"
    }
).json()
refresh_token = tokens["refresh_token"]
```

```javascript JavaScript theme={null}
const tokenRes = await fetch(
  "https://trimble-oauth2-helper.withleaf.io/farmengage/get_token",
  {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      client_id: "your-agco-client-id",
      client_secret: "your-agco-client-secret",
      code: "the-code-from-redirect",
      redirect_url: "https://your-app.com/callback",
    }),
  }
);
const { refresh_token } = await tokenRes.json();
```

The helper returns snake\_case fields:

```json theme={null}
{
  "access_token": "...",
  "refresh_token": "..."
}
```

`code` can be the raw authorization code or the full callback URL the grower landed on (the helper extracts `code=` from URLs that start with `http`).

You only need `refresh_token` for the next step. Leaf refreshes the access token itself.

## Step 3: Attach credentials to the Leaf user

```bash cURL theme={null}
curl -X POST "https://api.withleaf.io/services/usermanagement/api/users/{leafUserId}/farm-engage-credentials" \
  -H "Authorization: Bearer YOUR_LEAF_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "clientId": "your-agco-client-id",
    "clientSecret": "your-agco-client-secret",
    "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}/farm-engage-credentials",
    headers={"Authorization": f"Bearer {leaf_token}"},
    json={
        "clientId": "your-agco-client-id",
        "clientSecret": "your-agco-client-secret",
        "refreshToken": refresh_token
    }
)
print(response.json())
```

```javascript JavaScript theme={null}
const res = await fetch(
  `https://api.withleaf.io/services/usermanagement/api/users/${leafUserId}/farm-engage-credentials`,
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${leafToken}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      clientId: "your-agco-client-id",
      clientSecret: "your-agco-client-secret",
      refreshToken: refresh_token,
    }),
  }
);
console.log(await res.json());
```

Do not send `accessToken`. Leaf confirms the credential by refreshing the token and calling the organization list in FarmEngage. After that, Leaf handles token refresh automatically.

## Step 4: Confirm the credentials and organizations

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

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

Then confirm at least one organization is authorized:

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

If `connectedOrganizations` is empty, send the grower the `managementUri` from that response so they can grant your app access.

## What you built

You connected FarmEngage to a Leaf user. After at least one organization is authorized, Leaf syncs field boundaries, machine files, and field operations from PTx FarmEngage. Query fields, machine files, and field operations through the Leaf API and filter with `?provider=FarmEngage`. See [How FarmEngage data appears in Leaf's APIs](https://docs.withleaf.io/providers/farmengage.md#how-farmengage-data-appears-in-leafs-apis) and the [field operations](https://docs.withleaf.io/guides/tutorials/field-operations-quickstart.md) tutorial.

For the credentials schema and management endpoints, see the [FarmEngage provider guide](https://docs.withleaf.io/providers/farmengage.md) and the [provider credentials API reference](https://docs.withleaf.io/api-reference/providers.md).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.