In general
The API type is REST and the data format is JSON.
Where to start
The API documentation is available through Swagger. It shows:
All available endpoints
Required parameters
Request and response formats
Validation rules
Authentication requirements
Developers should use it as the technical reference, while this guide explains the overall structure and logic.
Base URL and versioning
The API currently uses versioned endpoints.
Most sandbox requests are sent to:
/api/v1/...
All endpoint paths in the documentation are relative to this base.
Authentication
Most endpoints require authentication using a Bearer token.
Requests must include:
Authorization: Bearer <token>
If authentication is missing or invalid, the API returns a 401 error.
All integrations should implement secure token handling and refresh logic if applicable. Learn more.
How the API is structured
The API is organized around several core concepts:
Attributes Reusable metadata fields that define what kind of data can be stored.
Industries and Categories
Classification and taxonomy data used for structuring products and documents.
Data Models Templates that define how documents are structured.
Documents The main business objects in the platform. Most integrations focus on creating, updating, and synchronizing documents.
EUDR Endpoints Specialized endpoints for building and maintaining EUDR-compliant datasets related to purchases, sales, batches, locations, and due diligence.
In practice, most integrations work by creating and updating documents that reference other entities and attributes.
Pagination
List endpoints use cursor-based pagination.
Typical responses include:
data(the actual records)links(pagination links)meta(metadata)
To retrieve more results:
Read the
links.nextvaluePass it as the
cursorparameter in the next request
The number of items per page is controlled with per_page (usually between 1 and 1000). All integrations that fetch lists must support cursor pagination and should not assume page numbers.
Identifiers: external_id
Most objects support an external_id.
This is intended to be the stable identifier coming from your own system (ERP, PIM, CRM, etc.).
Best practice:
Use
external_idas your primary reference keyKeep it consistent across syncs
Do not rely only on internal Prduct IDs
When linking entities (supplier, customer, product, etc.), external_id is usually preferred. This makes integrations more robust and easier to maintain.
Bulk operations
The API supports bulk creation of documents.
Bulk endpoints are useful when:
Importing large datasets
Running scheduled synchronizations
Onboarding new customers
When using bulk operations:
Handle partial failures
Log validation errors
Do not assume all items succeeded
Each item may be validated independently.
EUDR endpoints
EUDR endpoints help manage compliance-related data.
They are designed for:
Purchase documents
Sale documents
Batches and sub-batches
Locations
Due diligence statements
Key characteristics:
Support partial updates
Allow linking entities via
external_idSupport nested batch structures
Preserve existing data when not overwritten
These endpoints are best used when building or maintaining EUDR documentation workflows.
Recommended integration flow
A typical integration project should follow this sequence:
Set up authentication and test access
Read reference data (industries, categories, attributes)
Verify or create required attributes
Configure data models if needed
Implement document creation and updates using
external_idImplement EUDR workflows if relevant
Implement pagination for all list operations
Add logging, retries, and error handling
Following this order reduces validation issues and integration rework.
Core rules for stable integrations
For long-term stability, follow these principles:
Always use
external_idconsistentlyImplement cursor pagination
Handle translations correctly
Validate payloads before sending
Log all failed requests
Treat 422 errors as data-quality issues
Do not hardcode internal IDs
Use bulk endpoints for large datasets
Test in sandbox before production
Typical questions and standard answers
How do I paginate results?
Use the cursor value from links.next and pass it in the next request. Control page size with per_page.
Why do I get ‘is translatable’ errors?
The field must be sent inside translations[].attributes, not in top-level attributes.
How do I link suppliers, customers, or products?
Use their external_id when referencing them.
What identifier should I use?
Use external_id as your primary identifier and keep it stable.
When should I use bulk endpoints?
For large imports, onboarding, and scheduled synchronization jobs.
Typical errors & their causes
Error | Explanation | Solution |
403 Forbidden | Missing permissions/token | Check API keys and user permissions |
422 Name is required to create locations | locations used without an existing location document | Remove locations unless importing with GPS locations |
405 Method Not Allowed (PUT /documents) | PUT without document ID | Use URL with document_id |
PUT error on translations | PUT does not support the translation object | Use the translation endpoint |
Best practices for integration
Always use external_id as the primary update key unless otherwise agreed.
Create custom attributes before sending data; otherwise they are ignored/rejected.
Use sandbox.prduct.com/data-model to:
Create attributes
Check model names and input types
For importers, location objects are documents, and they must be created before they can be referenced.
For domestic batches, locations should not be used.
I get error message "The type field is required..."
This can be cause by several errors:
The type filed is not filled out correctly.
Using the wrong end-point.
Trying to send HTML/text via a Json bearer token.
Add "-ContentType 'application/json' to the body.
I get the error 422 "hs_code is translatable"?
Some fields in Prduct are defined as translatable. This means they cannot be sent directly in the top-level attributes object. Instead, they must be provided inside the translations array.
If you try an put a HS code like this:
},
"attributes": {
"hs_code": "XXXXXX"
},
You get this error:
"message": "hs_code is translatable"
This is due to the structure of the system. The HS code is a list of objects under translations. Your request need to be like this:
"translations": [
{
"attributes": {
"hs_code": [
{"value": "XXXXXX"}
]
}
}
]
Support and questions
If you encounter any issues or have questions along the way, feel free to contact us. Reach out via the chatbot in the lower-right corner or email us at [email protected]
