Sending Data via HTTPS
This guide explains how to send production data to OEE Tools using HTTPS REST API, a secure and widely-supported method for integrating production equipment and systems.
Overview
The HTTPS API allows you to send production data from your machines, PLCs, MES systems, or other applications to OEE Tools. The API uses standard HTTP POST requests with JSON payloads, making it easy to integrate with virtually any system.
Getting Started
Prerequisites
Before sending data via HTTPS, you need:
- API Key - A valid API key with production creation permissions
- Location Setup - Each production line or station must have an
external_idconfigured - HTTP Client - Any tool or library capable of making HTTP requests (available in all programming languages)
API Endpoint
POST https://your-domain.com/api/external/production/process_part
Authentication
Authentication is done using an API key passed in the request headers:
API-KEY: your_api_key_here
Note: Contact your administrator to get your API key and location external IDs.
Message Format
Messages must be sent as JSON payloads in the request body. Here's the most basic example:
{
"part": {
"external_id": "line_1",
"quantity": 1
}
}
This records 1 part at the current time using default values (good quality, fallback product).
Here's a comprehensive example for a good part:
{
"part": {
"external_id": "line_1",
"quantity": 5,
"quality": "good",
"product": "PROD001",
"cycle_time": 45.5,
"recorded_at": 1698765432
}
}
Here's a comprehensive example for a scrapped part:
{
"part": {
"external_id": "line_1",
"quantity": 1,
"quality": "scrap",
"product": "PROD001",
"cycle_time": 45.5,
"recorded_at": 1698765432,
"reason": "REASON01"
}
}
Message Fields
| Field | Type | Description | Required | Default |
|---|---|---|---|---|
external_id | String | Location identifier (configured in your system) | Yes | - |
quantity | Integer | Number of parts produced | No | 1 |
quality | String | Quality status: good, scrap, or rework | No | good |
product | String | Product code that identifies what is being produced | No* | - |
cycle_time | Float | Cycle time in seconds | No | - |
recorded_at | Integer/String | When the part was produced (Unix timestamp or ISO 8601) | No | Current time |
reason | String | Scrap reason code (only used when quality is scrap) | No | - |
* If product is not provided, the system will attempt to use cycle_time to identify the product. If the product cannot be found, a fallback product will be used.
Quality Values
| Value | Description | When to Use |
|---|---|---|
good | Good quality part | Part meets quality standards (default) |
scrap | Scrapped part | Part failed quality inspection and cannot be used |
rework | Part requiring rework | Part needs additional work to meet standards |
Timestamp (recorded_at) Formats
You can specify when a part was produced using either:
Unix timestamp (seconds since epoch):
{
"part": {
"external_id": "line_1",
"recorded_at": 1702900800
}
}
ISO 8601 datetime string:
{
"part": {
"external_id": "line_1",
"recorded_at": "2024-01-01T10:00:00Z"
}
}
If you don't provide a timestamp, the system uses the current server time when the request is received.
Response Format
Success Response
Status Code: 200 OK
{
"message": "Part processed successfully"
}
Error Responses
Status Code: 422 Unprocessable Entity
{
"error": "Location not found for external_id: line_1"
}
Status Code: 401 Unauthorized
{
"error": "Invalid API key"
}
Status Code: 500 Internal Server Error
{
"error": "Internal server error"
}
Implementation Examples
cURL Example
curl -X POST https://your-domain.com/api/external/production/process_part \
-H "Content-Type: application/json" \
-H "API-KEY: your_api_key_here" \
-d '{
"part": {
"external_id": "line_1",
"quantity": 5,
"quality": "good",
"product": "PROD001",
"recorded_at": 1698765432
}
}'
Python Example
import requests
import json
import time
# Configuration
api_url = "https://your-domain.com/api/external/production/process_part"
api_key = "your_api_key_here"
# Prepare headers
headers = {
"Content-Type": "application/json",
"API-KEY": api_key
}
# Prepare data
data = {
"part": {
"external_id": "line_1",
"quantity": 5,
"quality": "good",
"product": "PROD001",
"recorded_at": int(time.time())
}
}
# Send request
response = requests.post(api_url, headers=headers, json=data)
# Check response
if response.status_code == 200:
print("Success:", response.json())
else:
print(f"Error {response.status_code}:", response.json())
Node.js Example
const axios = require('axios');
// Configuration
const apiUrl = 'https://your-domain.com/api/external/production/process_part';
const apiKey = 'your_api_key_here';
// Prepare data
const data = {
part: {
external_id: 'line_1',
quantity: 5,
quality: 'good',
product: 'PROD001',
recorded_at: Math.floor(Date.now() / 1000)
}
};
// Send request
axios.post(apiUrl, data, {
headers: {
'Content-Type': 'application/json',
'API-KEY': apiKey
}
})
.then(response => {
console.log('Success:', response.data);
})
.catch(error => {
console.error('Error:', error.response?.data || error.message);
});
C# Example
using System;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
var apiUrl = "https://your-domain.com/api/external/production/process_part";
var apiKey = "your_api_key_here";
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("API-KEY", apiKey);
var data = new
{
part = new
{
external_id = "line_1",
quantity = 5,
quality = "good",
product = "PROD001",
recorded_at = DateTimeOffset.UtcNow.ToUnixTimeSeconds()
}
};
var json = JsonSerializer.Serialize(data);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await client.PostAsync(apiUrl, content);
var result = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
Console.WriteLine($"Success: {result}");
}
else
{
Console.WriteLine($"Error {response.StatusCode}: {result}");
}
}
}
PHP Example
<?php
// Configuration
$apiUrl = 'https://your-domain.com/api/external/production/process_part';
$apiKey = 'your_api_key_here';
// Prepare data
$data = [
'part' => [
'external_id' => 'line_1',
'quantity' => 5,
'quality' => 'good',
'product' => 'PROD001',
'recorded_at' => time()
]
];
// Prepare request
$options = [
'http' => [
'header' => [
'Content-Type: application/json',
'API-KEY: ' . $apiKey
],
'method' => 'POST',
'content' => json_encode($data)
]
];
$context = stream_context_create($options);
$response = file_get_contents($apiUrl, false, $context);
if ($response === false) {
echo "Error: Request failed\n";
} else {
echo "Success: " . $response . "\n";
}
?>
Arduino/ESP32 Example
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
const char* apiUrl = "https://your-domain.com/api/external/production/process_part";
const char* apiKey = "your_api_key_here";
void sendProduction() {
if (WiFi.status() == WL_CONNECTED) {
HTTPClient http;
http.begin(apiUrl);
http.addHeader("Content-Type", "application/json");
http.addHeader("API-KEY", apiKey);
// Prepare JSON
StaticJsonDocument<256> doc;
JsonObject part = doc.createNestedObject("part");
part["external_id"] = "line_1";
part["quantity"] = 1;
part["quality"] = "good";
part["product"] = "PROD001";
part["recorded_at"] = millis() / 1000;
String jsonString;
serializeJson(doc, jsonString);
// Send request
int httpResponseCode = http.POST(jsonString);
if (httpResponseCode == 200) {
String response = http.getString();
Serial.println("Success: " + response);
} else {
Serial.print("Error: ");
Serial.println(httpResponseCode);
}
http.end();
}
}
void setup() {
Serial.begin(115200);
// Connect to WiFi...
}
How It Works
When you send a request to the API:
- Authentication - Your API key is validated and permissions are checked
- Message Parsing - The JSON payload is parsed and validated
- Location Lookup - The location is identified by the
external_id - Product Lookup - The product code is matched to your product catalog
- Part Recorded - A new part record is created with the quantity and quality information
- Production Period Updated - The system automatically manages production periods, ending downtime if necessary
- Response Sent - A success or error response is returned
All timestamps are automatically converted to your configured timezone, and the API responds immediately with the result.
Best Practices
1. Use Accurate Timestamps
Always send the actual production time, not the time you're sending the request. This ensures accurate OEE calculations.
2. Send Requests Promptly
Send requests as soon as parts are produced for real-time monitoring. Avoid excessive batching.
3. Use Correct External IDs
Ensure the external_id matches exactly what's configured for your location. External IDs are case-sensitive.
4. Handle HTTP Errors
Always check the response status code and handle errors appropriately:
# Example: Python with error handling
def send_production_data(data):
try:
response = requests.post(api_url, headers=headers, json=data, timeout=10)
response.raise_for_status() # Raises exception for 4xx/5xx status codes
return response.json()
except requests.exceptions.Timeout:
print("Request timed out")
except requests.exceptions.HTTPError as e:
print(f"HTTP error: {e.response.status_code} - {e.response.text}")
except requests.exceptions.RequestException as e:
print(f"Request failed: {e}")
return None
5. Implement Retry Logic
For production systems, implement retry logic for transient failures:
import time
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.retry import Retry
def create_session_with_retries():
session = requests.Session()
retry = Retry(
total=3,
backoff_factor=1,
status_forcelist=[500, 502, 503, 504]
)
adapter = HTTPAdapter(max_retries=retry)
session.mount('http://', adapter)
session.mount('https://', adapter)
return session
# Use it
session = create_session_with_retries()
response = session.post(api_url, headers=headers, json=data)
6. Validate Data Before Sending
Ensure your data is valid before making the API call:
def validate_part_data(part):
# Check required fields
if 'external_id' not in part:
return False, "external_id is required"
# Validate quality value
if 'quality' in part:
valid_qualities = ['good', 'scrap', 'rework']
if part['quality'] not in valid_qualities:
return False, f"Invalid quality: {part['quality']}"
# Validate quantity
if 'quantity' in part and part['quantity'] < 1:
return False, "Quantity must be at least 1"
return True, None
# Use it
is_valid, error = validate_part_data(part_data)
if not is_valid:
print(f"Validation error: {error}")
else:
send_production_data(part_data)
7. Secure Your API Key
- Never hardcode API keys in your source code
- Use environment variables or secure configuration files
- Rotate API keys periodically
- Use different API keys for different systems/locations if possible
import os
# Good: Load from environment variable
api_key = os.environ.get('OEE_API_KEY')
# Bad: Hardcoded in source
# api_key = "abc123xyz456"
8. Use HTTPS Only
Always use HTTPS (not HTTP) to ensure your data and API key are encrypted in transit.
Troubleshooting
Common Error Messages
"Invalid API key"
Cause: The API key in the header is missing, incorrect, or expired.
Solution:
- Verify you're sending the
API-KEYheader - Check that the API key is correct
- Contact your administrator to verify the key is still active
"Location not found for external_id: xxx"
Cause: No location exists with the specified external_id.
Solution:
- Verify the
external_idis correct (check for typos) - Confirm the location is configured in the system
- Contact your administrator to set up the location
"Invalid message format"
Cause: The JSON payload is missing required fields or is malformed.
Solution:
- Ensure
external_idis included in the request - Verify the JSON is properly formatted
- Check that all field names are correct
Testing Your Integration
Use a tool like Postman, Insomnia, or cURL to test your API calls:
# Test with cURL
curl -X POST https://your-domain.com/api/external/production/process_part \
-H "Content-Type: application/json" \
-H "API-KEY: your_api_key_here" \
-d '{"part":{"external_id":"line_1","quantity":1}}' \
-v
The -v flag shows detailed request/response information for debugging.
Debug Mode
You can enable debug mode by adding a query parameter:
POST https://your-domain.com/api/external/production/process_part?debug=true
This provides additional logging on the server side (contact your administrator for access to logs).
Getting Help
If you continue to experience issues:
- Check the HTTP status code and error message in the response
- Verify your API key has the correct permissions
- Confirm your location's
external_idis properly configured - Test with a simple request using cURL or Postman
- Contact your system administrator with the error details
HTTPS vs MQTT
Both methods are supported for sending production data. Here's when to use each:
Use HTTPS when:
- You need request/response confirmation for each message
- Your system makes occasional API calls (not continuous streaming)
- You're integrating with web applications or REST-based systems
- You need simpler authentication (API key in header)
- You want to use standard HTTP libraries available in any language
Use MQTT when:
- You need real-time, continuous data streaming
- You're sending high-frequency messages (multiple per second)
- You want lower network overhead
- Your devices have limited bandwidth
- You're working with IoT devices or PLCs with MQTT support
Security Considerations
- Use HTTPS Only - Never send data over unencrypted HTTP
- Protect API Keys - Store API keys securely, never in source code
- Validate Input - Always validate data before sending
- Use Timeouts - Set reasonable timeouts to prevent hanging requests
- Rate Limiting - Be aware of any rate limits on the API
- Network Security - Ensure your network allows outbound HTTPS connections
- Error Logging - Log errors but never log sensitive data like API keys