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

FeatureStatus
UI-driven API configurationComing Soon
Custom code integrationsAvailable
Weather API integrationsAvailable via custom code
Market data integrationsAvailable via custom code

Use Cases

SourceExample Data
Weather APIsTemperature, humidity, forecasts
Market dataCommodity prices, exchange rates
ERP systemsProduction schedules, inventory
Custom servicesInternal 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:

MethodImplementation
API Keyheaders: { 'X-API-Key': key }
Bearer Tokenheaders: { 'Authorization': 'Bearer ' + token }
Basic Authheaders: { 'Authorization': 'Basic ' + btoa(user + ':' + pass) }
OAuth 2.0Use a library to handle token refresh

Polling Strategies

FrequencyUse CaseImplementation
1 minuteFast-changing dataCron job or setInterval
15 minutesStandard refreshScheduled function
1 hourSlow-changing dataBatch job
Event-drivenWebhooksHTTP endpoint

Deployment Options

Run your custom integration as:

OptionBest For
Azure Functions (Timer)Scheduled polling
Deno DeployLightweight, edge-deployed
ContainerComplex transformations
Webhook endpointEvent-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 databasesDatabase Guide →
Build queries on imported dataWarm Queries Guide →
Connect IoT devicesIoT Hub Guide →
On this page