External API Connections
Goal: Connect to third-party REST APIs and bring external data into the Control Plane.
Beta Feature:
UI-driven API connections are coming soon. Currently, external API integration requires custom code development. This guide covers the custom code approach for advanced users.
Current Status
| Feature | Status |
|---|---|
| UI-driven API configuration | Coming Soon |
| Custom code integrations | Available |
| Weather API integrations | Available via custom code |
| Market data integrations | Available via custom code |
Use Cases
| Source | Example Data |
|---|---|
| Weather APIs | Temperature, humidity, forecasts |
| Market data | Commodity prices, exchange rates |
| ERP systems | Production schedules, inventory |
| Custom services | Internal APIs, microservices |
Custom Code Approach
For teams that need external API connectivity now, you can build custom integrations.
Architecture
External API → Custom Integration Code → OpenIndustrial API → Control Plane
Example: Weather API Integration
// Fetch weather data from external API
async function fetchWeatherData(location: string) {
const response = await fetch(
`https://api.weather.example/v1/current?location=${location}`,
{
headers: {
'X-API-Key': process.env.WEATHER_API_KEY,
},
}
);
const data = await response.json();
// Transform to OpenIndustrial format
return {
deviceId: `weather-${location}`,
timestamp: new Date().toISOString(),
temperature: data.current.temp_f,
humidity: data.current.humidity,
conditions: data.current.condition,
};
}
// Push to OpenIndustrial
async function pushToOpenIndustrial(telemetry: object) {
const response = await fetch(
'https://www.openindustrial.co/api/workspaces/{workspace}/data-import',
{
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.OI_API_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
source: 'weather-api',
data: telemetry,
}),
}
);
return response.ok;
}
// Run on schedule
const weatherData = await fetchWeatherData('seattle');
await pushToOpenIndustrial(weatherData);
Example: Market Data Integration
// Fetch commodity prices
async function fetchCommodityPrices() {
const response = await fetch(
'https://api.marketdata.example/v1/commodities',
{
headers: {
'Authorization': `Bearer ${process.env.MARKET_API_KEY}`,
},
}
);
const data = await response.json();
// Transform each commodity to telemetry format
return data.commodities.map((commodity: any) => ({
deviceId: `commodity-${commodity.symbol}`,
timestamp: new Date().toISOString(),
price: commodity.price,
change: commodity.change_24h,
volume: commodity.volume,
}));
}
// Push all commodities
const prices = await fetchCommodityPrices();
for (const price of prices) {
await pushToOpenIndustrial(price);
}
Authentication Methods
Handle various API authentication methods in your custom code:
| Method | Implementation |
|---|---|
| API Key | headers: { 'X-API-Key': key } |
| Bearer Token | headers: { 'Authorization': 'Bearer ' + token } |
| Basic Auth | headers: { 'Authorization': 'Basic ' + btoa(user + ':' + pass) } |
| OAuth 2.0 | Use a library to handle token refresh |
Polling Strategies
| Frequency | Use Case | Implementation |
|---|---|---|
| 1 minute | Fast-changing data | Cron job or setInterval |
| 15 minutes | Standard refresh | Scheduled function |
| 1 hour | Slow-changing data | Batch job |
| Event-driven | Webhooks | HTTP endpoint |
Deployment Options
Run your custom integration as:
| Option | Best For |
|---|---|
| Azure Functions (Timer) | Scheduled polling |
| Deno Deploy | Lightweight, edge-deployed |
| Container | Complex transformations |
| Webhook endpoint | Event-driven APIs |
Error Handling
Implement robust error handling:
async function fetchWithRetry(url: string, options: RequestInit, retries = 3) {
for (let attempt = 1; attempt <= retries; attempt++) {
try {
const response = await fetch(url, options);
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
return await response.json();
} catch (error) {
if (attempt === retries) throw error;
// Exponential backoff
await new Promise(resolve =>
setTimeout(resolve, Math.pow(2, attempt) * 1000)
);
}
}
}
Security Considerations
Store API keys in environment variables or secret managers. Never commit credentials to source control.
- Use environment variables for API keys
- Implement rate limiting to respect API quotas
- Log API calls for debugging (without credentials)
- Handle API downtime gracefully
Coming Soon: UI-Driven Configuration
The upcoming UI-driven API connections will include:
- Visual endpoint configuration
- Authentication setup wizard
- Response mapping editor
- Polling schedule configuration
- Azi-assisted response parsing
Thinking Tip:
Want early access to the API connection UI? Contact the OpenIndustrial team.
Next Steps
| If you want to... | Go to... |
|---|---|
| Connect databases | Database Guide → |
| Build queries on imported data | Warm Queries Guide → |
| Connect IoT devices | IoT Hub Guide → |