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

# Get the signed PDF for a workflow

> The signed PDF for the workflow: the Compliance File's pdf_signed evidence source.



## OpenAPI

````yaml /api-reference/manuscript/openapi.json get /api/v1/workflows/{Id}/signed-pdf
openapi: 3.0.4
info:
  title: WorkAuthor API
  description: >-
    ## Webhooks


    When your system receives webhook events, for example document or assessment
    updates, your endpoint will receive HTTP POST requests from our platform.  


    These requests are signed using your configured signing keys. You should
    verify the signature to ensure that:

    - The request was sent by us, and  

    - The payload has not been modified in transit.


    ### Signature headers


    Webhook requests may include one or more signature headers.  


    A separate signature header is included for each active signing key. During
    key rotation, this means a request may contain multiple signatures.  


    Example:  

    X-Signature-HMAC-SHA256-1: 0mzEqDMT92/xvUvgMcogqVix12nSH6NRW+A6nEHy/aQ=  

    X-Signature-HMAC-SHA256-2: n9V4Qf3bM1l2aBcD4eFgHiJkLmNoPqRsTuVwXyZ0123=  


    Each header value is the Base64 encoded HMAC-SHA256 digest of the raw
    request body, generated using one of the active signing keys.  


    The numeric suffix (-1, -2, etc.) is an identifier only. It does not map to
    a specific signing key and should not be relied upon.  



    ### How to validate the request


    To verify a webhook request:  

    1. Read the raw request body exactly as received.  

    2. Compute an HMAC-SHA256 digest using each of your active signing keys.  

    3. Base64 encode each digest.  

    4. Compare each computed digest against all X-Signature-HMAC-SHA256-* header
    values.  

    5. Treat the request as valid if any computed digest matches any header
    value.  

    6. Reject the request if no signatures match.  



    ### Important implementation notes


    - Use the raw request body, not a parsed or re-serialised JSON payload.  

    - Do not modify the request body before computing the signature.  

    - Signature values are Base64 encoded and may include padding (=).  

    - More than one signature header may be sent when multiple signing keys are
    active.  

    - Do not assume any relationship between the header suffix and a specific
    signing key.  

    - Compare the computed and supplied signatures using a secure comparison
    method.  

    - Reject requests where no valid signature is present.  


    ### Key rotation


    To support key rotation, multiple signing keys can be active at the same
    time.  

    When this happens:  

    - webhook requests will include multiple signature headers,  

    - each signature is generated using a different active key,  

    - your application should validate the request against all active keys and
    all supplied headers.  



    A request should be accepted if any one valid match is found.  



    ### C# Example


    The following example demonstrates how to validate a single signature. If
    multiple signing keys or signature headers are present, repeat this process
    and accept the request if any signature matches.  



    ```csharp

    public static string ComputeHash(string secret, string payload)

    {
        byte[] bytes = Encoding.UTF8.GetBytes(secret);
        var hmac = new HMACSHA256(bytes);
        bytes = Encoding.UTF8.GetBytes(payload);

        return Convert.ToBase64String(hmac.ComputeHash(bytes));
    }


    public static bool HashIsValid(string secret, string payload, string verify)

    {
        ReadOnlySpan<byte> hashBytes = Convert.FromBase64String(ComputeHash(secret, payload));
        ReadOnlySpan<byte> verifyBytes = Convert.FromBase64String(verify);

        return CryptographicOperations.FixedTimeEquals(hashBytes, verifyBytes);
    }

    ```



    ### Node.js Example

    ```js

    const computeHash = (args) => {
      const hmac = crypto.createHmac('sha256', args.secret);
      hmac.write(args.payload);
      hmac.end();
      return hmac.read().toString('base64');
    };


    const isHashValid = (args) => {
      return crypto.timingSafeEqual(Buffer.from(args.verify, 'base64'), Buffer.from(computeHash(args), 'base64'));
    };

    ```
  version: 1.0.0
servers:
  - url: https://deployed.workauthor.com
    description: Deployed production backend (WorkAuthor). Paths carry /api/v1.
security: []
tags:
  - name: Assessments
  - name: Documents
  - name: Surveys
  - name: Workflows
paths:
  /api/v1/workflows/{Id}/signed-pdf:
    get:
      tags:
        - Workflows
      summary: Get the signed PDF for a workflow
      description: >-
        The signed PDF for the workflow: the Compliance File's pdf_signed
        evidence source.
      operationId: getWorkflowSignedPdf
      parameters:
        - name: Id
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: OK
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Not Found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
components:
  schemas:
    ErrorResponse:
      type: object
      properties:
        type:
          type: string
          nullable: true
        title:
          type: string
          nullable: true
        status:
          type: integer
          format: int32
        errors:
          type: array
          items:
            $ref: '#/components/schemas/ErrorDetail'
          nullable: true
        traceId:
          type: string
          nullable: true
      additionalProperties: false
    ErrorDetail:
      type: object
      properties:
        code:
          type: string
          nullable: true
        description:
          type: string
          nullable: true
        type:
          type: integer
          format: int32
      additionalProperties: false

````