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

# Asynchronous Notifications

> Webhook endpoint for receiving asynchronous notifications from Suki platform

Use this endpoint specification to implement a <Tooltip tip="A mechanism that allows Suki to send real-time event notifications to your application's server." cta="View in Glossary" href="/Glossary/w">webhook</Tooltip> endpoint in your application that receives notifications from the Suki platform.
This endpoint should be hosted by your application to receive notifications about <Tooltip tip="A single, time-bound instance of an ambient recording for a specific patient encounter." cta="View in Glossary" href="/Glossary/s">session</Tooltip> completion or failure.

Learn more about how webhooks work and how to implement your own webhook endpoint to receive them in the [Notification webhook for partners](/documentation/webhook/overview) documentation.

## Code examples

<Tabs>
  <Tab title="Python">
    ```python theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
    from flask import Flask, request, jsonify

    app = Flask(__name__)

    @app.route('/webhooks/notification', methods=['POST'])
    def handle_webhook():
        """
        Webhook endpoint to receive notifications from Suki platform.
        This endpoint should be hosted by your application.
        """
        # The payload is received in the request body from Suki
        data = request.get_json()  # This is the payload sent by Suki
        
        if not data:
            return jsonify({"error": "Invalid request"}), 400
        
        status = data.get("status")
        
        if status == "success":
            # Handle success notification
            session_id = data.get("session_id")
            encounter_id = data.get("encounter_id")
            sessions = data.get("sessions", [])
            additional_info = data.get("additional_info")
            
            print(f"Session {session_id} completed successfully")
            print(f"Encounter ID: {encounter_id}")
            print(f"Total sessions: {len(sessions)}")
            if additional_info:
                print(f"Additional info: {additional_info}")
            
            # Access links to retrieve content
            if "_links" in data:
                links = data["_links"]
                print("Available links:")
                
                # contents is an array of Link objects
                if "contents" in links:
                    print("  Session contents:")
                    for link in links["contents"]:
                        print(f"    {link.get('method')} {link.get('href')} - {link.get('name')}")
                
                # encounter_content is an array of Link objects
                if "encounter_content" in links:
                    print("  Encounter content:")
                    for link in links["encounter_content"]:
                        print(f"    {link.get('method')} {link.get('href')} - {link.get('name')}")
                
                # transcripts is an array of Link objects
                if "transcripts" in links:
                    print("  Transcripts:")
                    for link in links["transcripts"]:
                        print(f"    {link.get('method')} {link.get('href')} - {link.get('name')}")
                
                # status is an array of Link objects
                if "status" in links:
                    print("  Status:")
                    for link in links["status"]:
                        print(f"    {link.get('method')} {link.get('href')} - {link.get('name')}")
            
            return jsonify({"message": "Notification received"}), 200
        
        elif status == "failure":
            # Handle failure notification
            session_id = data.get("session_id")
            encounter_id = data.get("encounter_id")
            error_code = data.get("error_code")
            error_detail = data.get("error_detail")
            
            print(f"Session {session_id} failed")
            print(f"Encounter ID: {encounter_id}")
            print(f"Error Code: {error_code}")
            print(f"Error Detail: {error_detail}")
            
            return jsonify({"message": "Failure notification received"}), 200
        
        else:
            return jsonify({"error": "Unknown status"}), 400

    if __name__ == '__main__':
        app.run(port=3000)
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
    import express from 'express';

    const app = express();
    app.use(express.json());

    app.post('/webhooks/notification', (req, res) => {
      /**
       * Webhook endpoint to receive notifications from Suki platform.
       * This endpoint should be hosted by your application.
       */
      // The payload is received in the request body from Suki
      const data = req.body;  // This is the payload sent by Suki
      
      if (!data) {
        return res.status(400).json({ error: 'Invalid request' });
      }
      
      const status = data.status;
      
      if (status === 'success') {
        // Handle success notification
        const sessionId = data.session_id;
        const encounterId = data.encounter_id;
        const sessions = data.sessions || [];
        const additionalInfo = data.additional_info;
        
        console.log(`Session ${sessionId} completed successfully`);
        console.log(`Encounter ID: ${encounterId}`);
        console.log(`Total sessions: ${sessions.length}`);
        if (additionalInfo) {
          console.log(`Additional info:`, additionalInfo);
        }
        
        // Access links to retrieve content
        if (data._links) {
          const links = data._links;
          console.log('Available links:');
          
          // contents is an array of Link objects
          if (links.contents) {
            console.log('  Session contents:');
            links.contents.forEach((link: any) => {
              console.log(`    ${link.method} ${link.href} - ${link.name}`);
            });
          }
          
          // encounter_content is an array of Link objects
          if (links.encounter_content) {
            console.log('  Encounter content:');
            links.encounter_content.forEach((link: any) => {
              console.log(`    ${link.method} ${link.href} - ${link.name}`);
            });
          }
          
          // transcripts is an array of Link objects
          if (links.transcripts) {
            console.log('  Transcripts:');
            links.transcripts.forEach((link: any) => {
              console.log(`    ${link.method} ${link.href} - ${link.name}`);
            });
          }
          
          // status is an array of Link objects
          if (links.status) {
            console.log('  Status:');
            links.status.forEach((link: any) => {
              console.log(`    ${link.method} ${link.href} - ${link.name}`);
            });
          }
        }
        
        return res.status(200).json({ message: 'Notification received' });
      } else if (status === 'failure') {
        // Handle failure notification
        const sessionId = data.session_id;
        const encounterId = data.encounter_id;
        const errorCode = data.error_code;
        const errorDetail = data.error_detail;
        
        console.log(`Session ${sessionId} failed`);
        console.log(`Encounter ID: ${encounterId}`);
        console.log(`Error Code: ${errorCode}`);
        console.log(`Error Detail: ${errorDetail}`);
        
        return res.status(200).json({ message: 'Failure notification received' });
      } else {
        return res.status(400).json({ error: 'Unknown status' });
      }
    });

    app.listen(3000, () => {
      console.log('Webhook server listening on port 3000');
    });
    ```
  </Tab>
</Tabs>


## OpenAPI

````yaml POST /webhooks/notification
openapi: 3.0.1
info:
  title: Suki Developer Platform
  description: >-
    REST and WebSocket APIs for the Suki Developer Platform. Authenticate with
    Login or Register to obtain a Suki access token, then integrate ambient
    clinical documentation, form filling, transcription, and reference metadata
    endpoints.
  contact: {}
  version: '1.0'
servers:
  - url: https://sdp.suki.ai
    description: >-
      Production base URL for Suki Developer Platform REST APIs. WebSocket
      endpoints use the same host with `wss://`.
security:
  - SukiTokenAuth: []
paths:
  /webhooks/notification:
    post:
      tags:
        - /webhooks
      summary: Receive asynchronous notifications (partner webhook)
      description: >-
        Specification for the webhook endpoint your application hosts to receive
        asynchronous notifications from Suki when ambient session processing
        completes or fails. Suki sends POST requests to your configured
        notification URL.
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/controllers.FailureNotification'
        required: false
      responses:
        '200':
          description: OK
          content: {}
        '400':
          description: Bad request. The request body or parameters failed validation.
          content:
            '*/*':
              schema:
                $ref: '#/components/schemas/controllers.BadRequestError'
        '401':
          description: Unauthorized. The Suki access token is missing, expired, or invalid.
          content:
            '*/*':
              schema:
                $ref: '#/components/schemas/controllers.AuthenticationError'
        '500':
          description: Internal server error.
          content:
            '*/*':
              schema:
                $ref: '#/components/schemas/controllers.InternalServerError'
      security: []
components:
  schemas:
    controllers.FailureNotification:
      type: object
      properties:
        encounter_id:
          type: string
          description: Id of the encounter to which the payload belongs.
          example: 29de56bc-960a-4cd5-b18f-79a798d62874
        error_code:
          type: string
          description: Error code.
          example: ERROR_CODE_TRANSCRIPTION
        error_detail:
          type: string
          description: Details of the error, if any.
          example: Error in transcription
        session_id:
          type: string
          description: Id of the session that failed.
          example: 20965414-929a-4f71-a3e5-b92bec07d086
        status:
          type: string
          example: failure
      description: Webhook payload Suki sends when session processing fails.
    controllers.BadRequestError:
      type: object
      properties:
        code:
          type: integer
          example: 400
          description: HTTP status code for the error.
        message:
          type: string
          example: invalid request
          description: Human-readable description of the validation or request error.
      description: Error response when the request fails validation.
    controllers.AuthenticationError:
      type: object
      properties:
        code:
          type: integer
          example: 401
          description: HTTP status code for the error.
        message:
          type: string
          example: invalid token
          description: Human-readable description of the authentication failure.
      description: Error response when authentication fails.
    controllers.InternalServerError:
      type: object
      properties:
        code:
          type: integer
          example: 500
          description: HTTP status code for the error.
        message:
          type: string
          example: internal server error
          description: Human-readable description of the server error.
      description: Error response when the server encounters an unexpected error.
  securitySchemes:
    SukiTokenAuth:
      type: apiKey
      in: header
      name: sdp_suki_token
      description: >-
        Suki access token for the authenticated provider. Obtain this by calling
        Login or Register with a valid `partner_token`. Pass the `suki_token`
        value from the JSON response as the `sdp_suki_token` header on REST
        requests and non-browser WebSocket upgrades. Browser WebSocket clients
        pass the token in `Sec-WebSocket-Protocol` instead. Tokens expire after
        one hour; call Login again to refresh.

````