Azure Logic Apps — Custom API Connectors
Build Your Own OpenAPI-Based Connector for Proprietary APIs
Introduction
Azure Logic Apps provides 400+ built-in connectors for popular services, but sometimes you need to connect to internal or proprietary APIs. Custom API Connectors bridge this gap by exposing your APIs as reusable connectors that can be used across Logic Apps.
This guide covers:
- OpenAPI basics — Creating proper API definitions
- Connector creation — Multiple methods to build connectors
- Authentication — OAuth, API key, and custom auth
- Advanced features — Policies, rate limiting, testing
- Management — Versioning, monitoring, and security
Understanding Custom Connectors
When to Use Custom Connectors
| Scenario | Use Custom Connector |
|---|---|
| Internal REST API | ✅ |
| Proprietary service | ✅ |
| Legacy SOAP service | ✅ |
| Microservices | ✅ |
| Third-party APIs without official connector | ✅ |
| Azure Functions with HTTP triggers | ✅ |
Connector Architecture
┌─────────────────────────────────────────────────────────────────────┐
│ CUSTOM CONNECTOR ARCHITECTURE │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Custom API Connector │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ OpenAPI │ │ Auth Info │ │ Policies │ │ │
│ │ │ Definition │ │ │ │ │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ └────────────────────────────┬────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Logic App 1 │ │ Logic App 2 │ │ Power │ │
│ │ │ │ │ │ Automate │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
Create OpenAPI Definition
Basic OpenAPI Structure
{
"openapi": "3.0.3",
"info": {
"title": "Company Orders API",
"version": "1.0.0",
"description": "REST API for order management system",
"contact": {
"name": "API Support",
"email": "api-support@mycompany.com"
},
"license": {
"name": "MIT",
"url": "https://opensource.org/licenses/MIT"
}
},
"servers": [
{
"url": "https://api.mycompany.com/v1",
"description": "Production server"
},
{
"url": "https://staging-api.mycompany.com/v1",
"description": "Staging server"
}
]
}
Define API Endpoints
{
"paths": {
"/orders": {
"get": {
"operationId": "GetOrders",
"summary": "Retrieve all orders",
"description": "Returns a paginated list of orders. Use page and pageSize parameters to control pagination.",
"tags": ["Orders"],
"parameters": [
{
"name": "page",
"in": "query",
"description": "Page number",
"schema": { "type": "integer", "default": 1 }
},
{
"name": "pageSize",
"in": "query",
"description": "Items per page",
"schema": { "type": "integer", "default": 50 }
},
{
"name": "status",
"in": "query",
"description": "Filter by order status",
"schema": {
"type": "string",
"enum": ["pending", "processing", "completed", "cancelled"]
}
}
],
"responses": {
"200": {
"description": "Successful response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/OrderList"
},
"example": {
"orders": [
{"orderId": "ORD-001", "customerId": "CUST-123", "total": 99.99}
],
"page": 1,
"totalPages": 10,
"totalItems": 500
}
}
}
}
}
},
"post": {
"operationId": "CreateOrder",
"summary": "Create a new order",
"tags": ["Orders"],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/OrderInput" }
}
}
},
"responses": {
"201": {
"description": "Order created successfully",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/Order" }
}
}
},
"400": {
"description": "Invalid request body"
},
"409": {
"description": "Order already exists"
}
}
}
},
"/orders/{orderId}": {
"get": {
"operationId": "GetOrderById",
"summary": "Get order by ID",
"tags": ["Orders"],
"parameters": [
{
"name": "orderId",
"in": "path",
"required": true,
"schema": { "type": "string" }
}
],
"responses": {
"200": {
"description": "Order found",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/Order" }
}
}
},
"404": {
"description": "Order not found"
}
}
},
"put": {
"operationId": "UpdateOrder",
"summary": "Update an order",
"tags": ["Orders"],
"parameters": [
{
"name": "orderId",
"in": "path",
"required": true,
"schema": { "type": "string" }
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/OrderInput" }
}
}
},
"responses": {
"200": {
"description": "Order updated"
},
"404": {
"description": "Order not found"
}
}
},
"delete": {
"operationId": "DeleteOrder",
"summary": "Delete an order",
"tags": ["Orders"],
"parameters": [
{
"name": "orderId",
"in": "path",
"required": true,
"schema": { "type": "string" }
}
],
"responses": {
"204": {
"description": "Order deleted"
},
"404": {
"description": "Order not found"
}
}
}
}
}
}
Define Schemas
{
"components": {
"schemas": {
"Order": {
"type": "object",
"required": ["orderId", "customerId", "items"],
"properties": {
"orderId": {
"type": "string",
"description": "Unique order identifier"
},
"customerId": {
"type": "string",
"description": "Customer identifier"
},
"customerName": {
"type": "string",
"description": "Customer full name"
},
"items": {
"type": "array",
"items": { "$ref": "#/components/schemas/OrderItem" }
},
"total": {
"type": "number",
"format": "decimal",
"description": "Order total amount"
},
"status": {
"type": "string",
"enum": ["pending", "processing", "completed", "cancelled"]
},
"createdAt": {
"type": "string",
"format": "date-time"
},
"updatedAt": {
"type": "string",
"format": "date-time"
}
}
},
"OrderItem": {
"type": "object",
"required": ["productId", "quantity", "unitPrice"],
"properties": {
"productId": { "type": "string" },
"productName": { "type": "string" },
"quantity": { "type": "integer", "minimum": 1 },
"unitPrice": { "type": "number", "format": "decimal" }
}
},
"OrderInput": {
"type": "object",
"required": ["customerId", "items"],
"properties": {
"customerId": { "type": "string" },
"items": {
"type": "array",
"items": { "$ref": "#/components/schemas/OrderItem" }
},
"notes": { "type": "string" }
}
},
"OrderList": {
"type": "object",
"properties": {
"orders": {
"type": "array",
"items": { "$ref": "#/components/schemas/Order" }
},
"page": { "type": "integer" },
"pageSize": { "type": "integer" },
"totalPages": { "type": "integer" },
"totalItems": { "type": "integer" }
}
}
},
"securitySchemes": {
"ApiKeyAuth": {
"type": "apiKey",
"in": "header",
"name": "X-API-Key"
},
"BearerAuth": {
"type": "http",
"scheme": "bearer"
}
}
},
"security": [
{ "BearerAuth": [] },
{ "ApiKeyAuth": [] }
]
}
Create Custom Connector
Azure Portal Method
- Open Azure Portal → Search "Custom Connectors"
- Click "+ New" → "Create from blank" or "Import OpenAPI"
- Enter connector name and description
- Upload OpenAPI file or paste definition
- Configure authentication
- Create and test
CLI Method
# Create custom connector from OpenAPI file
az logic connector create \
--resource-group my-rg \
--name my-company-connector \
--definition ./openapi.json \
--location eastus
# Create with API Management backend
az logic connector create \
--resource-group my-rg \
--name my-apim-connector \
--definition ./openapi.json \
--backend-service-uri "https://myapim.azure-api.net/myapi"
ARM Template
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"type": "Microsoft.Logic/customConnectors",
"apiVersion": "2019-05-01",
"name": "my-company-connector",
"location": "eastus",
"properties": {
"properties": {
"description": "Custom connector for company orders API",
"connectionParameters": {
"apiKey": {
"type": "securestring",
"uiDefinition": {
"displayName": "API Key",
"description": "Enter your API key",
"tooltip": "API key from developer portal"
}
}
},
"definition": {
// OpenAPI definition here
}
}
}
}
]
}
Authentication Configuration
API Key Authentication
{
"properties": {
"type": "ApiKey",
"apiKey": {
"type": "securestring",
"uiDefinition": {
"displayName": "API Key",
"description": "Enter your company API key",
"tooltip": "Found in developer portal"
}
}
}
}
OAuth 2.0 with Azure AD
{
"properties": {
"type": "OAuth2",
"oauth2": {
"identityProvider": "aad",
"clientId": "@appsetting('ClientId')",
"clientSecret": "@appsetting('ClientSecret')",
"authorizationUrl": "https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize",
"tokenUrl": "https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token",
"refreshUrl": "https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token",
"scopes": {
"api.read": "Read access to API",
"api.write": "Write access to API"
}
}
}
}
OAuth 2.0 with Generic Provider
{
"properties": {
"type": "OAuth2",
"oauth2": {
"identityProvider": "oauth2",
"clientId": "@appsetting('OAuthClientId')",
"clientSecret": "@appsetting('OAuthClientSecret')",
"authorizationUrl": "https://auth.mycompany.com/oauth/authorize",
"tokenUrl": "https://auth.mycompany.com/oauth/token",
"scope": "read write"
}
}
}
Basic Authentication
{
"properties": {
"type": "Basic",
"basic": {
"uiDefinition": {
"displayName": "Username and Password",
"description": "Enter your credentials"
}
}
}
}
Use in Logic Apps
Consume in Standard Workflow
{
"definition": {
"actions": {
"Get_Orders": {
"type": "ApiConnection",
"inputs": {
"host": {
"connection": {
"name": "/subscriptions/{sub-id}/resourceGroups/{rg}/providers/Microsoft.Logic/customConnectors/my-company-connector"
}
},
"operation": "GetOrders",
"parameters": {
"page": 1,
"pageSize": 50
}
},
"runAfter": {}
},
"Process_Orders": {
"type": "Foreach",
"foreach": "@body('Get_Orders').orders",
"actions": {
"Create_Record": {
"type": "ApiConnection",
"inputs": {
"host": {
"connection": {
"name": "/subscriptions/{sub-id}/resourceGroups/{rg}/providers/Microsoft.Logic/customConnectors/my-company-connector"
}
},
"operation": "CreateOrder",
"parameters": {
"order": {
"customerId": "@items('Process_Orders').customerId",
"items": "@items('Process_Orders').items"
}
}
}
}
},
"runAfter": {
"Get_Orders": ["Succeeded"]
}
}
},
"trigger": {
"type": "Request",
"kind": "Http",
"inputs": {
"schema": {}
}
}
}
}
Test and Validate
Test in Connector Designer
# Test operation via CLI
az logic connector test \
--resource-group my-rg \
--name my-company-connector \
--operation-id GetOrders \
--parameters '{\"page\": 1, \"pageSize\": 10}'
Debug Common Issues
| Issue | Solution |
|---|---|
| Authentication failed | Verify credentials, check token URL |
| 400 Bad Request | Validate request body matches schema |
| 404 Not Found | Verify base URL in OpenAPI |
| 500 Server Error | Check API server logs |
Best Practices
| Practice | Description |
|---|---|
| Version your API | Include version in OpenAPI info |
| Document thoroughly | Add descriptions to all operations |
| Use proper schemas | Define reusable components |
| Test with real data | Use actual API responses in examples |
| Secure your API | Use OAuth 2.0, not API keys in code |
| Monitor usage | Enable logging for custom connectors |
Advanced: Azure Functions Connector
If your API is implemented as Azure Functions:
# Create connector from Function App
az logic connector create \
--resource-group my-rg \
--name my-function-connector \
--definition ./function-api.json
# The definition should point to the Function URL
# Azure Functions provides OpenAPI out of the box
Azure Integration Hub - Advanced Level