Colmeia Platform

Colmeia is the API middleware layer for the MT2Data agricultural data platform. It provides a unified, tenant-scoped interface for accessing farm management data from multiple integrated providers.

Public base URL: https://app.colmeia.agr.br/api

What Colmeia provides

  • Provider integrations — John Deere Operations Center, Syngenta Cropwise, Solinftec SCDI, and MT2Data Datalake
  • Transparent proxying — all provider authentication is handled server-side; you only need a tenant bearer secret
  • Mobile access — WhatsApp/bot interface for field-level data queries

Authentication

Your tenant ID and bearer secret are provisioned by MT2Data. Include the bearer secret in every request:

Authorization: Bearer <tenant-secret>

Custom Integrations

Overview

Custom integrations provide access to client-specific data sources that are not part of the standard provider catalog. Each integration is provisioned individually by MT2Data and requires authentication for access.

Base URL: https://app.colmeia.agr.br/api/<CLIENT_SLUG>

Authentication

Two methods are accepted — use whichever fits the context:

Bearer secret (recommended for programmatic access):

Authorization: Bearer <tenant-secret>

The tenant secret is the long-lived key shown on the Integrations page after rotating.

Session cookie (dashboard / browser):

Cookie: colmeia_session=<session-token>

Access is also gated per tenant. If the manager has disabled this integration for a specific tenant, the endpoint returns integration_disabled.


Large numbers and precision

All SQL Server integrations (PIMS, Protheus, Farmtell, and any future bridge built on the same stack) apply the same precision-safe serialisation rule. Read this once and the contract holds for every bridge.

Why

SQL Server columns declared NUMERIC(p, s) / DECIMAL(p, s) with p > 15, and BIGINT values outside the safe-integer range (|v| > 2^53 − 1 = 9007199254740991), do not fit in a JavaScript / JSON number without losing trailing digits. For example, an Oracle-style NUMBER(22) column stored as 30448901015033924 would be silently rounded to 30448901015033920 by a naive JSON serialiser, and the resulting filter WHERE id = 30448901015033920 returns zero rows.

To prevent silent corruption, the bridge returns affected values as JSON strings.

Rules

SQL Server type / shapeJSON type returned
NUMERIC(p, s) / DECIMAL(p, s) with p ≤ 15number (unchanged)
NUMERIC(p, s) / DECIMAL(p, s) with p > 15, s = 0string — full integer, e.g. "30448901015033924"
NUMERIC(p, s) / DECIMAL(p, s) with p > 15, s > 0string — full decimal, e.g. "3044890101503.3924" (negatives prefixed "-")
BIGINT (SQLINT8)string in all cases — the driver already serialises bigints as strings end-to-end
INT, SMALLINT, TINYINT, FLOAT, REAL, MONEY, SMALLMONEYnumber (no change)

Precision is column metadata, not value-level. A small value like 101 stored in a NUMERIC(22, 0) column still arrives as the string "101". Treat the column as string-typed across the entire result set.

How to handle the values

{
  "success": true,
  "data": [
    { "ID_UPNIVEL3": "101", "ID_INSUMO": "30448901015033924" }
  ]
}

Do:

  • Keep the value as a string in your application memory. Use it directly in equality / filter round-trips.
  • Pass the literal back into SQL Server either as a raw integer literal (WHERE id = 30448901015033924) or as a quoted string (WHERE CAST(id AS NVARCHAR(40)) = '30448901015033924'). Both work; SQL Server coerces.
  • For sorting or grouping in the application layer, sort as strings only when every value has the same length and zero-padding; otherwise convert to BigInt (JavaScript) / decimal.Decimal (Python) / BigInteger (Java) etc.

Do not:

  • Call parseFloat(value), Number(value), or +value on these strings. That re-introduces the precision loss the bridge just prevented.
  • Concatenate filter values with + in a way that coerces to number before the SQL round-trip.

Worked example

Two-step round-trip — fetch an ID, then use it as a filter — demonstrates that no precision is lost in the proxy chain:

# 1. Fetch a bigint ID
curl -s "https://app.colmeia.agr.br/api/<CLIENT_SLUG>/data/<TENANT_ID>/query" \
  -H "Authorization: Bearer <tenant-secret>" \
  -H "Content-Type: application/json" \
  -d '{ "query": "SELECT TOP 1 ID_INSUMO FROM <table>" }'
# → { "success": true, "data": [ { "ID_INSUMO": "30448901015033924" } ] }

# 2. Filter by the exact value returned (raw literal)
curl -s "https://app.colmeia.agr.br/api/<CLIENT_SLUG>/data/<TENANT_ID>/query" \
  -H "Authorization: Bearer <tenant-secret>" \
  -H "Content-Type: application/json" \
  -d '{ "query": "SELECT COUNT(*) AS n FROM <table> WHERE ID_INSUMO = 30448901015033924" }'
# → { "success": true, "data": [ { "n": 1 } ]   }   ← matches, full precision preserved

PIMS ERP

Execute SQL queries against a PIMS ERP SQL Server database.

POST /api/<CLIENT_SLUG>/data/:tenantId/query

Request body:

FieldRequiredType
queryYesstring — SQL query to execute

Simple query

curl -s \
  "https://app.colmeia.agr.br/api/<CLIENT_SLUG>/data/YOUR_TENANT_ID/query" \
  -H "Authorization: Bearer <tenant-secret>" \
  -H "Content-Type: application/json" \
  -d '{ "query": "SELECT TOP 10 * FROM <table_name>" }'

Multiline query

Save the SQL to a file (query.sql), then use jq to build the JSON payload:

-- query.sql
SELECT TOP 10
    <columns>
FROM <main_table> M
INNER JOIN <related_table> R ON R.<fk> = M.<pk>
LEFT JOIN <optional_table> O ON O.<fk> = M.<pk>
WHERE M.<date_column> >= '2026-01-01'
ORDER BY M.<date_column> DESC
curl -s \
  "https://app.colmeia.agr.br/api/<CLIENT_SLUG>/data/YOUR_TENANT_ID/query" \
  -H "Authorization: Bearer <tenant-secret>" \
  -H "Content-Type: application/json" \
  -d "$(jq -n --rawfile q query.sql '{"query": $q}')"

jq handles newlines, quotes, and special characters automatically. Install with brew install jq or apt install jq.

Consult the PIMS schema documentation provisioned to your tenant for table and column names.


Response:

{
  "success": true,
  "data": [
    { "<column_a>": "<value_a>", "<column_b>": "<value_b>" }
  ]
}

Error responses:

ErrorStatusMeaning
unauthorized401Missing or invalid credentials
forbidden403Tenant not owned by this manager
integration_disabled403Integration disabled for this tenant
missing_query400Request body missing query field
invalid_json400Malformed request body
db_error500Bridge could not execute the query

TOTVS Protheus ERP

Execute SQL queries against a TOTVS Protheus SQL Server database.

POST /api/<CLIENT_SLUG>/data/:tenantId/query

Request body:

FieldRequiredType
queryYesstring — SQL query to execute

Simple query

curl -s \
  "https://app.colmeia.agr.br/api/<CLIENT_SLUG>/data/YOUR_TENANT_ID/query" \
  -H "Authorization: Bearer <tenant-secret>" \
  -H "Content-Type: application/json" \
  -d '{ "query": "SELECT TOP 10 * FROM <table_name>" }'

Multiline query

Save the SQL to a file (query.sql), then use jq to build the JSON payload:

-- query.sql
SELECT TOP 10
    <columns>
FROM <main_table> M
INNER JOIN <related_table> R ON R.<fk> = M.<pk>
                            AND R.D_E_L_E_T_ = ' '
WHERE M.D_E_L_E_T_ = ' '
  AND M.<date_column> >= '20260101'
ORDER BY M.<date_column> DESC
curl -s \
  "https://app.colmeia.agr.br/api/<CLIENT_SLUG>/data/YOUR_TENANT_ID/query" \
  -H "Authorization: Bearer <tenant-secret>" \
  -H "Content-Type: application/json" \
  -d "$(jq -n --rawfile q query.sql '{"query": $q}')"

jq handles newlines, quotes, and special characters automatically. Install with brew install jq or apt install jq.

Protheus tables follow the pattern <table_code><company_suffix> (e.g., <table_code>01). Always filter D_E_L_E_T_ = ' ' to exclude logically deleted records. Consult the Protheus schema documentation provisioned to your tenant for table and column names.


Response:

{
  "success": true,
  "data": [
    { "<column_a>": "<value_a>", "<column_b>": "<value_b>" }
  ]
}

Error responses:

ErrorStatusMeaning
unauthorized401Missing or invalid credentials
forbidden403Tenant not owned by this manager
integration_disabled403Integration disabled for this tenant
missing_query400Request body missing query field
invalid_json400Malformed request body
db_error500Bridge could not execute the query

Farmtell

Execute SQL queries against a Farmtell SQL Server database.

POST /api/<CLIENT_SLUG>/data/:tenantId/query

Request body:

FieldRequiredType
queryYesstring — SQL query to execute

Simple query

curl -s \
  "https://app.colmeia.agr.br/api/<CLIENT_SLUG>/data/YOUR_TENANT_ID/query" \
  -H "Authorization: Bearer <tenant-secret>" \
  -H "Content-Type: application/json" \
  -d '{ "query": "SELECT TOP 10 * FROM <table_name>" }'

Multiline query

Save the SQL to a file (query.sql), then use jq to build the JSON payload:

-- query.sql
SELECT TOP 10
    <columns>
FROM <main_table> M
INNER JOIN <related_table> R ON R.<fk> = M.<pk>
LEFT JOIN <optional_table> O ON O.<fk> = M.<pk>
WHERE M.<date_column> >= '2026-01-01'
ORDER BY M.<date_column> DESC
curl -s \
  "https://app.colmeia.agr.br/api/<CLIENT_SLUG>/data/YOUR_TENANT_ID/query" \
  -H "Authorization: Bearer <tenant-secret>" \
  -H "Content-Type: application/json" \
  -d "$(jq -n --rawfile q query.sql '{"query": $q}')"

jq handles newlines, quotes, and special characters automatically. Install with brew install jq or apt install jq.

Table and column names may vary across Farmtell deployments. Consult the schema of the specific database provisioned to your tenant.


Response:

{
  "success": true,
  "data": [
    { "<column_a>": "<value_a>", "<column_b>": "<value_b>" }
  ]
}

Error responses:

ErrorStatusMeaning
unauthorized401Missing or invalid credentials
forbidden403Tenant not owned by this manager
integration_disabled403Integration disabled for this tenant
missing_query400Request body missing query field
invalid_json400Malformed request body
db_error500Bridge could not execute the query

MT2Data Datalake via Colmeia

Overview

Access MT2Data Datalake files through the Colmeia middleware. Your Datalake credentials are connected to your tenant by MT2Data — you only need your tenant bearer secret to make requests.

Base URL: https://app.colmeia.agr.br/api/dl

Authentication

All data routes require your tenant bearer secret:

Authorization: Bearer <tenant-secret>

The middleware handles Datalake OAuth token management automatically.


Catalog

GET /api/dl/data/:tenantId/catalog

Returns all Symbols your Datalake subscription is authorized to access, with descriptions and file paths. Fast (~1s).

curl https://app.colmeia.agr.br/api/dl/data/YOUR_TENANT_ID/catalog \
  -H "Authorization: Bearer YOUR_TENANT_SECRET"
{
  "clientId": "your-account",
  "files": [
    {
      "Symbol": "DatasetSymbol",
      "Description": "Human-readable description",
      "FileName": "Data/MT2/DatasetSymbol.parquet"
    }
  ],
  "count": 1
}

File Listing

GET /api/dl/data/:tenantId/list

Lists files that appear in your catalog and exist in storage — with size and upload timestamp. Uses batched verification (~2s for 500 files).

ParameterRequiredDefaultDescription
limitNo1000Max files to return
curl "https://app.colmeia.agr.br/api/dl/data/YOUR_TENANT_ID/list?limit=100" \
  -H "Authorization: Bearer YOUR_TENANT_SECRET"

GET /api/dl/data/:tenantId/count

Returns the total count of accessible files (~2s).

curl https://app.colmeia.agr.br/api/dl/data/YOUR_TENANT_ID/count \
  -H "Authorization: Bearer YOUR_TENANT_SECRET"

File Access

GET /api/dl/data/:tenantId/info/:symbol

Returns metadata for a file by Symbol (~0.5s).

curl https://app.colmeia.agr.br/api/dl/data/YOUR_TENANT_ID/info/DatasetSymbol \
  -H "Authorization: Bearer YOUR_TENANT_SECRET"

GET /api/dl/data/:tenantId/download/:symbol

Downloads a file by Symbol. Returns binary content.

curl https://app.colmeia.agr.br/api/dl/data/YOUR_TENANT_ID/download/DatasetSymbol \
  -H "Authorization: Bearer YOUR_TENANT_SECRET" \
  -o dataset.parquet

Performance Reference

EndpointSpeedUse Case
/catalog~1sBrowse available Symbols
/info/:symbol~0.5sFile metadata
/download/:symbol~0.5s + transferDownload a file
/list~2sVerify file existence with metadata
/count~2sCount accessible files

Recommended workflow:

  1. GET /catalog — find the Symbol
  2. GET /download/:symbol — download directly

Code Examples

Python

import requests

BASE = "https://app.colmeia.agr.br/api/dl/data"
TENANT = "YOUR_TENANT_ID"
HEADERS = {"Authorization": "Bearer YOUR_TENANT_SECRET"}

# Browse catalog
catalog = requests.get(f"{BASE}/{TENANT}/catalog", headers=HEADERS).json()
print(f"Symbols available: {catalog['count']}")

# Download a file
with requests.get(f"{BASE}/{TENANT}/download/DatasetSymbol", headers=HEADERS, stream=True) as r:
    r.raise_for_status()
    with open("dataset.parquet", "wb") as f:
        for chunk in r.iter_content(chunk_size=8192):
            f.write(chunk)

JavaScript / Node.js

const BASE = 'https://app.colmeia.agr.br/api/dl/data/YOUR_TENANT_ID';
const HEADERS = { Authorization: 'Bearer YOUR_TENANT_SECRET' };

const catalog = await fetch(`${BASE}/catalog`, { headers: HEADERS }).then(r => r.json());
console.log(`Symbols: ${catalog.count}`);

const fileData = await fetch(`${BASE}/download/DatasetSymbol`, { headers: HEADERS })
  .then(r => r.arrayBuffer());
require('fs').writeFileSync('dataset.parquet', Buffer.from(fileData));

Error Codes

HTTPCodeMeaning
401no_token_foundYour Datalake account is not connected — contact MT2Data
403upstream Access deniedSymbol not in your subscription
404upstream Not foundFile does not exist

John Deere Integration

Overview

Access agricultural data from John Deere Operations Center through the Colmeia middleware. Your John Deere account is connected to your tenant by MT2Data — you only need your tenant bearer secret to make requests.

Base URL: https://app.colmeia.agr.br/api/jd

Authentication

All data routes require your tenant bearer secret:

Authorization: Bearer <tenant-secret>

Pagination

John Deere uses HATEOAS pagination. Responses include a links array where a nextPage entry signals additional pages. The middleware rewrites all uri values in links to point through itself, so you can follow pagination links without a JD token:

{
  "total": 153,
  "links": [
    { "rel": "self",     "uri": "https://app.colmeia.agr.br/api/jd/data/YOUR_TENANT_ID/organizations/YOUR_ORG_ID/flag-categories" },
    { "rel": "nextPage", "uri": "https://app.colmeia.agr.br/api/jd/data/YOUR_TENANT_ID/organizations/YOUR_ORG_ID/flag-categories?pageOffset=10&itemLimit=10" }
  ],
  "values": [...]
}

Follow the nextPage URI directly — no additional auth headers required.


Organizations & Farms

Get Organizations

Endpoint: GET /jd/data/:tenantId/organizations

curl https://app.colmeia.agr.br/api/jd/data/YOUR_TENANT_ID/organizations \
  -H "Authorization: Bearer YOUR_TENANT_SECRET"

Get Single Organization

Endpoint: GET /jd/data/:tenantId/organizations/:orgId

curl https://app.colmeia.agr.br/api/jd/data/YOUR_TENANT_ID/organizations/YOUR_ORG_ID \
  -H "Authorization: Bearer YOUR_TENANT_SECRET"

Get Organization Settings

Endpoint: GET /jd/data/:tenantId/organizations/:orgId/settings

curl https://app.colmeia.agr.br/api/jd/data/YOUR_TENANT_ID/organizations/YOUR_ORG_ID/settings \
  -H "Authorization: Bearer YOUR_TENANT_SECRET"

Get Farms for Organization

Endpoint: GET /jd/data/:tenantId/organizations/:orgId/farms

curl https://app.colmeia.agr.br/api/jd/data/YOUR_TENANT_ID/organizations/YOUR_ORG_ID/farms \
  -H "Authorization: Bearer YOUR_TENANT_SECRET"

Fields & Boundaries

Get Fields for Organization

Endpoint: GET /jd/data/:tenantId/organizations/:orgId/fields

curl https://app.colmeia.agr.br/api/jd/data/YOUR_TENANT_ID/organizations/YOUR_ORG_ID/fields \
  -H "Authorization: Bearer YOUR_TENANT_SECRET"

List Boundaries for Organization

Endpoint: GET /jd/data/:tenantId/organizations/:orgId/boundaries

List Boundaries for Field

Endpoint: GET /jd/data/:tenantId/organizations/:orgId/fields/:fieldId/boundaries

Get Boundary by ID

Endpoint: GET /jd/data/:tenantId/organizations/:orgId/fields/:fieldId/boundaries/:boundaryId

Get Field Operation Boundary

Endpoint: GET /jd/data/:tenantId/field-operations/:operationId/boundary


Equipment

Note: The deprecated /machines and /implements endpoints were removed by John Deere on March 15, 2025. Use the Equipment API routes below. Scope eq1 is required.

Get Equipment for Organization

Endpoint: GET /jd/data/:tenantId/organizations/:orgId/equipment

curl https://app.colmeia.agr.br/api/jd/data/YOUR_TENANT_ID/organizations/YOUR_ORG_ID/equipment \
  -H "Authorization: Bearer YOUR_TENANT_SECRET"

Response:

{
  "total": 1,
  "values": [
    {
      "@type": "Machine",
      "id": "equipment-id-123",
      "name": "Tractor Model 2022",
      "modelYear": 2022,
      "links": [...]
    }
  ]
}

Get Equipment by ID

Endpoint: GET /jd/data/:tenantId/equipment/:equipmentId

Get Field Operations for Organization

Endpoint: GET /jd/data/:tenantId/organizations/:orgId/field-operations


Machine Telemetry

These endpoints require the machine to be a connected JD telematics device (active modem). Machines without an active modem return 404 or 410 — this is expected JD behavior, not a middleware error. Check the telematicsCapable field on equipment records as an indicator.

Device State Reports

curl https://app.colmeia.agr.br/api/jd/data/YOUR_TENANT_ID/machines/MACHINE_ID/device-state-reports \
  -H "Authorization: Bearer YOUR_TENANT_SECRET"

Machine Alerts

curl https://app.colmeia.agr.br/api/jd/data/YOUR_TENANT_ID/machines/MACHINE_ID/alerts \
  -H "Authorization: Bearer YOUR_TENANT_SECRET"

Location History

curl https://app.colmeia.agr.br/api/jd/data/YOUR_TENANT_ID/machines/MACHINE_ID/location-history \
  -H "Authorization: Bearer YOUR_TENANT_SECRET"
curl https://app.colmeia.agr.br/api/jd/data/YOUR_TENANT_ID/machines/MACHINE_ID/breadcrumbs \
  -H "Authorization: Bearer YOUR_TENANT_SECRET"

Hours of Operation

curl https://app.colmeia.agr.br/api/jd/data/YOUR_TENANT_ID/machines/MACHINE_ID/hours-of-operation \
  -H "Authorization: Bearer YOUR_TENANT_SECRET"

Engine Hours

curl https://app.colmeia.agr.br/api/jd/data/YOUR_TENANT_ID/machines/MACHINE_ID/engine-hours \
  -H "Authorization: Bearer YOUR_TENANT_SECRET"

Assets

List Assets for Organization

curl https://app.colmeia.agr.br/api/jd/data/YOUR_TENANT_ID/organizations/YOUR_ORG_ID/assets \
  -H "Authorization: Bearer YOUR_TENANT_SECRET"

Get Asset by ID

curl https://app.colmeia.agr.br/api/jd/data/YOUR_TENANT_ID/assets/ASSET_ID \
  -H "Authorization: Bearer YOUR_TENANT_SECRET"

Get Asset Locations

curl https://app.colmeia.agr.br/api/jd/data/YOUR_TENANT_ID/assets/ASSET_ID/locations \
  -H "Authorization: Bearer YOUR_TENANT_SECRET"

Asset Catalog

curl https://app.colmeia.agr.br/api/jd/data/YOUR_TENANT_ID/asset-catalog \
  -H "Authorization: Bearer YOUR_TENANT_SECRET"

Flags & Preferences

List Flags for Organization

curl https://app.colmeia.agr.br/api/jd/data/YOUR_TENANT_ID/organizations/YOUR_ORG_ID/flags \
  -H "Authorization: Bearer YOUR_TENANT_SECRET"

List Flag Categories

curl https://app.colmeia.agr.br/api/jd/data/YOUR_TENANT_ID/organizations/YOUR_ORG_ID/flag-categories \
  -H "Authorization: Bearer YOUR_TENANT_SECRET"

List Flags for Field

curl https://app.colmeia.agr.br/api/jd/data/YOUR_TENANT_ID/organizations/YOUR_ORG_ID/fields/FIELD_ID/flags \
  -H "Authorization: Bearer YOUR_TENANT_SECRET"

Products & Agronomic Catalog

Chemicals

curl https://app.colmeia.agr.br/api/jd/data/YOUR_TENANT_ID/organizations/YOUR_ORG_ID/chemicals \
  -H "Authorization: Bearer YOUR_TENANT_SECRET"

Fertilizers

curl https://app.colmeia.agr.br/api/jd/data/YOUR_TENANT_ID/organizations/YOUR_ORG_ID/fertilizers \
  -H "Authorization: Bearer YOUR_TENANT_SECRET"

Varieties

curl https://app.colmeia.agr.br/api/jd/data/YOUR_TENANT_ID/organizations/YOUR_ORG_ID/varieties \
  -H "Authorization: Bearer YOUR_TENANT_SECRET"

Active Ingredients

Served by the JD Equipment API (scope eq1 required).

curl https://app.colmeia.agr.br/api/jd/data/YOUR_TENANT_ID/active-ingredients \
  -H "Authorization: Bearer YOUR_TENANT_SECRET"

Crop Types

curl https://app.colmeia.agr.br/api/jd/data/YOUR_TENANT_ID/crop-types \
  -H "Authorization: Bearer YOUR_TENANT_SECRET"

Files & Map Layers

Files

curl https://app.colmeia.agr.br/api/jd/data/YOUR_TENANT_ID/organizations/YOUR_ORG_ID/files \
  -H "Authorization: Bearer YOUR_TENANT_SECRET"

Map Layer Summaries

curl https://app.colmeia.agr.br/api/jd/data/YOUR_TENANT_ID/organizations/YOUR_ORG_ID/fields/FIELD_ID/map-layer-summaries \
  -H "Authorization: Bearer YOUR_TENANT_SECRET"

Map Layers

curl https://app.colmeia.agr.br/api/jd/data/YOUR_TENANT_ID/map-layers/LAYER_ID \
  -H "Authorization: Bearer YOUR_TENANT_SECRET"

Guidance Lines

curl https://app.colmeia.agr.br/api/jd/data/YOUR_TENANT_ID/organizations/YOUR_ORG_ID/fields/FIELD_ID/guidance-lines \
  -H "Authorization: Bearer YOUR_TENANT_SECRET"

Code Example

const TENANT_ID = 'YOUR_TENANT_ID';
const BASE = 'https://app.colmeia.agr.br/api';
const headers = { Authorization: 'Bearer YOUR_TENANT_SECRET' };

// List organizations
const orgs = await fetch(`${BASE}/jd/data/${TENANT_ID}/organizations`, { headers })
  .then(r => r.json());

// Get fields for an org
const orgId = orgs.values[0].id;
const fields = await fetch(`${BASE}/jd/data/${TENANT_ID}/organizations/${orgId}/fields`, { headers })
  .then(r => r.json());

console.log(`Found ${fields.values?.length} fields`);

Scope Reference

ScopeDescription
org1View staff, operators, and partners
eq1View equipment data, machine locations
ag1View locations, farms, fields
ag2View + analyze production data, field operations
offline_accessLong-term token access

Error Codes

CodeMeaning
no_token_foundYour John Deere account is not connected — contact MT2Data
org_disabledThis organization has been disabled for your tenant

Middleware API

Overview

The Colmeia middleware provides a unified API for accessing agricultural data from connected providers. Each tenant has a bearer secret that authenticates all data requests.

Base URL: https://app.colmeia.agr.br/api

Authentication

All data routes require a tenant bearer secret in the Authorization header:

Authorization: Bearer <tenant-secret>

Tenant secrets are provisioned by MT2Data and can be rotated through the dashboard. Contact support if you need a new secret.


Connection Status

GET /api/data/:tenantId/connections

Returns the connection state for all providers configured for your tenant. Use this as a pre-flight check before making data requests.

curl https://app.colmeia.agr.br/api/data/YOUR_TENANT_ID/connections \
  -H "Authorization: Bearer YOUR_TENANT_SECRET"

Response:

{
  "success": true,
  "data": {
    "tenant_id": "your-tenant-id",
    "connections": [
      { "provider": "john_deere", "connected": true, "expired": false, "expires_at": 1714086400, "auto_renew": true },
      { "provider": "syngenta",   "connected": true, "expired": false },
      { "provider": "solinftec",  "connected": true, "expired": false, "expires_at": 2092433279, "auto_renew": true },
      { "provider": "datalake",   "connected": true, "expired": false, "expires_at": 1714090000, "auto_renew": true },
      { "provider": "pims",       "connected": true, "expired": false, "custom": true, "client_slug": "<your_pims_slug>",     "display_name": "<your_pims_label>" },
      { "provider": "protheus",   "connected": true, "expired": false, "custom": true, "client_slug": "<your_protheus_slug>", "display_name": "<your_protheus_label>" },
      { "provider": "farmtell",   "connected": true, "expired": false, "custom": true, "client_slug": "<your_farmtell_slug>", "display_name": "<your_farmtell_label>" },
      { "provider": "solinftec",  "connected": true, "expired": false, "snowflake": true, "source_id": "solinftec", "enabled": true, "data_path": "/api/sn/data/your-tenant-id/solinftec/query" }
    ]
  }
}

A connected: false provider means that integration has not been configured for your tenant yet. Contact MT2Data to enable it.

Entries with "custom": true represent custom SQL integrations (PIMS, Protheus, Farmtell, ...). provider is the integration type, client_slug is the per-tenant routing slug used by the data endpoint (/api/<client_slug>/data/<tenant_id>/query). A custom integration only appears here when it is enabled for your tenant.

Entries with "snowflake": true are Snowflake-routed connectors. source_id is the catalog slug for the external system reached over Snowflake (solinftec, …); data_path is the full URL to POST queries against — see snowflake.md. The provider field equals source_id, which can collide with a fixed-provider id (e.g. solinftec is also a first-class provider mounted under /api/sl/data/...). Both rows can appear in the same payload — they represent two distinct integrations and agents disambiguate by the snowflake: true flag plus the data_path URL.


Route Discovery

GET /api/

Returns the full list of available routes. No auth required.

curl https://app.colmeia.agr.br/api/

Response Envelope

All endpoints return a consistent JSON envelope:

{ "success": true,  "data": { ... } }
{ "success": false, "error": "snake_case_error_code" }

Client-facing error codes

CodeHTTPMeaning
unauthorized401Missing or invalid tenant bearer secret
unsupported_provider400Unknown provider ID
phone_not_linked404Phone number not provisioned to any tenant

Snowflake Connectors

Overview

Snowflake connectors let a manager attach one or more known external systems (catalogued by MT2Data) to a tenant and run SQL against them through the Colmeia API. Authentication to Snowflake uses key-pair JWT — Colmeia generates the keypair when the connector is created, displays the public key for one-time enrollment by the Snowflake account administrator, and signs JWTs from the dashboard side so your scripts only ever use your Colmeia tenant bearer.

Each connector is keyed by a Snowflake source slug drawn from a static catalog curated by MT2Data (currently: solinftec). A tenant can attach at most one connector per source slug, with its own keypair, account, role, warehouse, database, and schema defaults. The slug is the path segment used in the data URL.

Base URL: https://app.colmeia.agr.br/api/sn


Setup (one-time, in the dashboard)

  1. Sign in at https://app.colmeia.agr.br/login.

  2. Open the tenant page → Integrations.

  3. Scroll to the Snowflake Connectors section → click + Add Snowflake connection.

  4. Fill the form:

    FieldRequiredDescription
    Snowflake sourceYesDropdown of catalogued external systems available for this tenant. Pick the source you want to integrate (currently Solinftec). Sources already connected for this tenant are disabled in the dropdown. The selected source's slug becomes the path segment in the data URL (/api/sn/data/:tenantId/:sourceId/query). Picking a source may pre-fill the Warehouse / Database / Schema / Role fields — those defaults are suggestions you can edit.
    Account locatorYesBare Snowflake account locator (not org-account form). Get it by running SELECT CURRENT_ACCOUNT() in Snowflake — returns something like PS07064. The ORG-ACCOUNT form (e.g. SOLINFTEC-EASTUS2) is rejected by JWT auth on non-AWS-US regions; use the locator. For Azure / non-AWS-US accounts you may need region-qualified form LOCATOR.REGION.CLOUD (e.g. PS07064.EAST-US-2.AZURE) — try the bare locator first.
    Account URLYesSnowflake URL for your account (e.g. https://ps07064.east-us-2.azure.snowflakecomputing.com).
    Username (LOGIN_NAME)YesThe user's LOGIN_NAME (not its NAME), uppercased. Snowflake's JWT verifier maps the sub claim to login_name, not the user identifier. To get it, run DESC USER "<your_user>" in Snowflake and copy the LOGIN_NAME row value verbatim. If the user was created without an explicit LOGIN_NAME, this defaults to the user's NAME in uppercase.
    WarehouseNoDefault warehouse for queries that don't override it. Must have AUTO_RESUME = TRUE — programmatic access cannot wake a suspended warehouse. Check with SHOW WAREHOUSES LIKE '<wh>'; admin must run ALTER WAREHOUSE <wh> SET AUTO_RESUME = TRUE if it's false.
    RoleNoDefault role.
    Database / SchemaNoDefault database and schema.
  5. Submit. Colmeia generates a fresh RSA-2048 keypair tied to this connector and shows you an ALTER USER … SET RSA_PUBLIC_KEY=… command. The status reads Pending admin enrollment.

  6. Forward the ALTER USER … command to the Snowflake account administrator (see the message template below). They run it once. Key-pair JWT authentication is not subject to DUO/MFA, so no human interaction is needed afterwards.

  7. After the admin confirms enrollment, return to the connector card and click Test connection. Status flips to Connected and the connector is ready for queries.

You can later Disable (pauses queries while keeping the row), Enable, or Revoke (deletes the connector and its private key from Colmeia) a connector at any time. Revoking inside Colmeia does not revoke the public key on the Snowflake side — ask the admin to run ALTER USER "<USER>" UNSET RSA_PUBLIC_KEY; if you also want to remove it there.


Worked example — Solinftec

The dashboard accepts these values:

FieldValue
Snowflake sourceSolinftec (catalog entry — pre-fills warehouse/database/schema below)
Account locatorPS07064 (from SELECT CURRENT_ACCOUNT())
Account URLhttps://ps07064.east-us-2.azure.snowflakecomputing.com
Username (LOGIN_NAME)SAMUEL@MT2.PAGE (the LOGIN_NAME from DESC USER, not the user NAME)
WarehouseSSWH_0307 (catalog default, editable; verify AUTO_RESUME = TRUE)
DatabaseSOLINFTEC_BI (catalog default, editable)
SchemaSS (catalog default, editable)
Role(optional — leave blank or use the role Solinftec granted)

After saving, the dashboard shows the data URL as /api/sn/data/<your-tenant-id>/solinftec/query.

After submit, Colmeia shows a command similar to:

ALTER USER "<YOUR_USER>" SET RSA_PUBLIC_KEY='MIIBIjANBgkqhkiG9w0BAQEFAAOC...';

(The base64 payload is unique to this connector.)

Admin enrollment message (template)

Send to the Snowflake administrator by a secure channel:

Hello,

To allow programmatic access from Colmeia using key-pair JWT authentication (which is not subject to DUO MFA), please run the following SQL once as SECURITYADMIN or ACCOUNTADMIN. Note: the ALTER USER quoted identifier below must match the user's NAME (case-sensitive). If the user was created with an explicit LOGIN_NAME that differs from the NAME, replace "<YOUR_USER>" with the actual NAME shown by DESC USER.

ALTER USER "<YOUR_USER>" SET RSA_PUBLIC_KEY='<base64 shown in the Colmeia dashboard>';

Then confirm the fingerprint and the LOGIN_NAME:

DESC USER "<YOUR_USER>";

The RSA_PUBLIC_KEY_FP value should match the fingerprint shown on the Colmeia connector card. Please also reply with the user's LOGIN_NAME row value — that's what Colmeia must use in the connector's Username field (Snowflake's JWT verifier matches the sub claim against LOGIN_NAME, not NAME).

Additional checks:

  1. If the warehouse used by this user has AUTO_RESUME = FALSE, please enable auto-resume so programmatic queries can wake it:
    SHOW WAREHOUSES LIKE '<WH_NAME>';
    -- if auto_resume = false:
    ALTER WAREHOUSE <WH_NAME> SET AUTO_RESUME = TRUE;
    
  2. Confirm that any AUTHENTICATION POLICY attached to this user includes 'KEYPAIR_JWT', and that no NETWORK POLICY blocks Cloudflare egress (egress IPs are not fixed). If a network policy is active, NETWORK_POLICY_EVALUATION = NOT_ENFORCED on the auth policy resolves it.

Thanks.


Query API

POST /api/sn/data/:tenantId/:sourceId/query

Execute a free-form SQL statement against the connector's Snowflake account.

Path parameters:

ParameterDescription
tenantIdYour Colmeia tenant ID.
sourceIdSlug from the Snowflake source catalog (e.g. solinftec). The set of valid values per tenant is whatever the manager has connected — see GET /api/data/:tenantId/connections and look for entries with "snowflake": true.

Authentication — either:

Authorization: Bearer <tenant-secret>

or a dashboard session cookie:

Cookie: colmeia_session=<session-token>

Request body:

FieldRequiredTypeDescription
queryYesstringSQL statement to execute.
warehouseNostringOverride the connector's default warehouse.
databaseNostringOverride the connector's default database.
schemaNostringOverride the connector's default schema.
roleNostringOverride the connector's default role.
timeoutNonumberServer-side execution timeout in seconds (default 60).

Simple query

curl -s \
  "https://app.colmeia.agr.br/api/sn/data/YOUR_TENANT_ID/YOUR_SOURCE_ID/query" \
  -H "Authorization: Bearer <tenant-secret>" \
  -H "Content-Type: application/json" \
  -d '{ "query": "SELECT CURRENT_TIMESTAMP() AS now, CURRENT_USER() AS user" }'

The body fields warehouse, database, schema, role, and timeout are all optional. Omit them and the query runs with whatever defaults you set on the connector. The Snowflake user's DEFAULT_NAMESPACE, DEFAULT_ROLE, and DEFAULT_WAREHOUSE also fill in any gaps. Most queries don't need any of these fields.


Query with per-request overrides

Use the optional body fields only when a single query needs to run against a non-default warehouse / database / schema / role, or with a custom timeout. The override applies to that one call — the connector's defaults are untouched.

curl -s \
  "https://app.colmeia.agr.br/api/sn/data/YOUR_TENANT_ID/YOUR_SOURCE_ID/query" \
  -H "Authorization: Bearer <tenant-secret>" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "SELECT field_id, name, area_hectares FROM solinftec_bi.ss.fields LIMIT 10",
    "warehouse": "SSWH_LARGE",
    "database": "SOLINFTEC_BI",
    "schema": "SS",
    "role": "SSRL_0307",
    "timeout": 120
  }'

Common reasons to override:

  • warehouse — heavy query needs a bigger compute (e.g. switch from X-Small default to LARGE for this call only).
  • database / schema — query targets tables outside the connector's default namespace.
  • role — need a role with different grants for a specific query.
  • timeout — long-running query that may exceed the default 60s server-side execution timeout.

Multiline query

Save the SQL to a file (query.sql), then use jq to build the JSON payload:

-- query.sql
SELECT
    field_id,
    name,
    crop_type,
    area_hectares,
    last_visit_at
FROM your_database.public.fields
WHERE last_visit_at >= '2026-01-01'
ORDER BY last_visit_at DESC
LIMIT 100
curl -s \
  "https://app.colmeia.agr.br/api/sn/data/YOUR_TENANT_ID/YOUR_SOURCE_ID/query" \
  -H "Authorization: Bearer <tenant-secret>" \
  -H "Content-Type: application/json" \
  -d "$(jq -n --rawfile q query.sql '{"query": $q}')"

jq handles newlines, quotes, and special characters automatically. Install with brew install jq or apt install jq.

Database, schema, role, and warehouse fall back to whatever you configured on the connector. Override any of them per request by adding the matching field to the JSON body. Table and column names depend on the schema provisioned to your Snowflake account — consult your data provider for the catalog.


Response:

{
  "success": true,
  "data": {
    "columns": [
      { "name": "NOW",  "type": "timestamp_ltz" },
      { "name": "USER", "type": "text" }
    ],
    "data": [
      { "NOW": "1779132580.643000000", "USER": "YOUR_USER" }
    ]
  }
}

Values are returned as a string-typed array from Snowflake; numeric, boolean, and NULL columns are cast to JS-native types in the response.

Date/time encoding (important):

Snowflake's REST API does not return ISO strings for date/time columns. The encoding depends on the column type — be defensive when parsing:

Snowflake typeReturned asParse with
timestamp_ltz, timestamp_tzUnix seconds with fractional part as a string (e.g. "1779132580.643000000")new Date(parseFloat(v) * 1000)
timestamp_ntzUnix seconds string in UTC (no timezone applied)new Date(parseFloat(v) * 1000) (treat as UTC)
dateDays since Unix epoch as a string (e.g. "20023")new Date(parseInt(v, 10) * 86400 * 1000)
timeSeconds since midnight with fractional part as a stringParse manually

Always branch on the columns[i].type value before parsing.

Error responses:

ErrorStatusMeaning
unauthorized401Missing or invalid credentials.
forbidden403Tenant not owned by this manager, or connector belongs to a different tenant.
unknown_source404sourceId is not in the static Snowflake source catalog.
connector_not_found404No connector exists for this (tenantId, sourceId) pair.
integration_disabled403Connector exists but was disabled. Re-enable it in the dashboard.
missing_query400Request body missing query field.
invalid_json400Malformed request body.
snowflake_auth_failed502Snowflake rejected the JWT. Most often: the public key wasn't enrolled yet, the wrong key was enrolled, an authentication policy excludes KEYPAIR_JWT, or a network policy is blocking the request. The last error is shown on the connector card.
statement_poll_timeout504The Snowflake statement didn't finish in time. Tune timeout or simplify the query.

Listing your connectors

Existing connectors for a tenant are visible in the dashboard's Snowflake Connectors section. Each card shows the catalogued source name, source slug, account, user, warehouse, current status, and the data path — the same slug you put in the URL above.

Programmatic discovery: GET /api/data/:tenantId/connections lists every active connector for the tenant. Snowflake entries carry "snowflake": true, the source_id slug, and the data_path URL. See middleware-api.md for the full payload shape.

A tenant can attach at most one connector per source slug — Colmeia enforces uniqueness of (tenant, source_id). To connect to multiple external systems that all happen to expose Snowflake, those systems each need their own slug in the catalog (contact MT2Data to register additions).


Notes on the keypair

  • The private key never leaves Colmeia. You do not download, copy, or paste it anywhere.
  • The public key is shown only on the connector card. Re-display by reopening the card while the connector is in Pending admin enrollment status.
  • Revoking a connector permanently destroys the private key. Re-creating a connector generates a fresh keypair and requires a new ALTER USER … SET RSA_PUBLIC_KEY=… from the admin.
  • One Snowflake user can have only one public key enrolled at a time. If you need to rotate, ask the admin to overwrite the previous one with the new value shown in the dashboard.

Solinftec Integration

Overview

Access field operations, refueling, and meteorological data from the Solinftec SCDI platform through the Colmeia middleware. Your Solinftec account is connected to your tenant by MT2Data — you only need your tenant bearer secret to make requests.

All three endpoints accept a dateini/datefim range. The middleware fans out one internal fetch per day and returns the full merged result in a single call.

Base URL: https://app.colmeia.agr.br/api/sl

Authentication

All data routes require your tenant bearer secret:

Authorization: Bearer <tenant-secret>

The middleware handles Solinftec's rotating short-lived tokens automatically. No manual token management is needed on your side.

Ranged Requests

Pass dateini and datefim to fetch multiple days in a single call. The response shape is:

{ "data": [...], "days": 7, "total_rows": 294 }

The middleware hard cap is 92 days per single HTTP request. Ranges beyond that are rejected with invalid_date_range — split a longer window into sequential calls on your side.


Operation Details

Endpoint: GET /api/sl/data/:tenantId/operations

Returns field operation history with text descriptions alongside numeric codes.

Query Parameters:

ParameterRequiredFormatDescription
dateiniYesDD/MM/YYYY or DD/MM/YYYY HH:MM:SSStart date (inclusive)
datefimYesDD/MM/YYYY or DD/MM/YYYY HH:MM:SSEnd date (inclusive); max 92 days
sizeNointegerRecords per page per day (default: 1000)
equipamentoNostringFilter by equipment code
operacaoNostringFilter by operation code
operadorNostringFilter by operator code
unidadeNostringFilter by unit code
talhaoNostringFilter by field (talhão) code
ordemservicoNostringFilter by work order
# Fetch one week of operations
curl "https://app.colmeia.agr.br/api/sl/data/YOUR_TENANT_ID/operations?dateini=10/09/2024&datefim=16/09/2024" \
  -H "Authorization: Bearer YOUR_TENANT_SECRET"

Response:

{
  "data": [
    {
      "cd_id": 12345,
      "dt_movimentacao": "10/09/2024 00:00:00",
      "cd_equipamento": "T001",
      "desc_equipamento": "Equipment description",
      "cd_operacao": "101",
      "desc_operacao": "Operation description",
      "cd_operador": "OP01",
      "desc_operador": "Operator name",
      "vl_consumo": 45.2
    }
  ],
  "days": 7,
  "total_rows": 294
}

Train Refueling

Endpoint: GET /api/sl/data/:tenantId/refueling

Returns fuel volume dispensed and hourmeter readings. Returns all active trains — no per-train filtering.

Query Parameters — ranged (preferred):

ParameterRequiredFormatDescription
dateiniYes*DD/MM/YYYYStart date (inclusive)
datefimYes*DD/MM/YYYYEnd date (inclusive); max 92 days
sizeNointegerRecords per page per day (default: 1000, max: 10000)

Query Parameters — legacy single date:

ParameterRequiredFormatDescription
dateYes*DD/MM/YYYYDate to query (single day)
pageNointegerPage number (default: 1)
sizeNointegerRecords per page (default: 1000, max: 10000)

*Use either dateini/datefim or date, not both.

# Ranged (recommended)
curl "https://app.colmeia.agr.br/api/sl/data/YOUR_TENANT_ID/refueling?dateini=01/02/2024&datefim=10/02/2024" \
  -H "Authorization: Bearer YOUR_TENANT_SECRET"

# Legacy single date
curl "https://app.colmeia.agr.br/api/sl/data/YOUR_TENANT_ID/refueling?date=10/02/2024" \
  -H "Authorization: Bearer YOUR_TENANT_SECRET"

Meteorological Data

Endpoint: GET /api/sl/data/:tenantId/weather

Returns hourly climate metrics (rainfall, wind speed, temperature, humidity).

Query Parameters — ranged (preferred):

ParameterRequiredFormatDescription
dateiniYes*DD/MM/YYYYStart date (inclusive)
datefimYes*DD/MM/YYYYEnd date (inclusive); max 92 days
sizeNointegerRecords per page per day (default: 1000)

Query Parameters — legacy single date:

ParameterRequiredFormatDescription
dateYes*DD/MM/YYYYDate to query (single day)
pageNointegerPage number (default: 1)
sizeNointegerRecords per page (default: 1000)

*Use either dateini/datefim or date, not both.

# Ranged (recommended)
curl "https://app.colmeia.agr.br/api/sl/data/YOUR_TENANT_ID/weather?dateini=01/11/2024&datefim=07/11/2024" \
  -H "Authorization: Bearer YOUR_TENANT_SECRET"

# Legacy single date
curl "https://app.colmeia.agr.br/api/sl/data/YOUR_TENANT_ID/weather?date=02/11/2024" \
  -H "Authorization: Bearer YOUR_TENANT_SECRET"

Error Codes

HTTPCodeMeaning
400missing_date_rangedateini or datefim not provided when using the ranged path
400invalid_date_rangeDate parse failure, dateini > datefim, or range exceeds 92 days
400missing_datedate not provided on legacy single-day path (refueling / weather)
401no_token_foundYour Solinftec account is not connected — contact MT2Data
502solinftec_fetch_failedUpstream error during ranged fan-out

Solinftec Integration

How to connect a Solinftec source to Colmeia and fetch operations, weather, and refueling data over the HTTP API. For the endpoint-by-endpoint field reference, see Solinftec API reference.


Overview

Your application (HTTP)
      │  GET /api/sl/data/{tenant_id}/...   Bearer <tenant-secret>
      ▼
  Colmeia middleware  (HTTP proxy)
      │  Solinftec SCDI API  (token managed for you)
      ▼
  Solinftec SCDI platform

The Colmeia middleware is an HTTP proxy in front of Solinftec's SCDI platform. It owns Solinftec token rotation, per-day fan-out, and response merging — you never manage Solinftec tokens. You call one Colmeia endpoint with a date range and get a single merged result back.


1. Connection setup

A tenant must be connected before data can be fetched.

curl -X POST https://app.colmeia.agr.br/api/integrations/{tenant_id}/connect \
  -H "Content-Type: application/json" \
  -b "session=<manager-session-cookie>" \
  -d '{
    "provider": "solinftec",
    "username": "alvaro_ribeiro",
    "password": "YOUR_PASSWORD",
    "auto_renew": true
  }'

Response:

{ "success": true, "data": { "provider": "solinftec", "connected": true, "expires_at": 2092433279, "auto_renew": true } }

Credentials are exchanged for a Solinftec token and are not stored in plaintext. The middleware re-authenticates automatically when the token chain breaks.

Check status:

curl "https://app.colmeia.agr.br/api/data/{tenant_id}/connections" \
  -H "Authorization: Bearer YOUR_TENANT_SECRET"

Revoke:

curl -X POST https://app.colmeia.agr.br/api/integrations/{tenant_id}/tokens/revoke \
  -H "Content-Type: application/json" \
  -b "session=<manager-session-cookie>" \
  -d '{"provider":"solinftec"}'

2. HTTP API

Base URL: https://app.colmeia.agr.br/api/sl
Auth header: Authorization: Bearer <tenant-secret>

All three endpoints accept a dateini/datefim date range. The middleware fans out one Solinftec pull per day internally, with bounded concurrency, and returns the merged result:

{ "data": [...], "days": 7, "total_rows": 294 }

Endpoints

EndpointData
GET /data/{tenant_id}/operationsField operation details (hourly, with text descriptions)
GET /data/{tenant_id}/weatherMeteorological data (hourly: rainfall, wind, temperature)
GET /data/{tenant_id}/refuelingTrain refueling records (fuel volume, hourmeter)

Common parameters

ParameterFormatNotes
dateiniDD/MM/YYYY or DD/MM/YYYY HH:MM:SSStart date, inclusive
datefimDD/MM/YYYY or DD/MM/YYYY HH:MM:SSEnd date, inclusive
sizeintegerRecords per day per internal page (default 1000)

/operations also accepts: equipamento, operacao, operador, unidade, talhao, ordemservico.

/weather and /refueling accept a legacy ?date=DD/MM/YYYY for single-day queries (backward compatibility).

Date cap

A single HTTP call is capped at 92 days (dateini..datefim). Ranges beyond that are rejected with invalid_date_range — split a longer window into sequential calls on your side.

Examples

# One week of operations
curl "https://app.colmeia.agr.br/api/sl/data/ribeiro/operations?dateini=10/09/2024&datefim=16/09/2024" \
  -H "Authorization: Bearer YOUR_TENANT_SECRET"

# 10 days of weather
curl "https://app.colmeia.agr.br/api/sl/data/ribeiro/weather?dateini=01/11/2024&datefim=10/11/2024" \
  -H "Authorization: Bearer YOUR_TENANT_SECRET"

# 10 days of refueling
curl "https://app.colmeia.agr.br/api/sl/data/ribeiro/refueling?dateini=01/02/2024&datefim=10/02/2024" \
  -H "Authorization: Bearer YOUR_TENANT_SECRET"

Error reference

HTTPerrorMeaning
400missing_date_rangedateini or datefim missing
400invalid_date_rangeDate parse failure, dateini > datefim, or range > 92 days
400missing_datedate missing on legacy single-day path
401no_token_foundTenant not connected
401no_refresh_tokenToken row exists but credentials were not stored
502solinftec_auth_failedSolinftec API unreachable during connect
401invalid_solinftec_credentialsWrong username or password
502solinftec_fetch_failedUpstream error during ranged fan-out
500Solinftec error bodyUpstream SCDI error (legacy single-date path)

See also: Solinftec API reference.

Syngenta Cropwise Integration

Overview

Access farm properties, fields, and monitoring data from Syngenta Cropwise through the Colmeia middleware. Your Cropwise account is connected to your tenant by MT2Data — you only need your tenant bearer secret to make requests.

Base URL: https://app.colmeia.agr.br/api/cw

Authentication

All data routes require your tenant bearer secret:

Authorization: Bearer <tenant-secret>

Organization scoping

Cropwise scopes every request to a single Organization (an internal Syngenta UUID). Cropwise has no API to list the organizations a token can access, so the OrgID is provisioned out-of-band by the Syngenta Digital onboarding team and stored against your tenant when MT2Data connects your account.

You do not pass an orgId query parameter on any data route. The middleware resolves the OrgID from your tenant binding on every request and forwards it to Cropwise. If your tenant has no OrgID on file, data routes return 400 no_syngenta_org — contact MT2Data to provision the org.


Farm Management

List Properties (Farms)

Endpoint: GET /cw/data/:tenantId/properties

curl https://app.colmeia.agr.br/api/cw/data/YOUR_TENANT_ID/properties \
  -H "Authorization: Bearer YOUR_TENANT_SECRET"

Response:

{
  "total_elements": 3,
  "content": [
    {
      "id": "property-uuid",
      "name": "Property Name",
      "field_count": 27,
      "total_area": 3864.4776,
      "state": "MT",
      "city": "City Name",
      "reference_point": {
        "type": "Point",
        "coordinates": [-52.78, -11.31]
      }
    }
  ]
}

List Fields

Endpoint: GET /cw/data/:tenantId/properties/:propertyId/fields

curl https://app.colmeia.agr.br/api/cw/data/YOUR_TENANT_ID/properties/PROPERTY_ID/fields \
  -H "Authorization: Bearer YOUR_TENANT_SECRET"

Response:

{
  "total_elements": 70,
  "content": [
    {
      "id": "field-id",
      "name": "Field Name",
      "area": 154.32,
      "crop_type": "Soybean",
      "boundary": { "type": "Polygon", "coordinates": [[]] }
    }
  ]
}

Monitoring Data

Get Field Indicators

Endpoint: GET /cw/data/:tenantId/monitoring/indicators

Get monitoring indicators (pest pressure, disease risk, etc.) for fields.

curl "https://app.colmeia.agr.br/api/cw/data/YOUR_TENANT_ID/monitoring/indicators?propertyId=PROPERTY_ID&start=2024-01-01&end=2024-12-31" \
  -H "Authorization: Bearer YOUR_TENANT_SECRET"

Query Parameters:

ParameterRequiredDescription
propertyIdYesProperty ID
startNoStart date (YYYY-MM-DD)
endNoEnd date (YYYY-MM-DD)

Get Geo-Referenced Monitoring Points

Endpoint: GET /cw/data/:tenantId/monitoring/points

curl "https://app.colmeia.agr.br/api/cw/data/YOUR_TENANT_ID/monitoring/points?propertyId=PROPERTY_ID" \
  -H "Authorization: Bearer YOUR_TENANT_SECRET"

Get Monitoring Changes (Incremental Sync)

Endpoint: GET /cw/data/:tenantId/properties/:propertyId/monitoring/changes

Fetch only observations that changed within a date range — efficient for incremental sync.

curl "https://app.colmeia.agr.br/api/cw/data/YOUR_TENANT_ID/properties/PROPERTY_ID/monitoring/changes?start=2026-01-25&end=2026-01-31" \
  -H "Authorization: Bearer YOUR_TENANT_SECRET"

Query Parameters:

ParameterRequiredDescription
startYesStart date (YYYY-MM-DD)
endYesEnd date (YYYY-MM-DD) — max 7 days from start
date_referenceNo"sync_date" or "observation_date" (default: "sync_date")

Agronomic Context

Get Current Season Crops

Endpoint: GET /cw/data/:tenantId/properties/:propertyId/crops

curl "https://app.colmeia.agr.br/api/cw/data/YOUR_TENANT_ID/properties/PROPERTY_ID/crops" \
  -H "Authorization: Bearer YOUR_TENANT_SECRET"

Query Parameters: date (YYYY-MM-DD, defaults to today)

Get Crops Catalog

Endpoint: GET /cw/data/:tenantId/catalog/crops

curl "https://app.colmeia.agr.br/api/cw/data/YOUR_TENANT_ID/catalog/crops?country=BR" \
  -H "Authorization: Bearer YOUR_TENANT_SECRET"

Field Notes & Observations

Get Field Notes

Endpoint: GET /cw/data/:tenantId/properties/:propertyId/notes

curl "https://app.colmeia.agr.br/api/cw/data/YOUR_TENANT_ID/properties/PROPERTY_ID/notes" \
  -H "Authorization: Bearer YOUR_TENANT_SECRET"

Code Example

const TENANT_ID = 'YOUR_TENANT_ID';
const BASE = 'https://app.colmeia.agr.br/api';
const headers = { Authorization: 'Bearer YOUR_TENANT_SECRET' };

// Get all properties
const properties = await fetch(`${BASE}/cw/data/${TENANT_ID}/properties`, { headers })
  .then(r => r.json());

// Get fields for first property
const propertyId = properties.content[0].id;
const fields = await fetch(
  `${BASE}/cw/data/${TENANT_ID}/properties/${propertyId}/fields`, { headers }
).then(r => r.json());

console.log(`${properties.total_elements} properties, ${fields.total_elements} fields`);

Error Codes

CodeStatusMeaning
no_token_found401Your Cropwise account is not connected — contact MT2Data
no_syngenta_org400Tenant has no OrgID on file — contact MT2Data so they can provision it from the OrgID provided by Syngenta Digital
authentication_failed500Stored credentials need to be refreshed — contact MT2Data

Troubleshooting

Common Errors

401 — Missing or invalid tenant secret

Cause: The Authorization: Bearer header is missing, empty, or contains an incorrect secret.

Fix: Verify your tenant secret is correct and included on every request:

Authorization: Bearer <your-tenant-secret>

401 — no_token_found

Cause: Your tenant does not have a connection configured for the provider you are trying to access.

Fix: Contact MT2Data to confirm that the integration (John Deere, Syngenta, Solinftec, or Datalake) has been enabled for your tenant.


403 — forbidden

Cause: Your tenant secret is valid but does not have access to the requested resource.

Fix: Confirm you are using the correct tenant ID in the URL path and that the secret belongs to that tenant.


502 / upstream errors

Cause: The upstream provider (John Deere, Syngenta, Solinftec, or MT2Data Datalake) returned an error or is temporarily unavailable.

Fix: Retry after a short wait. If the issue persists, use GET /api/data/:tenantId/connections to check which providers are currently connected and whether any have expired tokens.


no_token_found on a previously working provider

Cause: The stored provider token may have expired and automatic renewal failed.

Fix: Contact MT2Data support to re-connect the integration for your tenant.


Getting Help

If you encounter an issue not covered here, reach out through any of the following:

When contacting support, include:

  • Your tenant ID
  • The endpoint you were calling
  • The error code and HTTP status returned
  • Approximate time of the request

About Colmeia

Colmeia is the MT2Data middleware platform. It provides a unified API for accessing agricultural data from John Deere Operations Center, Syngenta Cropwise, Solinftec SCDI, and the MT2Data Datalake — all through a single tenant bearer secret, with all provider authentication handled server-side.

For more information about the MT2Data platform, visit mt2data.cloud.