Features | Pricing | Documentation | Contact | Blog

Integrating Outside AWS

Proxylity UDP Gateway's API Gateway destination enables "inside-out" integration, allowing UDP traffic to trigger external HTTP/HTTPS services beyond AWS. This capability bridges UDP protocols to REST APIs across cloud providers, automation platforms, custom webhooks, and enterprise systems—all while maintaining fine-grained IAM security controls.

Architecture Pattern

The integration flow follows this pattern:

  1. UDP client sends packet to Proxylity listener
  2. Proxylity routes to API Gateway destination with IAM authentication
  3. API Gateway transforms request (if using REST API) and calls external HTTP endpoint
  4. External service processes request and returns HTTP response
  5. API Gateway transforms response (optional) and returns to Proxylity
  6. Proxylity sends UDP response back to client

This architecture allows UDP-based devices and protocols to interact with modern HTTP APIs without protocol translation on the client side.

HTTP API vs REST API: Choosing the Right Type

AWS API Gateway offers two API types with different transformation capabilities:

HTTP API - Simple Proxy

Use HTTP API when the external service can accept Proxylity's JSON packet format directly:

REST API - Full Transformation

Use REST API when you need to adapt Proxylity's format to match external API schemas:

In practice, most external integrations require REST API because external services expect specific JSON structures that differ from Proxylity's packet format.

VTL Transformation Example

Here's a simple VTL template that transforms Proxylity's packet format to match a typical webhook API:

#set($packet = $input.path('$.Messages[0]'))
{
  "event_type": "udp_packet_received",
  "timestamp": "$packet.ReceivedAt",
  "source_ip": "$packet.Remote.IpAddress",
  "source_port": $packet.Remote.Port,
  "payload": "$packet.Data",
  "metadata": {
    "listener": "$packet.Local.IpAddress:$packet.Local.Port",
    "formatter": "$packet.Formatter"
  }
}

This template extracts specific fields from the first packet in the batch and restructures them to match the external API's expected schema. REST API applies this transformation before sending the request to the backend.

For comprehensive VTL documentation, see AWS's mapping template reference.

Integration Use Cases

IoT Platforms

Send UDP sensor data directly to cloud-based IoT platforms:

Adafruit IO

Other IoT Platforms

Cross-Cloud Integration (Potential)

The same architectural pattern enables integration with serverless functions and managed services in other cloud providers:

Google Cloud Platform

Microsoft Azure

Automation Platforms (Potential)

Integration patterns that could work with no-code/low-code automation services:

Zapier

Make (formerly Integromat)

Other Platforms

Custom Webhooks

Integrate with custom HTTP services and applications:

Self-Hosted Applications

Microservices

Partner APIs

Enterprise Connectivity

Reach on-premises and private network services securely:

VPC and PrivateLink

Hybrid Cloud

For details on private API Gateway integrations, see AWS documentation on private integrations and private APIs.

IAM-Based Security and Fine-Grained Control

Unlike public webhooks secured only by URL obscurity or shared API keys, API Gateway destinations leverage IAM for robust, auditable access control.

Resource-Level Permissions

IAM policies can restrict Proxylity's access to specific API Gateway endpoints and stages:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowAdafruitIO",
      "Effect": "Allow",
      "Action": "execute-api:Invoke",
      "Resource": "arn:aws:execute-api:us-east-1:123456789012:abc123/prod/POST/adafruit/*"
    },
    {
      "Sid": "AllowCustomDashboard",
      "Effect": "Allow",
      "Action": "execute-api:Invoke",
      "Resource": "arn:aws:execute-api:us-east-1:123456789012:abc123/prod/POST/dashboard"
    }
  ]
}

This policy explicitly authorizes Proxylity to invoke Adafruit IO feed endpoints and a custom dashboard. Any attempt to call other routes will be denied, even if someone discovers the API Gateway URL.

Benefits of IAM Authentication

Least Privilege Pattern

Following AWS best practices, create destination-specific IAM roles with minimal permissions:

Resources:
  IoTPlatformRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              AWS: !FindInMap [ProxylityConfig, !Ref "AWS::Region", ServiceRole]
            Action: sts:AssumeRole
            Condition:
              StringEquals:
                sts:ExternalId: !FindInMap [ProxylityConfig, !Ref "AWS::Region", ExternalId]
      Policies:
        - PolicyName: InvokeIoTEndpoint
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: Allow
                Action: execute-api:Invoke
                Resource: !Sub "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${ExternalApi}/prod/POST/iot/*"

This role can only invoke API Gateway endpoints under the /iot/ path, nothing else.

Debugging External Integrations

Debugging external service integrations requires visibility at multiple layers of the request flow.

Layer 1: UDP Payload Capture

Use composite destinations to log the original UDP packet data before any transformation:

Destinations:
  - Name: external-api
    DestinationArn: !Sub "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${ApiGateway}/prod/POST/webhook"
    Role:
      RoleArn: !GetAtt ApiGatewayRole.Arn
  - Name: udp-debug-logs
    DestinationArn: !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/proxylity/udp-packets"
    Role:
      RoleArn: !GetAtt UdpLoggingRole.Arn

This captures the raw UDP data Proxylity received, useful for verifying packet contents before transformation.

Layer 2: API Gateway Execution Logs

Enable CloudWatch logging in API Gateway to see:

Configure logging in your API Gateway stage settings:

ApiGatewayStage:
  Type: AWS::ApiGateway::Stage
  Properties:
    StageName: prod
    RestApiId: !Ref ApiGateway
    DeploymentId: !Ref ApiGatewayDeployment
    AccessLogSetting:
      DestinationArn: !GetAtt ApiGatewayLogGroup.Arn
      Format: '$context.requestId $context.error.message $context.error.messageString'
    MethodSettings:
      - ResourcePath: /*
        HttpMethod: '*'
        LoggingLevel: INFO
        DataTraceEnabled: true

Set DataTraceEnabled: true to log full request/response bodies (be mindful of sensitive data).

Layer 3: External Service Logs

Check the external service's own logging:

Common Debugging Scenarios

Schema Mismatch

Symptom: External API returns 400 Bad Request or validation errors

Diagnosis: Compare API Gateway execution logs (transformed request) against external API's schema requirements

Solution: Adjust VTL mapping template to match expected schema

Authentication Failures

Symptom: External API returns 401 Unauthorized or 403 Forbidden

Diagnosis: Check if external service requires API keys, OAuth tokens, or specific headers

Solution: Add authentication headers in VTL template or API Gateway integration settings

Timeout Issues

Symptom: API Gateway returns 504 Gateway Timeout

Diagnosis: External service taking longer than API Gateway's 29-second timeout

Solution: Optimize external service or consider async pattern with callback webhook

No Response Received

Symptom: UDP client receives no reply packet

Diagnosis: Check if external API returned a response, and if API Gateway mapped it to Proxylity's response format

Solution: Ensure VTL response template transforms to {"Replies": [...]} format

CloudFormation Example

Complete example showing API Gateway destination with external HTTP integration, IAM role, and composite logging:

AWSTemplateFormatVersion: '2010-09-09'
Description: 'Proxylity UDP to External HTTP via API Gateway'

Resources:
  # API Gateway REST API
  ExternalIntegrationApi:
    Type: AWS::ApiGateway::RestApi
    Properties:
      Name: udp-to-external-api
      Description: Bridge UDP packets to external HTTP services

  # Resource and Method
  WebhookResource:
    Type: AWS::ApiGateway::Resource
    Properties:
      RestApiId: !Ref ExternalIntegrationApi
      ParentId: !GetAtt ExternalIntegrationApi.RootResourceId
      PathPart: webhook

  WebhookMethod:
    Type: AWS::ApiGateway::Method
    Properties:
      RestApiId: !Ref ExternalIntegrationApi
      ResourceId: !Ref WebhookResource
      HttpMethod: POST
      AuthorizationType: AWS_IAM
      Integration:
        Type: HTTP
        IntegrationHttpMethod: POST
        Uri: https://external-service.example.com/api/webhook
        RequestTemplates:
          application/json: |
            #set($packet = $input.path('$.Messages[0]'))
            {
              "event": "udp_packet",
              "data": "$packet.Data",
              "source": "$packet.Remote.IpAddress",
              "timestamp": "$packet.ReceivedAt"
            }
        IntegrationResponses:
          - StatusCode: 200
            ResponseTemplates:
              application/json: |
                {
                  "Replies": []
                }
      MethodResponses:
        - StatusCode: 200

  # Deployment
  ApiDeployment:
    Type: AWS::ApiGateway::Deployment
    DependsOn: WebhookMethod
    Properties:
      RestApiId: !Ref ExternalIntegrationApi
      StageName: prod

  # Proxylity IAM Role
  ProxylityApiGatewayRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              AWS: !FindInMap [ProxylityConfig, !Ref "AWS::Region", ServiceRole]
            Action: sts:AssumeRole
            Condition:
              StringEquals:
                sts:ExternalId: !FindInMap [ProxylityConfig, !Ref "AWS::Region", ExternalId]
      Policies:
        - PolicyName: InvokeWebhookEndpoint
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: Allow
                Action: execute-api:Invoke
                Resource: !Sub "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${ExternalIntegrationApi}/prod/POST/webhook"

  # CloudWatch Logs for UDP payload debugging
  UdpPayloadLogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: /proxylity/udp-payloads
      RetentionInDays: 7

  UdpLoggingRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              AWS: !FindInMap [ProxylityConfig, !Ref "AWS::Region", ServiceRole]
            Action: sts:AssumeRole
            Condition:
              StringEquals:
                sts:ExternalId: !FindInMap [ProxylityConfig, !Ref "AWS::Region", ExternalId]
      Policies:
        - PolicyName: WriteLogsPolicy
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: Allow
                Action:
                  - logs:CreateLogStream
                  - logs:PutLogEvents
                Resource: !GetAtt UdpPayloadLogGroup.Arn

  # Proxylity Listener with Composite Destinations
  UdpListener:
    Type: Custom::ProxylityUdpGatewayListener
    Properties:
      ServiceToken: !FindInMap [ProxylityConfig, !Ref "AWS::Region", ServiceToken]
      ApiKey: !FindInMap [ProxylityConfig, !Ref "AWS::Region", ApiKey]
      Protocols:
        - udp
      Destinations:
        - Name: external-webhook
          DestinationArn: !Sub "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${ExternalIntegrationApi}/prod/POST/webhook"
          Role:
            RoleArn: !GetAtt ProxylityApiGatewayRole.Arn
        - Name: debug-logging
          DestinationArn: !GetAtt UdpPayloadLogGroup.Arn
          Role:
            RoleArn: !GetAtt UdpLoggingRole.Arn

Outputs:
  UdpEndpoint:
    Description: UDP endpoint for sending packets
    Value: !Sub "${UdpListener.Domain}.proxylity.com:${UdpListener.Port}"
  ApiEndpoint:
    Description: API Gateway endpoint
    Value: !Sub "https://${ExternalIntegrationApi}.execute-api.${AWS::Region}.amazonaws.com/prod/webhook"

Examples and Further Reading

For complete working examples of UDP-to-HTTP integrations, see the udp-to-http folder in our examples repository, which includes:

Related documentation: