> ## 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.

# Form Filling Asynchronous Notifications

> Webhook endpoint for receiving asynchronous notifications when Form filling session processing completes

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 **Form filling** <Tooltip tip="A single, time-bound instance of a Form filling visit used to capture conversation and generate structured medical form output." cta="View in Glossary" href="/Glossary/s">session</Tooltip> completion or failure.

<Note>
  Host this endpoint on your server. Suki sends a POST when Form filling processing completes or fails. The payload `session_id` is the Form filling session ID from [Create Form Filling session](/form-filling-api-reference/form-filling-sessions/create).
</Note>

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

## 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 for Form filling session notifications.
        Verify X-API-Key and generated-at before parsing JSON; see Signature verification guide.
        """
        # TODO: verify webhook signature (see /documentation/webhook/signature-verification)
        data = request.get_json()

        if not data:
            return jsonify({"error": "Invalid request"}), 400

        status = data.get("status")

        if status == "success":
            session_id = data.get("session_id")
            encounter_id = data.get("encounter_id")
            print(f"Form filling session {session_id} completed (encounter {encounter_id})")

            links = data.get("_links") or {}
            for link in links.get("structured_data") or []:
                print(f"  Structured data: {link.get('method')} {link.get('href')}")
            for link in links.get("status") or []:
                print(f"  Status: {link.get('method')} {link.get('href')}")

            return jsonify({"message": "Notification received"}), 200

        if status == "failure":
            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"Form filling session {session_id} failed (encounter {encounter_id}): "
                f"{error_code} - {error_detail}"
            )
            return jsonify({"message": "Failure notification received"}), 200

        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) => {
      // TODO: verify webhook signature (see /documentation/webhook/signature-verification)
      const data = req.body;

      if (!data) {
        return res.status(400).json({ error: 'Invalid request' });
      }

      const status = data.status;

      if (status === 'success') {
        const sessionId = data.session_id;
        const encounterId = data.encounter_id;
        console.log(`Form filling session ${sessionId} completed (encounter ${encounterId})`);

        const links = data._links ?? {};
        (links.structured_data ?? []).forEach((link: { method?: string; href?: string }) => {
          console.log(`  Structured data: ${link.method} ${link.href}`);
        });
        (links.status ?? []).forEach((link: { method?: string; href?: string }) => {
          console.log(`  Status: ${link.method} ${link.href}`);
        });

        return res.status(200).json({ message: 'Notification received' });
      }

      if (status === 'failure') {
        console.log(
          `Form filling session ${data.session_id} failed (encounter ${data.encounter_id}): ` +
            `${data.error_code} - ${data.error_detail}`,
        );
        return res.status(200).json({ message: 'Failure notification received' });
      }

      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.

````