> ## Documentation Index
> Fetch the complete documentation index at: https://docs.asapp.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Azure Communication Services

> Learn how to integrate GenerativeAgent with Azure Communication Services to handle inbound PSTN calls

Use the Azure Communication Services (ACS) integration to route inbound PSTN calls to GenerativeAgent through your ACS phone numbers. Your Azure Event Grid routes calls directly to ASAPP's webhook endpoint with no code deployment or pre-call IVR required on your end.

<Note>
  If you need to collect caller context before connecting to GenerativeAgent (for example, account numbers or menu selections), an advanced IVR integration pattern is also supported. See the [Advanced Integration Pattern](#advanced-integration-pattern) section below.
</Note>

## How it works

Azure Communication Services separates call control (HTTP callbacks) from audio streaming (WebSocket). ASAPP handles both channels through the ACS media gateway.

At a high level, the integration works as follows:

1. **Caller dials your ACS phone number.** Azure generates an `IncomingCall` event and routes it to ASAPP's webhook via your Event Grid subscription.
2. **ASAPP answers the call.** The media gateway answers the call using Azure's Call Automation API and opens a bidirectional WebSocket audio stream.
3. **GenerativeAgent handles the conversation.** ASAPP streams audio in real time between the caller and GenerativeAgent, and automatically detects and forwards DTMF tones (keypad input).
4. **The call ends.** The call ends when GenerativeAgent completes the conversation, the caller hangs up, or a connection failure occurs.

<Accordion title="Detailed call flow">
  **1. Call initiation**

  The caller dials your ACS phone number. Azure receives the inbound PSTN call and generates an `IncomingCall` event.

  **2. IncomingCall notification**

  Azure Event Grid sends a webhook notification to ASAPP with your `asapp-api-id` and `asapp-api-secret` authentication headers. The event includes the call identifier, caller and called phone numbers, and an `incomingCallContext` token required to answer the call. For advanced integrations, the event may also include custom data collected by your IVR in `customContext.voipHeaders`.

  ASAPP's API gateway validates the authentication headers, maps them to your account, adds routing metadata, and forwards the event to the media gateway router.

  **3. Event routing**

  The media gateway router receives the validated event, extracts the routing header, responds 200 OK to Azure, converts the event to protobuf, and forwards it to an available media gateway pod.

  **4. Token generation**

  The media gateway pod retrieves JWT signing keys from Vault and generates two authentication tokens:

  * A **WebSocket token**: short-lived (30 seconds), used to authenticate Azure's audio streaming connection.
  * A **callback token**: longer-lived (3 hours), used to authenticate Azure's call state callback notifications.

  **5. Answer call**

  The media gateway pod uses Azure's Call Automation API to answer the call, providing:

  * A callback URL with the embedded callback JWT for subsequent call state events.
  * A WebSocket streaming URL with the embedded WebSocket JWT for audio streaming.

  **6. WebSocket connection**

  Azure establishes a WebSocket connection to the media gateway using the streaming URL. The pod validates the JWT (signature and expiration), then registers the call session with the media gateway router, creating a mapping that enables call state callbacks to route to the correct pod.

  **7. VoiceGenAgent connection**

  Upon receiving the initial audio stream metadata from Azure, the media gateway connects to GenerativeAgent with call information and session configuration. For advanced integrations, input variables collected by your IVR are included at this stage. ASAPP establishes recording and audio routing pipelines, bidirectional audio flow begins, and the call is now active.
</Accordion>

### During a call

Once the call is active, ASAPP manages audio, input detection, and recording concurrently.

* **Audio (caller to GenerativeAgent)**: ACS streams audio to ASAPP, which transcodes and forwards it to GenerativeAgent.
* **Audio (GenerativeAgent to caller)**: ASAPP receives GenerativeAgent's audio responses, transcodes, and sends them to ACS.
* **DTMF detection**: When the caller presses a keypad key, ACS sends a DTMF event over the WebSocket. ASAPP forwards it to GenerativeAgent.
* **Call recording**: If recording is enabled, ASAPP captures both audio streams.

## Before you begin

Before configuring the integration, you need:

* API credentials (API ID and API Secret) provisioned by ASAPP during onboarding. Contact your ASAPP account team to enable the ACS integration and receive your credentials.
* An Azure subscription with an Azure Communication Services resource.
* A phone number provisioned in your ACS resource.
* Permissions to create Event Grid subscriptions on your ACS resource.

## Configure the Azure Event Grid subscription

To complete the direct integration, set up an Azure Event Grid subscription on your ACS resource to route `IncomingCall` events to ASAPP's webhook.

<Steps>
  <Step title="Navigate to your ACS resource">
    In the Azure portal, open your Azure Communication Services resource and go to **Events** in the left menu.

    <Frame>
      <img src="https://mintcdn.com/asapp/OFHp9RxIM0yJpwoI/images/generativeagent/integrate/navigate_to_your_acs_resource.png?fit=max&auto=format&n=OFHp9RxIM0yJpwoI&q=85&s=350e0079ad16df1e7d56ce5db151587d" alt="ACS resource with Events selected in the left navigation menu" width="922" height="1320" data-path="images/generativeagent/integrate/navigate_to_your_acs_resource.png" />
    </Frame>
  </Step>

  <Step title="Create an Event Subscription">
    Click **+ Event Subscription** and configure the following:

    | Setting             | Value                                                 |
    | ------------------- | ----------------------------------------------------- |
    | Event Types         | `Microsoft.Communication.IncomingCall`                |
    | Endpoint Type       | Webhook                                               |
    | Subscriber Endpoint | `https://api.asapp.com/mg-genagent-acs/v1/acs-events` |

    <Frame>
      <img src="https://mintcdn.com/asapp/OFHp9RxIM0yJpwoI/images/generativeagent/integrate/create_event_subscription.png?fit=max&auto=format&n=OFHp9RxIM0yJpwoI&q=85&s=f28447bf93989c47df36a0bef75d07b0" alt="Event Subscription creation form with the required fields filled out" width="1438" height="1728" data-path="images/generativeagent/integrate/create_event_subscription.png" />
    </Frame>
  </Step>

  <Step title="Add authentication headers">
    In the **Delivery Properties** tab, add the following custom headers using the credentials provided by ASAPP:

    | Header name        | Value                 | Mark as secret |
    | ------------------ | --------------------- | -------------- |
    | `asapp-api-id`     | Your ASAPP API ID     | Yes            |
    | `asapp-api-secret` | Your ASAPP API Secret | Yes            |

    Mark both values as secret so Azure obscures them in the portal.

    <Frame>
      <img src="https://mintcdn.com/asapp/OFHp9RxIM0yJpwoI/images/generativeagent/integrate/delivery_properties.png?fit=max&auto=format&n=OFHp9RxIM0yJpwoI&q=85&s=26fedce2389e65a813b1aa4bd0567ed7" alt="Delivery Properties tab showing asapp-api-id and asapp-api-secret headers configured as secrets" width="3034" height="1610" data-path="images/generativeagent/integrate/delivery_properties.png" />
    </Frame>
  </Step>

  <Step title="Validate and save">
    Azure sends a validation request to the webhook endpoint to confirm it is accessible. Once validated, save the subscription.

    `IncomingCall` events from your ACS phone number now route to ASAPP automatically.
  </Step>
</Steps>

<Note>
  You need a separate Event Grid subscription for each ASAPP environment (sandbox and production). Use your sandbox credentials and endpoint for testing, and switch to production credentials when going live.
</Note>

## Advanced Integration Pattern

If you need to run pre-call IVR logic before connecting to GenerativeAgent (for example, collecting an account number, authenticating the caller, or routing through a menu), you can use an advanced integration pattern. In this pattern, you deploy your own IVR service that handles the initial call, then transfers to GenerativeAgent with collected context.

<Note>
  This pattern requires you to build and deploy an IVR service in your own Azure infrastructure using the Azure Communication Services Call Automation SDK.
</Note>

### How it works

Instead of routing calls directly to ASAPP, your Event Grid routes `IncomingCall` events to your own IVR service first. Your IVR collects caller context, then transfers the call to ASAPP using a dedicated ACS user identity. A second Event Grid subscription routes these transferred calls to ASAPP's webhook.

Any key-value pairs your IVR passes in the transfer's custom context are forwarded to GenerativeAgent as input variables, enabling personalized conversations based on data collected during your IVR flow.

**Example**: Your IVR collects the caller's account number via DTMF. It passes `accountNumber: "12345"` in the transfer's custom context. GenerativeAgent receives this as an input variable and can personalize the greeting accordingly.

### Setup

**Azure configuration**

1. Create an ACS `CommunicationUserIdentifier` for ASAPP using `CommunicationIdentityClient.createUser()`. This is the identity your IVR transfers calls to. Provide this identifier to your ASAPP account team during onboarding.

2. Create two Event Grid subscriptions on your ACS resource:

   | Subscription       | Filter                                                                   | Endpoint                                                                                                            |
   | ------------------ | ------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------- |
   | IVR subscription   | `IncomingCall` where `to.kind == "phoneNumber"`                          | Your IVR service webhook                                                                                            |
   | ASAPP subscription | `IncomingCall` where `to.id` matches ASAPP's CommunicationUserIdentifier | `https://api.asapp.com/mg-genagent-acs/v1/acs-events` (with `asapp-api-id` and `asapp-api-secret` delivery headers) |

**IVR service requirements**

Your IVR service must:

* Receive `IncomingCall` webhooks from Azure Event Grid.
* Use the [Azure Communication Services Call Automation SDK](https://learn.microsoft.com/en-us/azure/communication-services/concepts/call-automation/call-automation) to control calls programmatically (available in .NET, JavaScript, Python, and Java).
* Answer the call using `answerCall()` with the `incomingCallContext` claim.
* Collect caller context using `getCallMedia().startRecognizing()` for audio prompts and DTMF input.
* Transfer the call to ASAPP's CommunicationUserIdentifier using `transferCallToParticipant()`, passing collected data in `customCallingContext.voipHeaders`.

All key-value pairs in `customCallingContext.voipHeaders` are passed to GenerativeAgent as input variables.

**Returning control to your IVR**

If GenerativeAgent needs to return control to your IVR (for example, to route to a human agent based on conversation outcome), provide your IVR service's CommunicationUserIdentifier in the transfer's custom context. ASAPP stores this identifier and uses it to transfer the call back with GenerativeAgent's output variables in the custom context.

## Test the integration

To test your integration:

1. Call your ACS phone number from a test phone.
2. Confirm GenerativeAgent answers and responds to your questions.
3. Test variations including normal conversations, requests for a human agent, and caller hangup.

Contact your ASAPP account team if calls are not routing correctly or if GenerativeAgent does not answer.

## Next Steps

<CardGroup>
  <Card title="Configuration Overview" href="/generativeagent/configuring">
    Learn how to configure GenerativeAgent's behaviors, tasks, and communication style
  </Card>

  <Card title="Connect your APIs" href="/generativeagent/configuring/connect-apis">
    Configure your APIs to allow GenerativeAgent to access necessary data and perform actions
  </Card>

  <Card title="Input Variables" href="/generativeagent/configuring/tasks-and-functions/input-variables">
    Pass caller context to GenerativeAgent to personalize conversations
  </Card>

  <Card title="Go Live" href="/generativeagent/go-live">
    Follow the deployment checklist to launch GenerativeAgent in your production environment
  </Card>
</CardGroup>
