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

ScenarioUse 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

  1. Open Azure Portal → Search "Custom Connectors"
  2. Click "+ New" → "Create from blank" or "Import OpenAPI"
  3. Enter connector name and description
  4. Upload OpenAPI file or paste definition
  5. Configure authentication
  6. 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

IssueSolution
Authentication failedVerify credentials, check token URL
400 Bad RequestValidate request body matches schema
404 Not FoundVerify base URL in OpenAPI
500 Server ErrorCheck API server logs

Best Practices

PracticeDescription
Version your APIInclude version in OpenAPI info
Document thoroughlyAdd descriptions to all operations
Use proper schemasDefine reusable components
Test with real dataUse actual API responses in examples
Secure your APIUse OAuth 2.0, not API keys in code
Monitor usageEnable 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