Table of Contents

Directo API Documentation

Welcome to the Directo API - a comprehensive RESTful API for accessing and managing your ERP data including items, orders, customers, invoices, stock levels, and more.

πŸš€ Getting Started

Prerequisites

Quick Start Guide

  1. Configure Authentication: Set your API key in the collection's Authorization tab or update the X-Directo-Key header
  2. Set Variables: Configure baseUrl and version in collection variables
  3. Choose Format: Set the Accept header to application/json or application/xml
  4. Make Your First Request: Try the β€œAll items” request to retrieve your item catalog

Base URL & Versioning

Base URL Structure:

{{baseUrl}}/v{{version}}/{resource}

Current Configuration:

Example Full URL:

[https://login.directo.ee/apidirect/v1/items](https://login.directo.ee/apidirect/v1/items)

The API uses versioning to ensure backward compatibility. Always specify the version number in your requests.

πŸ” Authentication

The Directo API uses API Key authentication for secure access.

How to Authenticate

Include your API key in the request header:

X-Directo-Key: YOUR_API_KEY_HERE

Getting Your API Key

Contact your Directo system administrator to obtain an API key. Each key is associated with specific permissions and access levels.

Security Best Practices

πŸ“‹ Response Formats (JSON vs XML)

The API supports both JSON and XML response formats. Control the format using the Accept header.

Accept: application/json

Example Request:

curl -X GET "{{baseUrl}}/v{{version}}/items"
 
-H "X-Directo-Key: YOUR_API_KEY"
 
-H "Accept: application/json"

XML Format

Accept: application/xml

Example Request:

curl -X GET "{{baseUrl}}/v{{version}}/items"
 
-H "X-Directo-Key: YOUR_API_KEY"
 
-H "Accept: application/xml"

πŸ” Advanced Filtering (Key Feature)

🎯 ERP-Style Filtering - The Power of Directo API

⭐ CRITICAL FEATURE: The Directo API supports the exact same powerful filtering capabilities as the Directo ERP system itself.

This is one of the most powerful features of the Directo API. Filters can be applied like default filters inside the ERP system. All fields can be used for filters except calculated fields.

What This Means for Developers

Understanding Filterable vs Calculated Fields

βœ… Filterable Fields (Stored in Database) These are fields that are stored directly in the database and can be used for filtering:

❌ Calculated Fields (Cannot Be Filtered) These are fields computed on-the-fly and cannot be used for filtering:

How to Identify Calculated Fields

Practical Examples: Filterable vs Calculated

Example 1: Item Stock

βœ… WORKS: GET /items?quantity=>100
(quantity is stored in database)
❌ DOESN'T WORK: GET /items?available_stock=>100
(if available_stock = quantity - reserved, it's calculated)

Example 2: Order Totals

βœ… WORKS: GET /orders?row_price=>1000
(row_price is stored per line item)
❌ MIGHT NOT WORK: GET /orders?order_total=>5000
(if order_total is sum of all line items, it's calculated)
βœ… ALTERNATIVE: GET /orders?date=>2025-01-01&status=COMPLETED
(then calculate totals in your application)

Example 3: Customer Data

βœ… WORKS: GET /customers?country=EE&city=Tallinn
(both are stored fields)
❌ DOESN'T WORK: GET /customers?full_address=*Tallinn*
(if full_address is concatenation of address+city+country)
βœ… ALTERNATIVE: GET /customers?city=Tallinn
(filter by individual stored fields)

Basic Filtering

Filter by exact match using any stored field name:

GET {{baseUrl}}/v{{version}}/items?code=9810
GET {{baseUrl}}/v{{version}}/items?status=UUS
GET {{baseUrl}}/v{{version}}/orders?number=12345
GET {{baseUrl}}/v{{version}}/customers?country=EE
GET {{baseUrl}}/v{{version}}/items?class=KAUP

Key Principle: Use the exact field name as it appears in the API response (or as you see it in the ERP system).

Comparison Operators

The API supports powerful comparison operators for advanced filtering:

Greater Than (>)

GET {{baseUrl}}/v{{version}}/orders?date=>2025-09-01T00:00:00
GET {{baseUrl}}/v{{version}}/invoices?row_quantity=>5000

Less Than (<)

GET {{baseUrl}}/v{{version}}/orders?date=<2025-09-03T00:00:00
GET {{baseUrl}}/v{{version}}/invoices?row_quantity=<5000

Not Equal (!)

GET {{baseUrl}}/v{{version}}/items?country=!EE
GET {{baseUrl}}/v{{version}}/orders?status=!CLOSED

Greater Than or Equal (>=)

GET {{baseUrl}}/v{{version}}/items?price=>=100
GET {{baseUrl}}/v{{version}}/orders?date=>=2025-01-01T00:00:00

Less Than or Equal (⇐)

GET {{baseUrl}}/v{{version}}/items?weight=<=5.5
GET {{baseUrl}}/v{{version}}/orders?date=<=2025-12-31T23:59:59

Range Filtering

Combine operators to create ranges (AND logic):

GET {{baseUrl}}/v{{version}}/orders?date=>2025-09-01T00:00:00&date=<2025-09-03T00:00:00
GET {{baseUrl}}/v{{version}}/items?quantity=>10&quantity=<100

Multiple Values (OR Logic)

Use comma-separated lists to filter by multiple values:

GET {{baseUrl}}/v{{version}}/items?warehouse=AALTR,AIPM,WAREHOUSE1
GET {{baseUrl}}/v{{version}}/orders?status=NEW,PENDING,PROCESSING
GET {{baseUrl}}/v{{version}}/customers?country=EE,LV,LT

Timestamp-Based Filtering (Synchronization)

Use the ts parameter to retrieve records modified after a specific timestamp (ideal for synchronization):

GET {{baseUrl}}/v{{version}}/items?ts=>2025-10-01T08:11:05.129Z
GET {{baseUrl}}/v{{version}}/customers?ts=>2025-01-01T00:00:00Z

Best Practice: Store the timestamp of your last successful sync and use it in the next request to fetch only changed records.

Filtering by Line Item Fields

For resources with line items (orders, invoices), you can filter by line-level fields:

GET {{baseUrl}}/v{{version}}/orders?row_item=343443
GET {{baseUrl}}/v{{version}}/invoices?row_quantity=>10

Note: When filtering by line item fields, the API returns the entire document (order/invoice) if ANY line matches the filter.

Filtering by Custom Data Fields

If you have custom fields defined in your ERP system (visible in the datafields array), you can filter by them:

GET {{baseUrl}}/v{{version}}/items?IS_WEIGHT=1
GET {{baseUrl}}/v{{version}}/items?VISUAL_VERIFICATION=1

How to Find Custom Field Names: Make a request without filters and examine the datafields array in the response.

Complex Filter Combinations

Combine multiple filters to create sophisticated queries:

Get new orders from the last week for a specific customer:

GET {{baseUrl}}/v{{version}}/orders?status=NEW&date=>2025-11-13T00:00:00&customer_code=CUST001

Get items with low stock in specific warehouses, excluding closed items:

GET {{baseUrl}}/v{{version}}/items?quantity=<10&warehouse=AALTR,AIPM&status=!CLOSED

Common Filter Parameters by Resource

Parameter Description Example Applicable Resource
ts Timestamp for modified records (ISO 8601) 2025-10-01T08:11:05.129Z All resources
date Date filtering (supports operators) >2025-09-01T00:00:00 Orders, Invoices
number Document number 12345 or !001 Orders, Invoices
code Item/Customer code 9810 or CUST001 Items, Customers
name Name search Kalev Items, Customers
status Status filter UUS, CLOSED, NEW Orders, Items
country Country code (ISO 2-letter) EE, !EE Items, Customers
warehouse Warehouse/stock location code AALTR,AIPM Items, Stock Levels, Orders
quantity Quantity filter (supports operators) >100, <50 Items, Stock Levels
row_item Item code in line items 9810 or PROD-ABC Orders, Invoices
closed Closed status 1 (closed), 0 (open) Customers, Orders

Filter Best Practices

Troubleshooting Filters

Problem: Filter returns no results

Problem: Filter seems to be ignored

Problem: Unexpected results

πŸ“¦ API Resources & Endpoints

API Resources and Endpint can be found in Postman collection. Response field list managed in Directo ERP.

Postman collection can be downloaded here:POSTMAN

πŸ“Š Response Structure

Success Response (HTTP 200)

JSON Format:

[
{
"code": "1011",
"class": "KAUP",
"name": "Kommid Lily, Kalev",
"price": 12.50,
"quantity": 150,
"warehouse": "AALTR",
"datafields": [
{
"code": "TEST_ARTIKKEL",
"content": "Test lisavΓ€li sisu"
},
{
"code": "IS_WEIGHT",
"content": "0"
},
{
"code": "VISUAL_VERIFICATION",
"content": "0"
},
{
"code": "VENSAFE",
"content": "0"
}
]
},
{
"code": "1012",
"class": "KAUP",
"name": "Ε okolaad Kalev",
"price": 8.75,
"quantity": 200,
"warehouse": "AIPM",
"datafields": []
}
]

XML Format:

<items>
<item code="1011" class="KAUP" name="Kommid Lily, Kalev" price="12.50" quantity="150" warehouse="AALTR">
<datafields>
<data code="TEST_ARTIKKEL" content="Test lisavΓ€li sisu"/>
<data code="IS_WEIGHT" content="0"/>
<data code="VISUAL_VERIFICATION" content="0"/>
<data code="VENSAFE" content="0"/>
</datafields>
</item>
<item code="1012" class="KAUP" name="Ε okolaad Kalev" price="8.75" quantity="200" warehouse="AIPM">
<datafields/>
</item>
</items>

Response Characteristics

⚠️ Error Handling

HTTP Status Codes

Status Code Meaning Description
200 OK Request successful
400 Bad Request Invalid parameters or malformed request
400 API not enababled Resource not enabled for this API key
401 Unauthorized Missing or invalid API key
403 Forbidden API key lacks required permissions
404 Not Found Resource or endpoint not found
429 Too Many Requests Rate limit exceeded
500 Internal Server Error Server-side error
503 Service Unavailable API temporarily unavailable

Error Response Format

{
"error": {
"code": "INVALID_API_KEY",
"message": "The provided API key is invalid or expired",
"details": "Please check your API key and try again"
}
}

Common Error Scenarios

401 Unauthorized:

403 Forbidden:

400 Bad Request:

404 Not Found:

429 Too Many Requests:

500 Internal Server Error:

🚦 Rate Limiting & Performance

Rate Limits

While specific rate limits depend on your account tier, follow these guidelines:

Performance Best Practices

1. Use Timestamp Filtering for Sync Instead of fetching all records repeatedly, use the ts parameter:

GET {{baseUrl}}/v{{version}}/items?ts>=2025-11-20T07:00:00Z

* Benefits: Reduces data transfer, Faster response times, Lower server load, Stays within rate limits

2. Implement Pagination with Date Ranges For large datasets, break requests into smaller chunks:

# Week 1

GET {{baseUrl}}/v{{version}}/orders?date=>2025-11-01&date=<2025-11-08

# Week 2

GET {{baseUrl}}/v{{version}}/orders?date=>2025-11-08&date=<2025-11-15

3. Cache Static Data Cache data that changes infrequently:

4. Use Specific Filters Apply filters to retrieve only the data you need:

# Instead of fetching all items and filtering locally

GET {{baseUrl}}/v{{version}}/items

# Fetch only what you need

GET {{baseUrl}}/v{{version}}/items?warehouse=AALTR&quantity=>0

5. Implement Exponential Backoff For transient errors (429, 503), retry with increasing delays:

6. Batch Related Requests Group related operations to minimize round trips:

1. Fetch orders: ''GET /orders?ts=>{last_sync}''
2. For each order, fetch customer details (if needed)
3. Update local database in batch

7. Monitor API Usage Track your API consumption:

πŸ”„ Common Integration Patterns

Pattern 1: Initial Data Sync (First-Time Setup)

Objective: Load all data from Directo ERP into your system

Considerations: May take several minutes, run during off-peak hours, handle timeouts.

Pattern 2: Incremental Sync (Ongoing Synchronization)

Objective: Keep your system up-to-date with changes in Directo ERP

Pattern 3: Real-Time Order Monitoring

Objective: Monitor new orders for immediate processing

Pattern 4: Inventory Management & Availability Check

Objective: Maintain accurate inventory availability

Pattern 5: Customer Data Synchronization (CRM Integration)

Objective: Keep customer data synchronized between Directo and your CRM

Pattern 6: Invoice Export to Accounting System

Objective: Export invoices to external accounting software

Pattern 7: Price Synchronization to E-Commerce

Objective: Keep product prices updated in your online store

πŸ› οΈ Troubleshooting Guide

Issue: Empty Response / No Results

Possible Causes: Filters too restrictive, incorrect date format, filtering by calculated field. Solutions:

# Remove filters one by one

GET /items

# Verify date format

βœ… CORRECT: ?date=>2025-11-20T00:00:00Z

Issue: Authentication Errors (401/403)

Possible Causes: Missing key, incorrect header name, expired key. Solutions:

# Verify header name (case-sensitive)

βœ… CORRECT: X-Directo-Key: YOUR_KEY

Issue: Rate Limit Errors (429)

Solutions (Python):

import time
def make_request_with_retry(url, max_retries=5):
for attempt in range(max_retries):
response = requests.get(url)
if response.status_code == 200:
return response
elif response.status_code == 429:
wait_time = 2 ** attempt
time.sleep(wait_time)
raise Exception("Max retries exceeded")

πŸ“ž Support & Resources

Technical Support:

πŸ“ Changelog & Version History

Version 1 (Current)

πŸ”’ Security & Compliance

Data Security

Compliance Considerations

Security Best Practices

πŸ’‘ Tips & Tricks

Example (Python):

# Python example with comprehensive error handling
import requests
import time
def fetch_directo_data(endpoint, params=None, max_retries=3):
    url = f"{{{{baseUrl}}}}/v{{{{version}}}}/{endpoint}"
    headers = {
        "X-Directo-Key": "YOUR_API_KEY",
        "Accept": "application/json"
    }
    for attempt in range(max_retries):
        try:
            response = requests.get(url, headers=headers, params=params, timeout=30)
            if response.status_code == 200:
                return response.json()
            elif response.status_code == 429:
                # Rate limit - wait and retry
                wait_time = 2 ** attempt
                time.sleep(wait_time)
            elif response.status_code in [401, 403]:
                # Auth error - don't retry
                raise Exception(f"Authentication error: {response.status_code}")
            else:
                # Other error - log and retry
                print(f"Error {response.status_code}: {response.text}")
                time.sleep(1)
        except requests.exceptions.Timeout:
            print(f"Timeout on attempt {attempt + 1}")
            time.sleep(2)
        except requests.exceptions.RequestException as e:
            print(f"Request failed: {e}")
            time.sleep(2)
    raise Exception(f"Failed after {max_retries} attempts")
# Usage
items = fetch_directo_data("items", params={"warehouse": "AALTR", "quantity": ">0"})

Last Updated: 29-01-2026 API Version: 1

πŸ“š Quick Reference Card

Essential Endpoints

Items:        GET /v1/items
Customers:    GET /v1/customers
Orders:       GET /v1/orders
Invoices:     GET /v1/invoices
Stock:        GET /v1/stocklevels
Deletions:    GET /v1/deleted

Authentication

X-Directo-Key: YOUR_API_KEY

Response Format

Accept: application/json  (or application/xml)

Common Filters

Exact match:      ?field=value
Greater than:     ?field=>value
Less than:        ?field=<value
Not equal:        ?field=!value
Multiple values:  ?field=value1,value2
Timestamp:        ?ts=2025-11-20T07:00:00Z

Filter Examples

?warehouse=AALTR
?quantity=>100
?date=>2025-11-01T00:00:00&date=<2025-12-01T00:00:00
?status=NEW,PENDING
?country=!EE
?ts=2025-11-20T07:00:00Z

Remember

This documentation is maintained by the Directo development team. For questions or feedback, contact info@directo.ee