NextGen APIs

Setup Queue Async Processing

Queue Async Processing

This guide explains how to enable and configure asynchronous processing for your Integration API endpoints.

Overview

diagram (39).svg


The Queue Async Processing feature allows you to process API requests asynchronously using AWS SNS/SQS queues. When enabled, requests are published to an SNS topic, processed asynchronously via SQS, and results are sent back via a callback endpoint.

How to Enable Async Processing

The Integration API library provides pre-configured async-enabled endpoints. To use them, you need to manually configure the required properties - no code changes or annotations are needed.

What you need to do:

  • Manually add all required stream configuration properties (SNS/SQS setup)

  • Configure callback settings (optional)

  • Enable the specific endpoints you want to use asynchronously

  • Configure the Notify Async Stream (required for callback functionality)

Note: Property auto-configuration (integrationlayer.async.processing.property.autoconfigure.enabled) is always set to false and should not be changed. All properties must be configured manually.


Notify Async Stream Configuration

The Notify Async Stream is a dedicated queue that handles callback notifications after async processing completes. This stream is required when you want to receive callbacks about the processing results.

How It Works

When an async endpoint finishes processing (either successfully or with an error), it publishes a notification message to the Notify Async Stream. This stream then:

  1. Receives the notification message via SNS

  2. Processes it via SQS

  3. Calls the configured callback endpoint with the processing result

Configuration Properties

Add the following properties to your setup.properties to enable the Notify Async Stream:

# ============================================
# Notify Async Stream Configuration
# ============================================

# Publisher configuration (SNS)
# Add snsIntegrationApiNotifyAsync to the foundation.stream.pub list
foundation.stream.pub.snsIntegrationApiNotifyAsync.spout=*.spout.AsyncProcessingNotifyMessage
foundation.stream.pub.snsIntegrationApiNotifyAsync.target=integrationApiNotifyAsyncTarget

# SNS Target
foundation.stream.target.integrationApiNotifyAsyncTarget.type=SNS
foundation.stream.target.integrationApiNotifyAsyncTarget.endpoint=${env:SNS_ENDPOINT}
foundation.stream.target.integrationApiNotifyAsyncTarget.topic=IntegrationApi-NotifyAsync

# Subscriber configuration (SQS)
# Add integrationApiNotifyAsync to the foundation.stream.sub list
foundation.stream.sub.integrationApiNotifyAsync.spin=*.spin.AsyncProcessingEventNotifyMessage
foundation.stream.sub.integrationApiNotifyAsync.source=integrationApiNotifyAsyncSub
foundation.stream.sub.integrationApiNotifyAsync.spin.agent=integrationApiNotifyAsyncAgent
foundation.stream.sub.integrationApiNotifyAsync.spin.tenant=admin

# SQS Source
foundation.stream.source.integrationApiNotifyAsyncSub.type=SQS
foundation.stream.source.integrationApiNotifyAsyncSub.endpoint=${env:SQS_ENDPOINT}
foundation.stream.source.integrationApiNotifyAsyncSub.topic=IntegrationApi-NotifyAsync
foundation.stream.source.integrationApiNotifyAsyncSub.logging=true
foundation.stream.source.integrationApiNotifyAsyncSub.emergencyTopic=IntegrationApi-NotifyAsync-DLQ

Important Notes

  • The Notify Async Stream must be included in both foundation.stream.pub and foundation.stream.sub lists

  • Example when enabling async processing with notify stream:

    foundation.stream.pub=snsIntegrationApiPostAssetsR1Assets,snsIntegrationApiNotifyAsync
    foundation.stream.sub=integrationApiPostAssetsR1Assets,integrationApiNotifyAsync
    
  • The Notify Async Stream is shared across all async endpoints - you only need to configure it once

  • If no callback endpoint is configured, the notify messages will still be processed but no external call will be made

AWS Resources for Notify Async Stream

Create the following AWS resources:

Resource Type

Name

SNS Topic

IntegrationApi-NotifyAsync

SQS Queue

IntegrationApi-NotifyAsync

DLQ

IntegrationApi-NotifyAsync-DLQ


Pre-configured Async Endpoints

The following endpoints are pre-configured for async processing. Copy and paste the configuration for the endpoints you want to enable:

1. POST /integration/assets/r1/accounts

Property Key: integrationApiPostAssetsR1Accounts

# Enable endpoint
integrationlayer.async.processing.integrationApiPostAssetsR1Accounts.enabled=true

# Publisher configuration (SNS)
foundation.stream.pub=snsIntegrationApiPostAssetsR1Accounts
foundation.stream.pub.snsIntegrationApiPostAssetsR1Accounts.spout=*.spout.PostIntegrationAssetsR1AccountsAsyncProcessingRequestMessage
foundation.stream.pub.snsIntegrationApiPostAssetsR1Accounts.target=integrationApiPostAssetsR1AccountsTarget

# SNS Target
foundation.stream.target.integrationApiPostAssetsR1AccountsTarget.type=SNS
foundation.stream.target.integrationApiPostAssetsR1AccountsTarget.endpoint=${env:SNS_ENDPOINT}
foundation.stream.target.integrationApiPostAssetsR1AccountsTarget.topic=IntegrationApi-IntegrationApiPostAssetsR1Accounts

# Subscriber configuration (SQS)
foundation.stream.sub=integrationApiPostAssetsR1Accounts
foundation.stream.sub.integrationApiPostAssetsR1Accounts.spin=*.spin.PostIntegrationAssetsR1AccountsAsyncProcessingEventRequestMessage
foundation.stream.sub.integrationApiPostAssetsR1Accounts.source=integrationApiPostAssetsR1AccountsSub
foundation.stream.sub.integrationApiPostAssetsR1Accounts.spin.agent=integrationApiPostAssetsR1AccountsAgent
foundation.stream.sub.integrationApiPostAssetsR1Accounts.spin.tenant=admin

# SQS Source
foundation.stream.source.integrationApiPostAssetsR1AccountsSub.type=SQS
foundation.stream.source.integrationApiPostAssetsR1AccountsSub.endpoint=${env:SQS_ENDPOINT}
foundation.stream.source.integrationApiPostAssetsR1AccountsSub.topic=IntegrationApi-IntegrationApiPostAssetsR1Accounts
foundation.stream.source.integrationApiPostAssetsR1AccountsSub.logging=true
foundation.stream.source.integrationApiPostAssetsR1AccountsSub.emergencyTopic=IntegrationApi-IntegrationApiPostAssetsR1Accounts-DLQ

2. POST /integration/assets/r1/assets

Property Key: integrationApiPostAssetsR1Assets

# Enable endpoint
integrationlayer.async.processing.integrationApiPostAssetsR1Assets.enabled=true

# Publisher configuration (SNS)
foundation.stream.pub=snsIntegrationApiPostAssetsR1Assets
foundation.stream.pub.snsIntegrationApiPostAssetsR1Assets.spout=*.spout.PostIntegrationAssetsR1AssetsAsyncProcessingRequestMessage
foundation.stream.pub.snsIntegrationApiPostAssetsR1Assets.target=integrationApiPostAssetsR1AssetsTarget

# SNS Target
foundation.stream.target.integrationApiPostAssetsR1AssetsTarget.type=SNS
foundation.stream.target.integrationApiPostAssetsR1AssetsTarget.endpoint=${env:SNS_ENDPOINT}
foundation.stream.target.integrationApiPostAssetsR1AssetsTarget.topic=IntegrationApi-IntegrationApiPostAssetsR1Assets

# Subscriber configuration (SQS)
foundation.stream.sub=integrationApiPostAssetsR1Assets
foundation.stream.sub.integrationApiPostAssetsR1Assets.spin=*.spin.PostIntegrationAssetsR1AssetsAsyncProcessingEventRequestMessage
foundation.stream.sub.integrationApiPostAssetsR1Assets.source=integrationApiPostAssetsR1AssetsSub
foundation.stream.sub.integrationApiPostAssetsR1Assets.spin.agent=integrationApiPostAssetsR1AssetsAgent
foundation.stream.sub.integrationApiPostAssetsR1Assets.spin.tenant=admin

# SQS Source
foundation.stream.source.integrationApiPostAssetsR1AssetsSub.type=SQS
foundation.stream.source.integrationApiPostAssetsR1AssetsSub.endpoint=${env:SQS_ENDPOINT}
foundation.stream.source.integrationApiPostAssetsR1AssetsSub.topic=IntegrationApi-IntegrationApiPostAssetsR1Assets
foundation.stream.source.integrationApiPostAssetsR1AssetsSub.logging=true
foundation.stream.source.integrationApiPostAssetsR1AssetsSub.emergencyTopic=IntegrationApi-IntegrationApiPostAssetsR1Assets-DLQ

3. POST /integration/work-orders/r1/work-orders

Property Key: integrationApiPostWorkOrdersR1WorkOrders

# Enable endpoint
integrationlayer.async.processing.integrationApiPostWorkOrdersR1WorkOrders.enabled=true

# Publisher configuration (SNS)
foundation.stream.pub=snsIntegrationApiPostWorkOrdersR1WorkOrders
foundation.stream.pub.snsIntegrationApiPostWorkOrdersR1WorkOrders.spout=*.spout.PostIntegrationWorkOrdersR1WorkOrdersAsyncProcessingRequestMessage
foundation.stream.pub.snsIntegrationApiPostWorkOrdersR1WorkOrders.target=integrationApiPostWorkOrdersR1WorkOrdersTarget

# SNS Target
foundation.stream.target.integrationApiPostWorkOrdersR1WorkOrdersTarget.type=SNS
foundation.stream.target.integrationApiPostWorkOrdersR1WorkOrdersTarget.endpoint=${env:SNS_ENDPOINT}
foundation.stream.target.integrationApiPostWorkOrdersR1WorkOrdersTarget.topic=IntegrationApi-IntegrationApiPostWorkOrdersR1WorkOrders

# Subscriber configuration (SQS)
foundation.stream.sub=integrationApiPostWorkOrdersR1WorkOrders
foundation.stream.sub.integrationApiPostWorkOrdersR1WorkOrders.spin=*.spin.PostIntegrationWorkOrdersR1WorkOrdersAsyncProcessingEventRequestMessage
foundation.stream.sub.integrationApiPostWorkOrdersR1WorkOrders.source=integrationApiPostWorkOrdersR1WorkOrdersSub
foundation.stream.sub.integrationApiPostWorkOrdersR1WorkOrders.spin.agent=integrationApiPostWorkOrdersR1WorkOrdersAgent
foundation.stream.sub.integrationApiPostWorkOrdersR1WorkOrders.spin.tenant=admin

# SQS Source
foundation.stream.source.integrationApiPostWorkOrdersR1WorkOrdersSub.type=SQS
foundation.stream.source.integrationApiPostWorkOrdersR1WorkOrdersSub.endpoint=${env:SQS_ENDPOINT}
foundation.stream.source.integrationApiPostWorkOrdersR1WorkOrdersSub.topic=IntegrationApi-IntegrationApiPostWorkOrdersR1WorkOrders
foundation.stream.source.integrationApiPostWorkOrdersR1WorkOrdersSub.logging=true
foundation.stream.source.integrationApiPostWorkOrdersR1WorkOrdersSub.emergencyTopic=IntegrationApi-IntegrationApiPostWorkOrdersR1WorkOrders-DLQ

4. PATCH /integration/work-orders/r1/work-orders

Property Key: integrationApiPatchWorkOrdersR1WorkOrders

# Enable endpoint
integrationlayer.async.processing.integrationApiPatchWorkOrdersR1WorkOrders.enabled=true

# Publisher configuration (SNS)
foundation.stream.pub=snsIntegrationApiPatchWorkOrdersR1WorkOrders
foundation.stream.pub.snsIntegrationApiPatchWorkOrdersR1WorkOrders.spout=*.spout.PatchIntegrationWorkOrdersR1WorkOrdersAsyncProcessingRequestMessage
foundation.stream.pub.snsIntegrationApiPatchWorkOrdersR1WorkOrders.target=integrationApiPatchWorkOrdersR1WorkOrdersTarget

# SNS Target
foundation.stream.target.integrationApiPatchWorkOrdersR1WorkOrdersTarget.type=SNS
foundation.stream.target.integrationApiPatchWorkOrdersR1WorkOrdersTarget.endpoint=${env:SNS_ENDPOINT}
foundation.stream.target.integrationApiPatchWorkOrdersR1WorkOrdersTarget.topic=IntegrationApi-IntegrationApiPatchWorkOrdersR1WorkOrders

# Subscriber configuration (SQS)
foundation.stream.sub=integrationApiPatchWorkOrdersR1WorkOrders
foundation.stream.sub.integrationApiPatchWorkOrdersR1WorkOrders.spin=*.spin.PatchIntegrationWorkOrdersR1WorkOrdersAsyncProcessingEventRequestMessage
foundation.stream.sub.integrationApiPatchWorkOrdersR1WorkOrders.source=integrationApiPatchWorkOrdersR1WorkOrdersSub
foundation.stream.sub.integrationApiPatchWorkOrdersR1WorkOrders.spin.agent=integrationApiPatchWorkOrdersR1WorkOrdersAgent
foundation.stream.sub.integrationApiPatchWorkOrdersR1WorkOrders.spin.tenant=admin

# SQS Source
foundation.stream.source.integrationApiPatchWorkOrdersR1WorkOrdersSub.type=SQS
foundation.stream.source.integrationApiPatchWorkOrdersR1WorkOrdersSub.endpoint=${env:SQS_ENDPOINT}
foundation.stream.source.integrationApiPatchWorkOrdersR1WorkOrdersSub.topic=IntegrationApi-IntegrationApiPatchWorkOrdersR1WorkOrders
foundation.stream.source.integrationApiPatchWorkOrdersR1WorkOrdersSub.logging=true
foundation.stream.source.integrationApiPatchWorkOrdersR1WorkOrdersSub.emergencyTopic=IntegrationApi-IntegrationApiPatchWorkOrdersR1WorkOrders-DLQ

5. POST /integration/workforce/r1/work-shift-exceptions

Property Key: integrationApiPostWorkforceR1WorkShiftExceptions

# Enable endpoint
integrationlayer.async.processing.integrationApiPostWorkforceR1WorkShiftExceptions.enabled=true

# Publisher configuration (SNS)
foundation.stream.pub=snsIntegrationApiPostWorkforceR1WorkShiftExceptions
foundation.stream.pub.snsIntegrationApiPostWorkforceR1WorkShiftExceptions.spout=*.spout.PostIntegrationWorkforceR1WorkShiftExceptionsAsyncProcessingRequestMessage
foundation.stream.pub.snsIntegrationApiPostWorkforceR1WorkShiftExceptions.target=integrationApiPostWorkforceR1WorkShiftExceptionsTarget

# SNS Target
foundation.stream.target.integrationApiPostWorkforceR1WorkShiftExceptionsTarget.type=SNS
foundation.stream.target.integrationApiPostWorkforceR1WorkShiftExceptionsTarget.endpoint=${env:SNS_ENDPOINT}
foundation.stream.target.integrationApiPostWorkforceR1WorkShiftExceptionsTarget.topic=IntegrationApi-IntegrationApiPostWorkforceR1WorkShiftExceptions

# Subscriber configuration (SQS)
foundation.stream.sub=integrationApiPostWorkforceR1WorkShiftExceptions
foundation.stream.sub.integrationApiPostWorkforceR1WorkShiftExceptions.spin=*.spin.PostIntegrationWorkforceR1WorkShiftExceptionsAsyncProcessingEventRequestMessage
foundation.stream.sub.integrationApiPostWorkforceR1WorkShiftExceptions.source=integrationApiPostWorkforceR1WorkShiftExceptionsSub
foundation.stream.sub.integrationApiPostWorkforceR1WorkShiftExceptions.spin.agent=integrationApiPostWorkforceR1WorkShiftExceptionsAgent
foundation.stream.sub.integrationApiPostWorkforceR1WorkShiftExceptions.spin.tenant=admin

# SQS Source
foundation.stream.source.integrationApiPostWorkforceR1WorkShiftExceptionsSub.type=SQS
foundation.stream.source.integrationApiPostWorkforceR1WorkShiftExceptionsSub.endpoint=${env:SQS_ENDPOINT}
foundation.stream.source.integrationApiPostWorkforceR1WorkShiftExceptionsSub.topic=IntegrationApi-IntegrationApiPostWorkforceR1WorkShiftExceptions
foundation.stream.source.integrationApiPostWorkforceR1WorkShiftExceptionsSub.logging=true
foundation.stream.source.integrationApiPostWorkforceR1WorkShiftExceptionsSub.emergencyTopic=IntegrationApi-IntegrationApiPostWorkforceR1WorkShiftExceptions-DLQ

Important Notes:

  • If you enable multiple endpoints, combine the foundation.stream.pub and foundation.stream.sub properties with comma-separated values

  • Always include the Notify Async Stream when using callbacks

  • Example for enabling 2 endpoints with notify stream:

    foundation.stream.pub=snsIntegrationApiPostAssetsR1Assets,snsIntegrationApiPostWorkOrdersR1WorkOrders,snsIntegrationApiNotifyAsync
    foundation.stream.sub=integrationApiPostAssetsR1Assets,integrationApiPostWorkOrdersR1WorkOrders,integrationApiNotifyAsync
    

Configuration

Prerequisites

  • AWS SNS and SQS configuration (via Foundation stream properties)

  • Notify Async Stream configuration (required for callbacks)

  • Callback endpoint URL (optional - callback is only enabled if the URL is configured)

  • Authentication credentials for the callback endpoint (optional, depends on auth type)

Step 1: Configure Foundation Stream Properties

For each endpoint you want to enable asynchronously, you must manually configure the Foundation stream properties for SNS publishing and SQS consumption.

Example: Async Processing for POST /integration/assets/r1/assets

The property key follows the pattern: integrationApi{HttpMethod}{CamelCasePath}

For this endpoint, the key is: integrationApiPostAssetsR1Assets

Add the following properties to your setup.properties:

# Enable endpoint
integrationlayer.async.processing.integrationApiPostAssetsR1Assets.enabled=true

# Publisher configuration (SNS)
foundation.stream.pub=snsIntegrationApiPostAssetsR1Assets
foundation.stream.pub.snsIntegrationApiPostAssetsR1Assets.spout=*.spout.PostIntegrationAssetsR1AssetsAsyncProcessingRequestMessage
foundation.stream.pub.snsIntegrationApiPostAssetsR1Assets.target=integrationApiPostAssetsR1AssetsTarget

# SNS Target
foundation.stream.target.integrationApiPostAssetsR1AssetsTarget.type=SNS
foundation.stream.target.integrationApiPostAssetsR1AssetsTarget.endpoint=${env:SNS_ENDPOINT}
foundation.stream.target.integrationApiPostAssetsR1AssetsTarget.topic=IntegrationApi-IntegrationApiPostAssetsR1Assets

# Subscriber configuration (SQS)
foundation.stream.sub=integrationApiPostAssetsR1Assets
foundation.stream.sub.integrationApiPostAssetsR1Assets.spin=*.spin.PostIntegrationAssetsR1AssetsAsyncProcessingEventRequestMessage
foundation.stream.sub.integrationApiPostAssetsR1Assets.source=integrationApiPostAssetsR1AssetsSub
foundation.stream.sub.integrationApiPostAssetsR1Assets.spin.agent=integrationApiPostAssetsR1AssetsAgent
foundation.stream.sub.integrationApiPostAssetsR1Assets.spin.tenant=admin

# SQS Source
foundation.stream.source.integrationApiPostAssetsR1AssetsSub.type=SQS
foundation.stream.source.integrationApiPostAssetsR1AssetsSub.endpoint=${env:SQS_ENDPOINT}
foundation.stream.source.integrationApiPostAssetsR1AssetsSub.topic=IntegrationApi-IntegrationApiPostAssetsR1Assets
foundation.stream.source.integrationApiPostAssetsR1AssetsSub.logging=true
foundation.stream.source.integrationApiPostAssetsR1AssetsSub.emergencyTopic=IntegrationApi-IntegrationApiPostAssetsR1Assets-DLQ

Step 2: Configure Notify Async Stream

If you want to receive callbacks when async processing completes, you must configure the Notify Async Stream. See the Notify Async Stream Configuration section above.

Step 3: Configure Callback (Optional)

If you want to receive callbacks when async processing completes, configure the callback settings:

# Global callback endpoint (optional)
integrationlayer.async.processing.global.callback.endpoint=${env:ASYNC_PROCESSING_CALLBACK_ENDPOINT}

# Global authentication configuration (optional)
# Supported auth types: "none", "basic", "bearer"
# Default: "none" (if not specified)
integrationlayer.async.processing.global.auth.type=${env:ASYNC_PROCESSING_CALLBACK_AUTH_TYPE}

# Required only for "basic" and "bearer" auth types
integrationlayer.async.processing.global.auth.user=${env:ASYNC_PROCESSING_CALLBACK_AUTH_USER}
integrationlayer.async.processing.global.auth.password=${env:ASYNC_PROCESSING_CALLBACK_AUTH_PASSWORD}

# Required only for "bearer" auth type (OAuth2 token endpoint)
integrationlayer.async.processing.global.auth.url=${env:ASYNC_PROCESSING_CALLBACK_AUTH_URL}

You can also override callback settings per endpoint:

# Override callback endpoint for specific endpoint
integrationlayer.async.processing.integrationApiPostAssetsR1Assets.callback.endpoint=${env:CUSTOM_CALLBACK_ENDPOINT}
integrationlayer.async.processing.integrationApiPostAssetsR1Assets.auth.type=basic
integrationlayer.async.processing.integrationApiPostAssetsR1Assets.auth.user=custom_user
integrationlayer.async.processing.integrationApiPostAssetsR1Assets.auth.password=custom_password

Authentication Types

The callback mechanism supports three authentication types:

Auth Type

Description

Required Properties

none

No authentication (default if not specified)

None

basic

HTTP Basic Authentication

auth.user, auth.password

bearer

OAuth2 Bearer Token Authentication

auth.user, auth.password, auth.url

Important Notes:

  • If auth.type is not specified, it defaults to none

  • The callback is only executed if callback.endpoint is configured

  • For bearer auth, the system will automatically retrieve an OAuth2 token from auth.url using the provided credentials

Step 4: Set Environment Variables

Configure the following environment variables:

Bash
# AWS Endpoints (REQUIRED)
SNS_ENDPOINT=arn:aws:sns:eu-west-1:0000012344556
SQS_ENDPOINT=https://sqs.eu-west-1.amazonaws.com

# Callback Configuration (optional - only if you want callbacks)
ASYNC_PROCESSING_CALLBACK_ENDPOINT=https://your-app.com/callback

# Authentication Configuration (optional - depends on auth type)
ASYNC_PROCESSING_CALLBACK_AUTH_TYPE=basic  # Options: none, basic, bearer
ASYNC_PROCESSING_CALLBACK_AUTH_USER=username
ASYNC_PROCESSING_CALLBACK_AUTH_PASSWORD=password

# Only for bearer auth type
ASYNC_PROCESSING_CALLBACK_AUTH_URL=https://auth-server.com/oauth/token

Property Key Naming Convention

The property key is generated based on:

  • HTTP method (Post, Get, Put, Patch, Delete)

  • Controller path

  • Method path

Pattern: integrationApi + {HttpMethod} + {CamelCasePath}

Examples:

  • POST /integration/assets/r1/assetsintegrationApiPostAssetsR1Assets

  • POST /integration/work-orders/r1/work-ordersintegrationApiPostWorkOrdersR1WorkOrders

  • PATCH /integration/work-orders/r1/work-ordersintegrationApiPatchWorkOrdersR1WorkOrders

  • POST /integration/assets/r1/accountsintegrationApiPostAssetsR1Accounts

  • POST /integration/workforce/r1/work-shift-exceptionsintegrationApiPostWorkforceR1WorkShiftExceptions


Complete Configuration Example

Here's a complete example for enabling async processing on two endpoints with callback support:

setup.properties:

# ============================================
# Notify Async Stream (REQUIRED for callbacks)
# ============================================

# Publisher configuration (SNS)
foundation.stream.pub.snsIntegrationApiNotifyAsync.spout=*.spout.AsyncProcessingNotifyMessage
foundation.stream.pub.snsIntegrationApiNotifyAsync.target=integrationApiNotifyAsyncTarget

# SNS Target
foundation.stream.target.integrationApiNotifyAsyncTarget.type=SNS
foundation.stream.target.integrationApiNotifyAsyncTarget.endpoint=${env:SNS_ENDPOINT}
foundation.stream.target.integrationApiNotifyAsyncTarget.topic=IntegrationApi-NotifyAsync

# Subscriber configuration (SQS)
foundation.stream.sub.integrationApiNotifyAsync.spin=*.spin.AsyncProcessingEventNotifyMessage
foundation.stream.sub.integrationApiNotifyAsync.source=integrationApiNotifyAsyncSub
foundation.stream.sub.integrationApiNotifyAsync.spin.agent=integrationApiNotifyAsyncAgent
foundation.stream.sub.integrationApiNotifyAsync.spin.tenant=admin

# SQS Source
foundation.stream.source.integrationApiNotifyAsyncSub.type=SQS
foundation.stream.source.integrationApiNotifyAsyncSub.endpoint=${env:SQS_ENDPOINT}
foundation.stream.source.integrationApiNotifyAsyncSub.topic=IntegrationApi-NotifyAsync
foundation.stream.source.integrationApiNotifyAsyncSub.logging=true
foundation.stream.source.integrationApiNotifyAsyncSub.emergencyTopic=IntegrationApi-NotifyAsync-DLQ

# ============================================
# Async Processing for POST /integration/assets/r1/assets
# ============================================

# Enable endpoint
integrationlayer.async.processing.integrationApiPostAssetsR1Assets.enabled=true

# Publisher configuration (SNS)
foundation.stream.pub=snsIntegrationApiPostAssetsR1Assets,snsIntegrationApiPostWorkOrdersR1WorkOrders,snsIntegrationApiNotifyAsync
foundation.stream.pub.snsIntegrationApiPostAssetsR1Assets.spout=*.spout.PostIntegrationAssetsR1AssetsAsyncProcessingRequestMessage
foundation.stream.pub.snsIntegrationApiPostAssetsR1Assets.target=integrationApiPostAssetsR1AssetsTarget

# SNS Target
foundation.stream.target.integrationApiPostAssetsR1AssetsTarget.type=SNS
foundation.stream.target.integrationApiPostAssetsR1AssetsTarget.endpoint=${env:SNS_ENDPOINT}
foundation.stream.target.integrationApiPostAssetsR1AssetsTarget.topic=IntegrationApi-IntegrationApiPostAssetsR1Assets

# Subscriber configuration (SQS)
foundation.stream.sub=integrationApiPostAssetsR1Assets,integrationApiPostWorkOrdersR1WorkOrders,integrationApiNotifyAsync
foundation.stream.sub.integrationApiPostAssetsR1Assets.spin=*.spin.PostIntegrationAssetsR1AssetsAsyncProcessingEventRequestMessage
foundation.stream.sub.integrationApiPostAssetsR1Assets.source=integrationApiPostAssetsR1AssetsSub
foundation.stream.sub.integrationApiPostAssetsR1Assets.spin.agent=integrationApiPostAssetsR1AssetsAgent
foundation.stream.sub.integrationApiPostAssetsR1Assets.spin.tenant=admin

# SQS Source
foundation.stream.source.integrationApiPostAssetsR1AssetsSub.type=SQS
foundation.stream.source.integrationApiPostAssetsR1AssetsSub.endpoint=${env:SQS_ENDPOINT}
foundation.stream.source.integrationApiPostAssetsR1AssetsSub.topic=IntegrationApi-IntegrationApiPostAssetsR1Assets
foundation.stream.source.integrationApiPostAssetsR1AssetsSub.logging=true
foundation.stream.source.integrationApiPostAssetsR1AssetsSub.emergencyTopic=IntegrationApi-IntegrationApiPostAssetsR1Assets-DLQ

# ============================================
# Async Processing for POST /integration/work-orders/r1/work-orders
# ============================================

# Enable endpoint
integrationlayer.async.processing.integrationApiPostWorkOrdersR1WorkOrders.enabled=true

# Publisher configuration (SNS)
foundation.stream.pub.snsIntegrationApiPostWorkOrdersR1WorkOrders.spout=*.spout.PostIntegrationWorkOrdersR1WorkOrdersAsyncProcessingRequestMessage
foundation.stream.pub.snsIntegrationApiPostWorkOrdersR1WorkOrders.target=integrationApiPostWorkOrdersR1WorkOrdersTarget

# SNS Target
foundation.stream.target.integrationApiPostWorkOrdersR1WorkOrdersTarget.type=SNS
foundation.stream.target.integrationApiPostWorkOrdersR1WorkOrdersTarget.endpoint=${env:SNS_ENDPOINT}
foundation.stream.target.integrationApiPostWorkOrdersR1WorkOrdersTarget.topic=IntegrationApi-IntegrationApiPostWorkOrdersR1WorkOrders

# Subscriber configuration (SQS)
foundation.stream.sub.integrationApiPostWorkOrdersR1WorkOrders.spin=*.spin.PostIntegrationWorkOrdersR1WorkOrdersAsyncProcessingEventRequestMessage
foundation.stream.sub.integrationApiPostWorkOrdersR1WorkOrders.source=integrationApiPostWorkOrdersR1WorkOrdersSub
foundation.stream.sub.integrationApiPostWorkOrdersR1WorkOrders.spin.agent=integrationApiPostWorkOrdersR1WorkOrdersAgent
foundation.stream.sub.integrationApiPostWorkOrdersR1WorkOrders.spin.tenant=admin

# SQS Source
foundation.stream.source.integrationApiPostWorkOrdersR1WorkOrdersSub.type=SQS
foundation.stream.source.integrationApiPostWorkOrdersR1WorkOrdersSub.endpoint=${env:SQS_ENDPOINT}
foundation.stream.source.integrationApiPostWorkOrdersR1WorkOrdersSub.topic=IntegrationApi-IntegrationApiPostWorkOrdersR1WorkOrders
foundation.stream.source.integrationApiPostWorkOrdersR1WorkOrdersSub.logging=true
foundation.stream.source.integrationApiPostWorkOrdersR1WorkOrdersSub.emergencyTopic=IntegrationApi-IntegrationApiPostWorkOrdersR1WorkOrders-DLQ

# ============================================
# Global Callback Configuration (Optional)
# ============================================

integrationlayer.async.processing.global.callback.endpoint=${env:ASYNC_PROCESSING_CALLBACK_ENDPOINT}
integrationlayer.async.processing.global.auth.type=basic
integrationlayer.async.processing.global.auth.user=${env:ASYNC_PROCESSING_CALLBACK_AUTH_USER}
integrationlayer.async.processing.global.auth.password=${env:ASYNC_PROCESSING_CALLBACK_AUTH_PASSWORD}

Note: When enabling multiple endpoints, the foundation.stream.pub and foundation.stream.sub properties should list all enabled endpoints separated by commas, including the Notify Async Stream.


How It Works

  1. Request Reception: When a request arrives at an async-enabled endpoint, it's immediately queued

  2. SNS Publishing: The request is published to an SNS topic (configured via foundation.stream.pub.*)

  3. SQS Processing: The message is consumed from an SQS queue (configured via foundation.stream.sub.*)

  4. Async Execution: The service method is executed asynchronously

  5. Notify Message: A notification message is published to the Notify Async Stream

  6. Callback (if configured): The Notify Async Stream processor calls the configured callback endpoint with the processing result

Callback Behavior

  • Callback is only executed if callback.endpoint is configured

  • Notify Async Stream must be configured for callbacks to work

  • If no callback endpoint is set, async processing still works but no notification is sent

  • The callback includes the processing result and the original request trace information

  • Authentication is applied based on the auth.type setting

AWS Resources Naming Convention

The SNS topics, SQS queues, and DLQs follow this naming pattern:

  • SNS Topic: IntegrationApi-{CapitalizedApiName}

  • SQS Queue: IntegrationApi-{CapitalizedApiName}

  • DLQ: IntegrationApi-{CapitalizedApiName}-DLQ

Example: For integrationApiPostAssetsR1Assets:

  • SNS Topic: IntegrationApi-IntegrationApiPostAssetsR1Assets

  • SQS Queue: IntegrationApi-IntegrationApiPostAssetsR1Assets

  • DLQ: IntegrationApi-IntegrationApiPostAssetsR1Assets-DLQ

For Notify Async Stream:

  • SNS Topic: IntegrationApi-NotifyAsync

  • SQS Queue: IntegrationApi-NotifyAsync

  • DLQ: IntegrationApi-NotifyAsync-DLQ


Troubleshooting

Async Processing Not Working

  1. Check all Foundation stream properties are configured:

    • Verify foundation.stream.pub includes your endpoint (e.g., foundation.stream.pub=snsIntegrationApiPostAssetsR1Assets)

    • Verify foundation.stream.pub.* properties for SNS publishing

    • Verify foundation.stream.target.* properties for SNS target

    • Verify foundation.stream.sub includes your endpoint (e.g., foundation.stream.sub=integrationApiPostAssetsR1Assets)

    • Verify foundation.stream.sub.* properties for SQS subscription

    • Verify foundation.stream.source.* properties for SQS source

  2. Check endpoint enable flag: Verify the specific endpoint is enabled with the correct property key

    integrationlayer.async.processing.integrationApiPostAssetsR1Assets.enabled=true
    
  3. Check AWS endpoints: Ensure SNS and SQS endpoints are configured and accessible

    Bash
    SNS_ENDPOINT=arn:aws:sns:eu-west-1:0000012344556
    SQS_ENDPOINT=https://sqs.eu-west-1.amazonaws.com
    
  4. Check AWS resources exist: Verify that the SNS topics and SQS queues exist in AWS with the correct names

  5. Check logs: Look for errors related to SNS/SQS connectivity or message processing

Callback Not Working

  1. Check Notify Async Stream is configured:

    • Verify foundation.stream.pub includes snsIntegrationApiNotifyAsync

    • Verify foundation.stream.sub includes integrationApiNotifyAsync

    • Verify all Notify Async Stream properties are configured (see Notify Async Stream Configuration)

  2. Check callback endpoint is configured:

    integrationlayer.async.processing.global.callback.endpoint=${env:ASYNC_PROCESSING_CALLBACK_ENDPOINT}
    

    Callback is only executed if this property is set

  3. Check authentication configuration:

    • For auth.type=basic: Ensure auth.user and auth.password are set

    • For auth.type=bearer: Ensure auth.user, auth.password, and auth.url are set

    • If auth.type is not set, it defaults to none (no authentication)

  4. Verify callback endpoint is accessible: Test the callback URL manually to ensure it's reachable

  5. Check logs for callback errors: Look for "Error during callback to external system" messages

  6. Check Notify Async Stream AWS resources exist: Verify that IntegrationApi-NotifyAsync SNS topic and SQS queue exist

Finding the Correct Property Key

The property key follows the pattern: integrationApi{HttpMethod}{CamelCasePath}

Steps to determine the key:

  1. Identify the HTTP method (POST, GET, PUT, PATCH, DELETE)

  2. Identify the full path (e.g., /integration/assets/r1/assets)

  3. Convert to camelCase, capitalizing the first letter of each segment except "integration"

  4. Prepend with integrationApi

Examples:

  • POST /integration/assets/r1/assetsintegrationApiPostAssetsR1Assets

  • POST /integration/work-orders/r1/work-ordersintegrationApiPostWorkOrdersR1WorkOrders

  • PATCH /integration/work-orders/r1/work-ordersintegrationApiPatchWorkOrdersR1WorkOrders

  • POST /integration/workforce/r1/work-shift-exceptionsintegrationApiPostWorkforceR1WorkShiftExceptions

Common Mistakes

  1. Missing Notify Async Stream configuration: Callbacks won't work without the Notify Async Stream

  2. Missing foundation.stream.pub or foundation.stream.sub properties: These must list all enabled endpoints including snsIntegrationApiNotifyAsync and integrationApiNotifyAsync

  3. Missing Foundation stream properties: All foundation.stream.* properties must be configured manually

  4. Expecting callback without configuring endpoint: Callback is only sent if callback.endpoint is configured

  5. Wrong authentication configuration: Make sure to provide all required properties for your chosen auth type

  6. Forgetting to enable specific endpoints: Even with all stream configuration, each endpoint must be individually enabled with .enabled=true

  7. Wrong property key format: Ensure you follow the exact naming convention (case-sensitive)

  8. Incorrect AWS resource names: SNS topics and SQS queues must match the naming convention exactly


Configuration Template

Use this template to configure async processing for any endpoint:

# ============================================
# Async Processing for {HTTP_METHOD} {ENDPOINT_PATH}
# Property Key: {PROPERTY_KEY}
# ============================================

# Enable endpoint
integrationlayer.async.processing.{PROPERTY_KEY}.enabled=true

# Publisher configuration (SNS)
# Add {PROPERTY_KEY_SNS} to the comma-separated list
foundation.stream.pub=sns{PROPERTY_KEY}
foundation.stream.pub.sns{PROPERTY_KEY}.spout=*.spout.{MessageClassName}
foundation.stream.pub.sns{PROPERTY_KEY}.target={PROPERTY_KEY}Target

# SNS Target
foundation.stream.target.{PROPERTY_KEY}Target.type=SNS
foundation.stream.target.{PROPERTY_KEY}Target.endpoint=${env:SNS_ENDPOINT}
foundation.stream.target.{PROPERTY_KEY}Target.topic=IntegrationApi-{CAPITALIZED_PROPERTY_KEY}

# Subscriber configuration (SQS)
# Add {PROPERTY_KEY} to the comma-separated list
foundation.stream.sub={PROPERTY_KEY}
foundation.stream.sub.{PROPERTY_KEY}.spin=*.spin.{MessageClassName}
foundation.stream.sub.{PROPERTY_KEY}.source={PROPERTY_KEY}Sub
foundation.stream.sub.{PROPERTY_KEY}.spin.agent={PROPERTY_KEY}Agent
foundation.stream.sub.{PROPERTY_KEY}.spin.tenant=admin

# SQS Source
foundation.stream.source.{PROPERTY_KEY}Sub.type=SQS
foundation.stream.source.{PROPERTY_KEY}Sub.endpoint=${env:SQS_ENDPOINT}
foundation.stream.source.{PROPERTY_KEY}Sub.topic=IntegrationApi-{CAPITALIZED_PROPERTY_KEY}
foundation.stream.source.{PROPERTY_KEY}Sub.logging=true
foundation.stream.source.{PROPERTY_KEY}Sub.emergencyTopic=IntegrationApi-{CAPITALIZED_PROPERTY_KEY}-DLQ

Replace:

  • {HTTP_METHOD} - HTTP method (POST, GET, PUT, etc.)

  • {ENDPOINT_PATH} - Full endpoint path

  • {PROPERTY_KEY} - Property key in camelCase (e.g., integrationApiPostAssetsR1Assets)

  • {CAPITALIZED_PROPERTY_KEY} - Property key with capital first letter (e.g., IntegrationApiPostAssetsR1Assets)

  • {MessageClassName} - Message class name (e.g., PostIntegrationAssetsR1AssetsAsyncProcessingRequestMessage)


Quick Reference Checklist

  • Determine the property key for your endpoint using the naming convention
  • Add the endpoint to foundation.stream.pub (with sns prefix)
  • Add the endpoint to foundation.stream.sub
  • Configure all Foundation stream properties (foundation.stream.pub.*, foundation.stream.target.*, foundation.stream.sub.*, foundation.stream.source.*)
  • Enable the endpoint with .enabled=true
  • Configure Notify Async Stream (required for callbacks)
  • Add snsIntegrationApiNotifyAsync to foundation.stream.pub
  • Add integrationApiNotifyAsync to foundation.stream.sub
  • Configure callback endpoint (optional)
  • Configure authentication (optional)
  • Set environment variables (SNS_ENDPOINT, SQS_ENDPOINT, callback settings)
  • Create AWS resources (SNS topics, SQS queues, DLQs) with correct names
  • Create Notify Async Stream AWS resources (IntegrationApi-NotifyAsync topic, queue, and DLQ)
  • Deploy and test

Required vs Optional Configuration

Configuration

Required?

Notes

foundation.stream.pub

Required

Comma-separated list of all enabled publishers (with sns prefix)

foundation.stream.sub

Required

Comma-separated list of all enabled subscribers

Foundation stream properties

Required

All foundation.stream.* properties must be configured

{endpoint}.enabled

Required

Each endpoint must be explicitly enabled

SNS/SQS endpoints

Required

Must be set via environment variables

AWS resources (topics/queues)

Required

Must exist in AWS with correct names

Notify Async Stream

Required for callbacks

Must be configured if you want callback notifications

global.callback.endpoint

Optional

Callback only works if this is set

global.auth.type

Optional

Defaults to none if not specified

global.auth.user

Conditional

Required for basic and bearer auth

global.auth.password

Conditional

Required for basic and bearer auth

global.auth.url

Conditional

Required only for bearer auth


For more information, contact the Integration API team.