Skip to main content

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:

  1. API Key - A valid API key with production creation permissions
  2. Location Setup - Each production line or station must have an external_id configured
  3. 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

FieldTypeDescriptionRequiredDefault
external_idStringLocation identifier (configured in your system)Yes-
quantityIntegerNumber of parts producedNo1
qualityStringQuality status: good, scrap, or reworkNogood
productStringProduct code that identifies what is being producedNo*-
cycle_timeFloatCycle time in secondsNo-
recorded_atInteger/StringWhen the part was produced (Unix timestamp or ISO 8601)NoCurrent time
reasonStringScrap 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

ValueDescriptionWhen to Use
goodGood quality partPart meets quality standards (default)
scrapScrapped partPart failed quality inspection and cannot be used
reworkPart requiring reworkPart 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:

  1. Authentication - Your API key is validated and permissions are checked
  2. Message Parsing - The JSON payload is parsed and validated
  3. Location Lookup - The location is identified by the external_id
  4. Product Lookup - The product code is matched to your product catalog
  5. Part Recorded - A new part record is created with the quantity and quality information
  6. Production Period Updated - The system automatically manages production periods, ending downtime if necessary
  7. 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-KEY header
  • 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_id is 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_id is 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:

  1. Check the HTTP status code and error message in the response
  2. Verify your API key has the correct permissions
  3. Confirm your location's external_id is properly configured
  4. Test with a simple request using cURL or Postman
  5. 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