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

# FarmEngage

> Connect to FarmEngage (PTx/AGCO) to pull field boundaries, machine files, and field operations through Leaf's provider credentials API.

> [!NOTE]
>
> This page covers **FarmEngage**, PTx/AGCO's API. For the legacy Trimble Agriculture integration, see [Trimble](https://docs.withleaf.io/providers/trimble.md). Existing Trimble connections continue to work until PTx disables that API. New integrations should use FarmEngage.

PTx Trimble (AGCO) exposes two API platforms. Leaf supports both as separate providers: **[Trimble](https://docs.withleaf.io/providers/trimble.md)** and **FarmEngage** (this page). FarmEngage authenticates with **AGCO ID**, not Trimble Identity. Existing Trimble `clientId`, `clientSecret`, and refresh tokens do not work with FarmEngage.

Leaf connects to FarmEngage using OAuth 2.0. After Leaf validates the credentials and the grower authorizes at least one organization, Leaf syncs growers, farms, and fields when `fieldsAutoSync` is enabled. Leaf syncs machine files and field operations when `operationsAutoSync` is enabled.

## Prerequisites

1. FarmEngage API access from PTx. Request credentials through [PTx's API request form](https://www.ptxag.com/us/en/partners/developers/resources/request-apis.html). PTx issues an AGCO `clientId` and `clientSecret`.
2. Your application's redirect URL registered with PTx. If you use [Magic Link](https://docs.withleaf.io/components/magic-link.md) or [Leaf Link](https://docs.withleaf.io/components/leaf-link.md), register `https://widget.withleaf.io`.
3. A grower's `refreshToken` obtained through the FarmEngage (AGCO ID) OAuth 2.0 consent flow.

> [!WARNING]
>
> Legacy Trimble Agriculture credentials cannot be reused. The grower must re-authorize with AGCO ID, and you must attach a new `farm-engage-credentials` object. See [Migrate from Trimble to FarmEngage](https://docs.withleaf.io/guides/tutorials/migrate-trimble-to-farmengage.md).

## Setup steps

If you use [Magic Link](https://docs.withleaf.io/components/magic-link.md) or [Leaf Link](https://docs.withleaf.io/components/leaf-link.md), register `POST /app-keys/FarmEngage/{appName}`, add `https://widget.withleaf.io` at PTx, and add `"FarmEngage"` to `allowedProviders`. Those users do not need the helper or the `farm-engage-credentials` POST below.

1. Complete the FarmEngage OAuth 2.0 flow to obtain a `refreshToken` for the grower's account. Leaf's helper endpoints are documented in the [Connect FarmEngage tutorial](https://docs.withleaf.io/guides/tutorials/connect-farmengage.md).
2. POST the credentials to Leaf:

```bash cURL theme={null}
curl -X POST \
    -H 'Authorization: Bearer YOUR_TOKEN' \
    -H 'Content-Type: application/json' \
    -d '{
      "clientId": "your-agco-client-id",
      "clientSecret": "your-agco-client-secret",
      "refreshToken": "grower-refresh-token"
    }' \
    'https://api.withleaf.io/services/usermanagement/api/users/{leafUserId}/farm-engage-credentials'
```

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

TOKEN = 'YOUR_TOKEN'

endpoint = 'https://api.withleaf.io/services/usermanagement/api/users/{leafUserId}/farm-engage-credentials'
headers = {'Authorization': f'Bearer {TOKEN}'}

data = {
    "clientId": "your-agco-client-id",
    "clientSecret": "your-agco-client-secret",
    "refreshToken": "grower-refresh-token"
}

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/users/{leafUserId}/farm-engage-credentials'
const headers = { 'Authorization': `Bearer ${TOKEN}` }

const data = {
    "clientId": "your-agco-client-id",
    "clientSecret": "your-agco-client-secret",
    "refreshToken": "grower-refresh-token"
}

axios.post(endpoint, data, { headers })
    .then(res => console.log(res.data))
    .catch(console.error)
```

3. Leaf validates the token against FarmEngage (`GET /config/organizations`) and begins syncing. Check credential status with `GET /users/{leafUserId}/farm-engage-credentials`.
4. Confirm the grower authorized at least one FarmEngage organization. If they skipped that step, Leaf syncs nothing. Use `GET /users/{leafUserId}/organizations/FarmEngage` and send them the returned `managementUri`.

## Credentials schema

**Create request body:**

| Field | Type | Required | Description |
| - | - | - | - |
| `clientId` | string | Yes | Your application's AGCO client ID from PTx |
| `clientSecret` | string | Yes | Your application's AGCO client secret |
| `refreshToken` | string | Yes | The grower's OAuth refresh token from the AGCO ID flow |

There is no `subscriptionKey` and no `clientEnvironment`. FarmEngage app keys and user credentials are production-only.

**Response:**

```json theme={null}
{
  "id": "uuid",
  "status": "str",
  "createdTime": "yyyy-MM-dd'T'HH:mm:ss.SSSSSS'Z'",
  "clientId": "str",
  "clientSecret": "str",
  "accessToken": "str",
  "refreshToken": "str"
}
```

POST create and GET responses both obfuscate `clientId`, `clientSecret`, `accessToken`, and `refreshToken`. Leaf obtains and refreshes the access token itself — you do not send `accessToken` on create.

## Endpoints

Base URL: `https://api.withleaf.io/services/usermanagement/api`

| Action | Method | Path |
| - | - | - |
| Get credentials | GET | `/users/{leafUserId}/farm-engage-credentials` |
| Create credentials | POST | `/users/{leafUserId}/farm-engage-credentials` |
| Delete credentials | DELETE | `/users/{leafUserId}/farm-engage-credentials` |
| Get credential events | GET | `/users/{leafUserId}/farm-engage-credentials/events` |
| List organizations | GET | `/users/{leafUserId}/organizations/FarmEngage` |

Register Leaf Link / Magic Link app keys at `POST /app-keys/FarmEngage/{appName}` with `{ "clientId", "clientSecret" }`. That path has no `{clientEnvironment}` segment.

## Data sync behavior

Leaf polls FarmEngage on the same schedule as other non-webhook providers (at least every 24 hours). Field hierarchy sync (growers, farms, fields) runs when `fieldsAutoSync` is enabled. Machine files and field operations run when `operationsAutoSync` is enabled. Neither flag requires the other. There is no FarmEngage webhook subscription.

**Field hierarchy.** FarmEngage uses Organization → Client → Farm → Field. Leaf maps Client to Grower, Farm to Farm, and Field to Field. Boundaries come from each field's extent geometry when FarmEngage reports a positive area. Leaf keys grower records by a salted hash of the AGCO ID token `sub` claim, not by the FarmEngage client ID. Leaf does not copy the client display name onto the grower.

**Machine files.** Leaf lists task files per authorized organization, downloads each file from its time-limited `temporaryAccessUri`, and runs the standard conversion pipeline. Leaf creates field operations the same way as for every other provider.

`organizationDataSync` / SELECTED-only org filtering is John Deere only. FarmEngage syncs every organization the grower's token can see.

## How FarmEngage data appears in Leaf's APIs

FarmEngage data flows through the same Leaf endpoints as every other provider — fields, files, and operations. The `provider` field on each object is `FarmEngage`:

* Fields: `"provider": "FarmEngage"`
* Machine files: `"provider": "FarmEngage"`
* Field operations: `"provider": "FarmEngage"`

Legacy Trimble data continues to show `"provider": "Trimble"`.

You can filter by provider when querying:

```bash theme={null}
curl "https://api.withleaf.io/services/fields/api/fields?provider=FarmEngage" \
  -H "Authorization: Bearer YOUR_TOKEN"
```

Output format (GeoJSON/GeoParquet) and per-provider field-operation merge behavior match other providers. FarmEngage organization, grower, farm, and field IDs are new UUIDs that must not be joined to stored Trimble IDs. Grower records have no FarmEngage client display name. A parallel Trimble credential creates a second Leaf field, file, and operations graph.

> [!WARNING]
>
> If a Leaf user has both `trimble-credentials` and `farm-engage-credentials` attached, the same physical field might appear twice — once with `"provider": "Trimble"` and once with `"provider": "FarmEngage"`. Remove the legacy credential after confirming the FarmEngage connection to avoid duplicates.

## Organizations

After the grower authorizes, list the organizations Leaf can see:

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

Example response:

```json theme={null}
{
  "managementUri": "https://www.farmengage.com/ThirdPartyAccess/ThirdPartyAuthorizationRedirect?clientid=your-agco-client-id&IsAgcoId=true",
  "connectedOrganizations": [
    {
      "id": "11111111-2222-3333-4444-555555555555",
      "name": "Organization Name"
    }
  ]
}
```

FarmEngage organization IDs are UUIDs. They do not match legacy Trimble organization IDs.

* The list returns `connectedOrganizations` only. FarmEngage does not expose a separate not-connected list the way John Deere does.
* `managementUri` is a single account-level URL. Send the grower there to grant or change which organizations your app can access.
* If `connectedOrganizations` is empty, the token is valid but no organization is authorized. Sync does not produce fields or files until the grower completes that step.

## Troubleshooting

Use the events endpoint to inspect credential health:

```bash cURL theme={null}
curl -X GET \
    -H 'Authorization: Bearer YOUR_TOKEN' \
    'https://api.withleaf.io/services/usermanagement/api/users/{leafUserId}/farm-engage-credentials/events'
```

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

TOKEN = 'YOUR_TOKEN'
endpoint = 'https://api.withleaf.io/services/usermanagement/api/users/{leafUserId}/farm-engage-credentials/events'
headers = {'Authorization': f'Bearer {TOKEN}'}

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

```javascript JavaScript theme={null}
const axios = require('axios')
const TOKEN = 'YOUR_TOKEN'

const endpoint = 'https://api.withleaf.io/services/usermanagement/api/users/{leafUserId}/farm-engage-credentials/events'
const headers = { 'Authorization': `Bearer ${TOKEN}` }

axios.get(endpoint, { headers })
    .then(res => console.log(res.data))
    .catch(console.error)
```

> [!WARNING]
>
> Event logs are retained for 30 days. Once the credential is deleted or disassociated from the Leaf user, the logs are no longer available.

Common issues:

* **Status changes to invalid**: The grower might have revoked access, or a token refresh failed after FarmEngage issued a replacement refresh token. Leaf persists tokens from scheduled and on-demand credential refresh. Confirmation also refreshes against FarmEngage and does not store that replacement. If status becomes invalid immediately after attach, have the grower re-authorize through the AGCO ID OAuth flow.
* **Empty organizations / no files**: The grower authenticated but did not grant your application access to any FarmEngage organizations. Send them the `managementUri`.
* **Using Trimble helper paths or Trimble client IDs**: FarmEngage uses `/farmengage/get_url` and `/farmengage/get_token` on the Trimble OAuth helper host, and AGCO-issued client credentials. `api.farmengage.com` rejects legacy Trimble tokens. Those helper endpoints are unauthenticated: send `clientSecret` only from a backend, never from browser or Leaf Link client code, and treat the helper's token response as secrets.
* **Redirect URL mismatch**: The `client_redirect_url` / `redirect_url` you send the helper must match the URL registered with PTx, including trailing slashes.

## What to do next

* [Connect FarmEngage Tutorial](https://docs.withleaf.io/guides/tutorials/connect-farmengage.md) — Step-by-step walkthrough.
* [Migrate from Trimble to FarmEngage](https://docs.withleaf.io/guides/tutorials/migrate-trimble-to-farmengage.md) — For customers moving off the legacy Trimble provider.
* [Provider Authentication Overview](https://docs.withleaf.io/providers/overview.md) — How provider credentials work across all providers.
* [API Reference: Providers](https://docs.withleaf.io/api-reference/providers.md) — Full endpoint reference for provider credentials.


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