# API Reference Welcome! This guide will get you up and running with our API. Our goal is to provide a powerful and intuitive interface that is easy to integrate with. Our API is designed using an **RPC (Remote Procedure Call) style over HTTP**. This means that instead of focusing on RESTful resources (nouns), you'll interact with **operation-centric** methods that represent clear business actions (verbs). # Core Principles We designed the API with three key principles in mind to make your development experience as smooth as possible. - **Domain-driven Design:** Our API is organized into domain-specific **namespaces** that logically group related operations. This domain-oriented design simplifies method discovery and ensures that you are always interacting with the correct part of the system. - **Business Process-Oriented:** Our API methods are designed to mirror your real-world business processes. Instead of generic data manipulation, you'll call functions that represent distinct steps in your workflow. For example, you'll call `setGreenLotWeight` or `transferGreenLotToLocation`, directly matching the actions your team performs. - **Data Consistency:** To guarantee data integrity, our API treats each business operation as a single, atomic request. This approach bundles all data changes into one call, preventing the data corruption and inconsistencies that can occur when an operation is split across multiple requests. # Request Format {% table %} - Criteria {% width="30%" %} - Description --- - **HTTP Method** - Our API exclusively uses the `POST` HTTP method for all operations. The specific action you wish to perform (e.g., retrieving, creating, or updating data) should be specified within the request body, rather than by using different HTTP verbs like `GET`, `PUT`, or `DELETE`. --- - **Protocol & Security** - All communication with the API must be made over **HTTPS**. For security, connections made over unencrypted HTTP will be rejected. --- - **Base URL** - The **base path** for all endpoints is `https://api.cropster.com/rpc/v1` where `v1` is the current version of the API. --- - **URL Path Schema** - The endpoints are **hierarchical structure** using dotted namespaces to reflect the business domain. This structure allows for clear organization and easy discovery of endpoints related to specific business operations. The following endpoint naming schema is used for all endpoints: `{domain}.{subdomain}.{operation}` (e.g., `inventory.roast.listRoastedLots`). --- - **Content-Type** - All POST requests must include a `Content-Type` header set to `application/json`. Requests with a different content type, or without this header, will be rejected. The only exception to this is the OAuth token request, which requires a `Content-Type` of `application/x-www-form-urlencoded`. --- - **Payload** - Request and response bodies are in **JSON** format with **camelCase** field names. **Singular nouns** are generally used for fields representing single entities (e.g. `locationId`). **Plural nouns** are used for fields representing lists of entities (e.g. `greenLots`). {% /table %} # Authentication The Cropster API uses the **OAuth 2.0 Client Credentials Grant** flow to authenticate all requests. This is a server-to-server authentication method where applications authenticate directly rather than on behalf of a user. The process involves two main steps which are explained in the following. ### Generate API Credentials Before you can connect to the API, you must create a Service Account in the Cropster user interface to obtain a `Client ID` and `Client Secret`. 1. Log in to your [Cropster account](https://c-sar.cropster.com) and navigate to the **Settings > Service Accounts** section. 2. Create a new **Service Account**. 3. Assign a name and the required **OAuth scopes** that define the specific permissions for this account (e.g., `inventory.roast` to access roast inventory data). 4. Upon creation, your `Client ID` and `Client Secret` will be displayed. {% admonition type="warning" name="Secure Your Credentials" %} Your `Client Secret` is highly sensitive and is only displayed once upon creation. Store it securely and treat it like a password. Do not expose it in client-side code. {% /admonition %} ## Request Access Token Next, exchange your credentials for a temporary access token by making a `POST` request against the OAuth2 token endpoint: `https://auth.cropster.com/oauth2/token`. Note that the `scope` parameter must include all OAuth scopes that are required for subsequent API requests. For example, to access roasted inventory data, the `inventory.roast` scope must be included. {% openapi-code-sample descriptionFile="../oauth/oauth-api.yaml" operationId="oauth2Token" /%} If the request is successful, the response contains the access token that must be set as `Bearer: ` in the `Authorization` header of all subsequent API requests. {% markdoc-example renderDemo=false %} ```markdown {% title="Successful Response" %} { "access_token": "", "expires_in": 28799, "scope": "inventory.green%20inventory.roast%20inventory.blend", "token_type": "bearer" } ``` {% /markdoc-example %} {% admonition type="info" name="Access Token Lifetime" %} The access token is valid for **8 hours**. You should cache the token in your application and reuse it until it expires to reduce latency and avoid unnecessary token requests. {% /admonition %} ---

Request Format

This section details the required request format for obtaining an access token and the structure of the response you will receive.

Request Parameters

The following parameters are required for the access token request: {% json-schema schema={ "$ref": "../oauth/oauth-api.yaml#/components/schemas/oauth2TokenRequest" } /%}

Response Fields

A successful request returns the access token along with its associated metadata: {% json-schema schema={ "$ref": "../oauth/oauth-api.yaml#/components/schemas/oauth2TokenResponse" } /%} # Error Handling Each API request is returning a status code that indicates if the request was successfully completed. In the following, the most common HTTP status codes are listed: {% table %} - HTTP Status Code {% width="30%" %} - Description --- - **200 OK** - The request was successful. --- - **400 Bad Request** - The request couldn't be processed by the server due to an invalid request. Possible reasons can be missing or invalid query parameters, invalid JSON payload or malformed URL. --- - **401 Unauthorized** - The provided authentication credentials are not correct. Please check the section Authentication on how to provide valid authentication credentials. --- - **403 Forbidden** - The client doesn't have permissions to perform the request. Please check the endpoint documentation on which permissions are required. --- - **405 Method Not Allowed** - This error indicates that the requested operation is not supported. For example, this error can be caused when a POST request is not supported by an endpoint. --- - **422 Unprocessable Entity** - The request failed due to semantic errors in the request body. Examples of semantic errors are missing attributes or the violation of business rules (e.g. creating a green lot with a negative weight). --- - **429 Too Many Requests** - The client has sent too many requests in a given amount of time. Please check the Rate Limiting section for more details. --- - **500 Server Error** - An internal error encountered within Cropster. Please check the Cropster status page to verify if all systems are operational. --- {% /table %} To handle errors programmatically, each error response contains one of the following error codes: {% table %} - Error Code {% width="30%" %} - Description --- - **invalid_authentication** - Indicates that the authentication credentials provided are invalid. For example, the JWT is missing or is expired. --- - **access_denied** - Indicates that the user is authenticated but does not have the required permissions to access the requested resource. For example, a user without the appropriate role attempts to perform a restricted operation. --- - **resource_not_found** - Indicates that the specified resource could not be found. For example, an object is request by an ID that does not exist. --- - **invalid_weight** - Indicates that the weight parameter in the request is invalid. For example, a negative weight amount is specified. --- - **invalid_price** - Indicates that the price parameter in the request is invalid. For example, a negative price amount is provided. --- - **invalid_parameter** - A general-purpose error indicating that one or more parameters in the request failed validation. This is a fallback error and should include a descriptive message with more detail. Note, this error should not normally be returned unless a more specific code is not applicable. --- - **missing_parameter** - Indicates that a required parameter is missing from the request. For example, the name property is omitted in the `importGreenLot` request. --- - **unsupported_currency** - Indicates that the specified currency is not an ISO 8601 compliant currency code. --- - **unsupported_unit** - Indicates that the specified weight unit is not supported. Only `KG` and `LBS` are currently accepted. --- - **too_many_requests** - Indicates that the client has sent too many requests in a given amount of time. --- - **server_error** - Indicates an internal server error occurred while processing the request. The accompanying error message should provide additional context. --- {% /table %} # Pagination The RPC API uses cursor-based pagination for read-centric, listing endpoints. The results are delivered in reverse-chronological order. This means that the most recently created results appear first in the result set. For the time being, only forward navigation is supported. The default page size is set to 50 items per page. The `meta.pagination.endCursor` field in the response indicates if there are more pages. Pass this cursor value in the `params.pagination.after` field of the next request to retrieve the next page. If there are no further pages, `meta.pagination.endCursor` will be null. ---

Pagination Request Parameters

{% json-schema schema={ "title": "", "type": "object", "properties": { "params.pagination.after": { "type": "string", "description": "Cursor value to retrieve the result of the next page. This value is obtained from the `meta.pagination.endCursor` field of the previous response. If not specified or `null`, the first page of results is returned.", }, "params.pagination.limit": { "type": "int", "description": "Specifies the page size of the result set. The value must be in the range between 1 and 100. If not specified, the default value of 50 is used.", "minimum": 1, "maximum": 100 } } } /%}

Pagination Response Field

{% json-schema schema={ "title": "", "type": "object", "properties": { "meta.pagination.endCursor": { "type": "string", "description": "Cursor value to retrieve the records of the next page. This value should be passed in the `params.pagination.after` field of the next request. If there are no further pages, this value is `null`." } } } /%}

Example

In the following the pagination mechanism is explained using the `inventory.roast.listRoastedLots` endpoint as an example. The first request retrieves the first page of roasted lots created after `2025-01-01T00:00:00Z` with a page size of 10 records. Notice, the `after` field is set to `null` to indicate that the first page should be returned. {% markdoc-example renderDemo=false %} ``` JSON {% title="First request to retrive first page" %} POST /inventory.roast.listRoastedLots Content-type: application/json Authorization: Bearer { "params": { "filter": { "roastedDate": { "from": "2025-01-01T00:00:00Z" } }, "pagination": { "after": null, "limit": 10 } } } ``` {% /markdoc-example %} The response of the above request contains the `meta.pagination.endCursor` field that can be used to retrieve the next page. This value should be passed in the `params.pagination.after` field of the next request. If there are no further pages, `meta.pagination.endCursor` will be null. {% markdoc-example renderDemo=false %} ```JSON {% title="Paginated response" %} { "ok": true, "result": { "roasts": [ ... ] }, "meta": { "pagination": { "endCursor": "aBc=" } } } ``` {% /markdoc-example %} Since an `endCursor` value of `aBc=` was returned in the previous response, there are more pages available. To retrieve the next page, use this value in the `params.pagination.after` field in the next request. {% markdoc-example renderDemo=false %} ``` JSON {% title="Second request to retrieve the next page" %} POST /inventory.roast.listRoastedLots Content-type: application/json Authorization: Bearer { "params": { "filter": { "roastedDate": { "from": "2025-01-01T00:00:00Z" } }, "pagination": { "after": "aBc= } } } ``` {% /markdoc-example %} # Rate Limiting To ensure fair usage and maintain optimal performance of the API, rate limiting is enforced on all endpoints. If a client exceeds the specified limits, the API will respond with an `429 Too Many Requests` HTTP status code. Our standard rate limits are set as follows: - **Rate Limit:** 5 requests per second. This is the average throughput your application is allowed to execute. - **Burst Limit:** 10 requests per second. Allows for short-term spikes in traffic. For example, your application can send up to 10 requests in a single, as long as the average rate remains within the 5 req/sec sustained limit. # Versioning Our API is versioned to ensure that your integration remains stable and that future updates do not introduce breaking changes unexpectedly. We use URI path versioning, where the version is explicitly included in the request path. - **Current Version:** The current stable version of our API is `v1`. - **Future Versions:** When we introduce backward-incompatible changes, we will release a new API version (e.g., `v2`, `v3`). Older versions are supported for a reasonable time, with a clear migration guide provided well in advance of retirement. ## Servers ``` https://api.cropster.com/rpc/v1 ``` ## Security ### oauth2 Type: oauth2 ## Download OpenAPI description [API Reference](https://docs.cropster.com/_spec/api/rpc/reference.yaml) ## Green The `inventory.green` namespace contains all operations for managing your green lots. With this API, you can: - Import green lots from your ERP system to Cropster. - Transfer green inventory to another location. - Make weight adjustments to existing green lots. - Retrieve the existing green lots from you inventory. ### Transfer Green Lot To Location - [POST /inventory.green.transferGreenLotToLocation](https://docs.cropster.com/api/rpc/reference/green/transfergreenlottolocation.md): Transfers weight from a given green lot to another location. When transferring green lot weight the following cases need to be distinguish: - When the green lot hasn't yet transferred to the destination location, a new green lot in the destination location will be created. - When the green lot has already been transferred to the specified destination location, the green lot weight in the destination location will be increased. Please consider the following business constraints before you execute your request: - Consumed lots cannot be transferred - Transferred weight may not be negative - Transferred weight may be less or equal than the origin green lot weight ### Set Green Lot Weight - [POST /inventory.green.setGreenLotWeight](https://docs.cropster.com/api/rpc/reference/green/setgreenlotweight.md): Sets a new weight for a given green lot. When the green lot weight set it zero, the green lot will be marked as consumed. Notice that a negative weight is not supported. ### List Green Lots - [POST /inventory.green.listGreenLots](https://docs.cropster.com/api/rpc/reference/green/getgreenlots.md): Retrieves a list of green lots from the inventory. ### Import Green Lot - [POST /inventory.green.importGreenLot](https://docs.cropster.com/api/rpc/reference/green/importgreenlot.md): Imports a new green lot from an external system (e.g. ERP) into Cropster by an external identifier (= ). Optionally, providing the warehouse via location is possible, by setting the property. ## Roast Currently, the `inventory.roast` namespace allows you to retrieve roasted lots from your inventory. ### List Roasted Lots - [POST /inventory.roast.listRoastedLots](https://docs.cropster.com/api/rpc/reference/roast/getroastedlots.md): Retrieves a list of roasted lots from inventory, optionally filterable by an inclusive roasting date. ### Get Roast Details - [POST /inventory.roast.getRoastDetailsByIds](https://docs.cropster.com/api/rpc/reference/roast/getroastdetailsbyids.md): Gets detailed information about roasts by their IDs. ## Blend Currently, the `inventory.blend` namespace allows you to retrieve blended lots from your inventory. ### List Blended Lots - [POST /inventory.blend.listBlendedLots](https://docs.cropster.com/api/rpc/reference/blend/getblendedlotslist.md): Retrieves a list of post-roast blended lots from inventory, optionally filterable by an inclusive blended date.