Get clientId, clientSecret, apiKey, apiSecret, and the registered callback URL.
FMS Open Platform
Third-Party Integration Notice
This page is for third-party integrators and summarizes credential preparation, OAuth2 token exchange, open API calling rules, request signing, error codes, and integration recommendations.
Overview
First receive credentials, then finish OAuth2 authorization and token exchange, and finally call open APIs with signed requests.
When a third-party system connects to FMS Open Platform, it must first receive client credentials and signing credentials from the platform. The authorization flow is used to obtain an access token. Business APIs are called through
/openapi/** and must include the token, API Key, timestamp, nonce, and signature in the request headers.
Use the one-time authorization code with /oauth2/token to obtain an access_token.
Sign the path, query string, and request body, then call /openapi/** with the required headers.
Preparation
Before integration, the platform should provide client credentials, signing credentials, and the registered redirect URI.
Before integration, the platform should provide the following credentials:
clientIdclientSecretapiKeyapiSecret- Registered
redirectUri
| Credential | Purpose | Notes |
|---|---|---|
clientId + clientSecret |
Use /oauth2/token to obtain or refresh a token. |
clientSecret is sensitive. The platform does not expose an interface to retrieve the current plain-text secret. |
apiKey + apiSecret |
Generate request signatures when calling /openapi/**. |
apiSecret is sensitive and should never appear in front-end pages, logs, or public configuration. |
redirectUri |
Receives callback parameters after authorization completes. | It must be registered in advance and must match exactly during token exchange. |
clientSecret is lost, contact a platform administrator to rotate it. Do not share full secrets or tokens through logs, screenshots, or ticket bodies.
OAuth2 Authorization and Token Exchange
After authorization, the callback returns code, state, and domain, which are then used to exchange for an access token.
Authorization result
After a user completes authorization, the third-party callback address receives code, state, and domain.
code: one-time authorization code.state: pass-through state value originally sent by the third party.domain: used to choose the target service domain for subsequent open platform requests.
Exchange authorization code for token
POST /oauth2/token
Content-Type: application/json
{
"grantType": "authorization_code",
"code": "authorization-code",
"redirectUri": "https://third.example.com/callback",
"clientId": "your-client-id",
"clientSecret": "your-client-secret"
}
Successful response example:
{
"code": 0,
"message": "Success",
"data": {
"access_token": "access-token",
"token_type": "Bearer",
"scope": "default"
},
"requestId": "req-1234567890abcd",
"timestamp": 1760000000000
}
- Request fields use camelCase, such as
grantType. - Token fields in the response use snake_case, such as
access_token. - An authorization code can be consumed only once.
- Missing, expired, or already consumed authorization codes currently map to
10004. - Tokens do not use a fixed absolute expiration strategy. As long as valid requests continue, the platform renews them automatically.
Refresh token
{
"grantType": "refresh_token",
"refreshToken": "old-access-token",
"clientId": "your-client-id",
"clientSecret": "your-client-secret"
}
Pass the previous access token through the refreshToken field.
Open API Calling Rules
All open business APIs use /openapi/** and require the shared authentication headers plus the request signature.
All open business APIs use the /openapi/** prefix, for example /openapi/customer/page, /openapi/farm/page, and /openapi/task/page.
Required headers
Authorization: Bearer <access_token>
X-Api-Key: <apiKey>
X-Timestamp: <unix timestamp in milliseconds>
X-Nonce: <unique value per request>
X-Signature-Version: v1
X-Signature: <signature result>
Content-Type: application/json
HTTP status codes
| Status | Meaning |
|---|---|
200 OK |
The request was processed successfully. Continue interpreting the business result through the response body code. |
400 Bad Request |
Parameters are invalid or missing, or the request format does not match expectations. |
401 Unauthorized |
Authentication failed, such as a missing Authorization header, an invalid token, a missing signature, or signature validation failure. |
403 Forbidden |
The server received the request, but the current client is disabled or a downstream business validation failed. |
404 Not Found |
The requested path does not exist. |
429 Too Many Requests |
Rate limiting was triggered. |
For /openapi/**, signature-related failures currently return HTTP 401. Some 10001 responses may include a more specific message, but program logic should rely on code.
Unified response structure
{
"code": 0,
"message": "Success",
"data": {},
"requestId": "req-xxxx",
"timestamp": 1760000000000
}
{
"code": 10014,
"message": "Request signature is invalid",
"data": null,
"requestId": "req-xxxx",
"timestamp": 1760000000000
}
Log the request path, request time, HTTP status, requestId, and response code on the caller side.
Signature Rules
The signature uses HmacSHA256 plus Base64, based on method, path, canonical query string, body hash, and shared header values.
Algorithm
- Algorithm:
HmacSHA256 - Output:
Base64 - Version:
v1 - Key: the assigned
apiSecret
Signature validation proves that the request was sent by an integrator holding the correct apiSecret and that the request was not modified in transit.
String to sign
HTTP_METHOD + "\n" +
REQUEST_PATH + "\n" +
CANONICAL_QUERY_STRING + "\n" +
BODY_SHA256 + "\n" +
X-Api-Key + "\n" +
X-Timestamp + "\n" +
X-Nonce
HTTP_METHODmust be uppercase, such asGETorPOST.REQUEST_PATHmust be the full request path without domain, protocol, or QueryString.CANONICAL_QUERY_STRINGis the sorted and encoded query string without the leading?.- Query parameters must be sorted by parameter name, then by parameter value when names are equal.
- Both query keys and values should be UTF-8 encoded and then URL-encoded. In Java,
URLEncoderis recommended, and+should be replaced with%20. - If no query parameters exist, the blank line must still be preserved.
BODY_SHA256is the SHA-256 of the raw request body bytes in lowercase hexadecimal.X-Api-Key,X-Timestamp, andX-Noncemust match the actual request header values exactly.
The SHA-256 for an empty request body is always:
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
Canonical Query String example
/openapi/task/page?pageNum=1&pageSize=20&name=demo%20task
The CANONICAL_QUERY_STRING that participates in signing is:
name=demo%20task&pageNum=1&pageSize=20
Do not include the leading ? or the full URL in the string to sign.
Body hash rule
The hashed content must be the exact JSON byte sequence that is ultimately sent. Re-serializing after signing can change field order or whitespace and break signature validation.
{"name":"demo","pageNum":1,"pageSize":20}
Signing flow
- Prepare the request method, path, query parameters, and raw request body.
- Compute
CANONICAL_QUERY_STRING. - Compute
BODY_SHA256. - Build the string to sign in the fixed field order, using
\nbetween lines. - Use
apiSecretto applyHmacSHA256to the string to sign. - Base64-encode the result and place it in the
X-Signatureheader.
Common signature failures
10013 SIGNATURE_REQUIRED: usually meansX-SignatureorX-Signature-Versionis missing.10014 SIGNATURE_INVALID: first check whether the request path included the domain, whether query parameters were sorted, and whether the body was re-serialized after signing.10015 SIGNATURE_TIMESTAMP_EXPIRED: check whether the client machine time differs too much from standard time.10016 SIGNATURE_NONCE_REPLAY: the sameX-Noncewas reused.- If headers look correct but validation still fails, verify that the correct
apiSecretis being used for the right environment. Test and production credentials must not be mixed.
Anti-Replay Requirements
The timestamp must stay inside the allowed window, and a nonce can be used only once within that window.
X-Timestampmust fall inside the allowed time window.X-Noncecan be used only once inside the valid window.- Reusing a nonce returns
10016.
Current Open API List
The currently exposed interfaces are organized into master data, business operations, and prescription or sampling groups.
Master data APIs
POST /openapi/customer/pagePOST /openapi/farm/pagePOST /openapi/farmland/pagePOST /openapi/boundary/pagePOST /openapi/baseline/pagePOST /openapi/employee/page
Business and operation APIs
POST /openapi/task/pagePOST /openapi/agriPlan/pagePOST /openapi/graderTask/pagePOST /openapi/grader/pagePOST /openapi/machine/pagePOST /openapi/machineTools/pagePOST /openapi/marker/pagePOST /openapi/kitAutoSteering/page
Prescription and sampling APIs
POST /openapi/imagePrescription/pagePOST /openapi/simplePrescription/pagePOST /openapi/soilPrescription/pagePOST /openapi/yieldPrescription/pagePOST /openapi/sampleGroup/pagePOST /openapi/sampleGroup/samplePoints/list
Common Error Codes
The main error groups cover token and authorization, signature and security, parameter validation, rate limiting or idempotency, and system failures.
| Category | Codes | Description |
|---|---|---|
| Token and authorization | 10001 INVALID_TOKEN10004 INVALID_AUTHORIZATION_CODE20001 CLIENT_NOT_FOUND20002 CLIENT_DISABLED20003 CLIENT_SECRET_MISMATCH30001 REDIRECT_URI_MISMATCH30002 REDIRECT_URI_NOT_ALLOWED |
Missing, expired, or already consumed authorization codes currently map to 10004. |
| Signature and security | 10010 API_KEY_INVALID10011 API_KEY_DISABLED10012 API_KEY_EXPIRED10013 SIGNATURE_REQUIRED10014 SIGNATURE_INVALID10015 SIGNATURE_TIMESTAMP_EXPIRED10016 SIGNATURE_NONCE_REPLAY |
10010 is protocol-reserved. In the current implementation, an unknown apiKey may appear as 20001 CLIENT_NOT_FOUND. |
| Parameter and business validation | 20004 ACCESS_VALIDATION_FAILED40001 INVALID_PARAM40002 PARAM_REQUIRED40003 PARAM_OUT_OF_RANGE40004 PARAM_FORMAT_ERROR |
20004 means the request passed open platform authentication but failed downstream FMS validation. |
| Rate limit and idempotency | 50001 RATE_LIMIT_EXCEEDED50002 IDEMPOTENCY_KEY_REQUIRED50003 IDEMPOTENCY_KEY_CONFLICT |
50002 and 50003 are returned only when idempotency checks are enabled and the endpoint requires Idempotency-Key. |
| System errors | 90001 INTERNAL_ERROR90004 REMOTE_CALL_ERROR |
System exceptions usually collapse into 90001 or 90004. Third-party callers typically do not receive 90002 or 90003 directly in the current version. |
Integration Recommendations
During integration, wrap a shared client, record requestId, and finish test-environment verification before asking for production credentials.
- Wrap a shared HTTP client on the caller side to centralize signing and common headers.
- Record the
requestIdfrom every response to make joint debugging and issue tracing easier. - Do not reuse
X-Nonce. - During integration, let your program logic prioritize the response body
code;messageis better suited to log analysis. - Third parties should complete test-environment verification before requesting production endpoints and related details. The platform can reject production credential issuance if test-environment integration has not been completed.
- Do not print full
apiSecret, fullaccess_token, or full authorization codes in logs.