<commit_before>---
!include ../includes.yaml
name: webhook
comment: |
  **Webhooks are currently in BETA - The information here may change.**

  Webhooks allow an application to be notified of changes. This is in addition
  to the ability to fetch those changes directly as
  [Events](/developers/api-reference/events) - in fact, Webhooks are just a way
  to receive Events via HTTP POST at the time they occur instead of polling for
  them. For services accessible via HTTP this is often vastly more convenient,
  and if events are not too frequent can be significantly more efficient.

  In both cases, however, changes are represented as Event objects - refer to
  the [Events documentation](/developers/api-reference/events) for more
  information on what data these events contain.

  **NOTE:** While Webhooks send arrays of Event objects to their target, the
  Event objects themselves contain *only IDs*, rather than the actual resource
  they are referencing. So while a normal event you receive via GET /events
  would look like this:

      {\
        "resource": {\
          "id": 1337,\
          "name": "<NAME>"\
        },\
        "parent": null,\
        "created_at": "2013-08-21T18:20:37.972Z",\
        "user": {\
          "id": 1123,\
          "name": "<NAME>"\
        },\
        "action": "changed",\
        "type": "task"\
      }

  In a Webhook payload you would instead receive this:

      {\
        "resource": 1337,\
        "parent": null,\
        "created_at": "2013-08-21T18:20:37.972Z",\
        "user": 1123,\
        "action": "changed",\
        "type": "task"\
      }

  Webhooks themselves contain only the information necessary to deliver the
  events to the desired target as they are generated.
properties:

  - name: id
    <<: *PropType.Id
    comment: |
      Globally unique ID of the webhook.

  - name: resource
    <<: *PropType.Task
    access: Read-only
    comment: |
      The resource the webhook is subscribed to.

  - name: target
    <<: *PropType.Target
    access: Read-only
    comment: |
      The URL to receive the HTTP POST.

  - name: active
    <<: *PropType.Bool
    comment: |
      If true, the webhook will send events - if false it is considered
      inactive and will not generate events.

  - name: created_at
    <<: *PropType.DateTime
    access: Read-only
    comment: |
      The timestamp when the webhook was created.

  - name: last_success_at
    <<: *PropType.DateTime
    access: Read-only
    comment: |
      The timestamp when the webhook last successfully sent an event to the
      target.

  - name: last_failure_at
    <<: *PropType.DateTime
    access: Read-only
    comment: |
      The timestamp when the webhook last received an error when sending an
      event to the target.

  - name: last_failure_content
    <<: *PropType.FailureContent
    access: Read-only
    comment: |
      The contents of the last error response sent to the webhook when
      attempting to deliver events to the target.

action_classes:
  - name: Create a webhook
    url: create
  - name: Get webhooks
    url: get
  - name: Get webhook
    url: get-single
  - name: Receiving webhook events
    url: receive
    comment: |
      Because multiple events often happen in short succession, a webhook
      payload is designed to be able to transmit multiple events at once. The
      exact model of events is described in the
      [Events documentation](/developers/api-reference/events).

      The HTTP POST that the target receives contains:

       * An `X-Hook-Signature` header, which allows verifying that the payload
      is genuine.  The signature is a SHA256 HMAC using the shared secret
      (transmitted during the handshake) of the request body. Verification is
      **strongly recommended**, as it would otherwise be possible for an
      attacker to POST a malicious payload to the same endpoint. If the target
      endpoint can be kept secret this risk is mitigated somewhat, of course.\
       * A JSON body with a single key, `events`, containing an array of the
      events that have occurred since the last webhook delivery. Note that this
      list may be empty, as periodically we may send a "heartbeat" webhook to
      verify that the endpoint is available.

      Note that events are "skinny" - we expect consumers who desire syncing
      data to make additional calls to the API to retrieve the latest state.
      Because the data may have already changed by the time we send the event,
      it would be misleading to send a snapshot of the data along with the
      event.

      **Example**

          # Request to your server\
          POST /receive-webhook/7654\
          X-Hook-Signature: 1d6207f8818f063890758a32d3833914754ba788cb8993e644701bac7257f59e

          {\
            "events": [\
              {\
                "action": "changed",\
                "created_at": "2013-08-21T18:20:37.972Z",\
                "parent": null,\
                "resource": 1337,\
                "type": "task",\
                "user": 1123\
              },\
              {\
                "action": "changed",\
                "created_at": "2013-08-21T18:22:45.421Z",\
                "parent": null,\
                "resource": 1338,\
                "type": "task",\
                "user": 1428\
              }\
            ]\
          }

  - name: Error handling and retry
    url: retry
    comment: |
      If we attempt to send a webhook payload and we receive an error status
      code, or the request times out, we will retry delivery with exponential
      backoff. In general, if your servers are not available for an hour, you
      can expect it to take no longer than approximately an hour after they
      come back before the paused delivery resumes. However, if we are unable
      to deliver a message for 24 hours the webhook will be deactivated.
  - name: Delete a webhook
    url: delete
actions:

  - name: create
    class: create
    method: POST
    path: "/webhooks"
    params:
      - name: resource
        <<: *Param.Id
        required: true
        explicit: true
        comment: |
          A resource ID to subscribe to. The resource can be a task or project.
      - name: target
        <<: *Param.Target
        required: true
        explicit: true
        comment: |
          The URL to receive the HTTP POST.
    comment: |
      Establishing a webhook is a two-part process. First, a simple HTTP POST
      similar to any other resource creation. Since you could have multiple
      webhooks we recommend specifying a unique local id for each target.

      Next comes the confirmation handshake. When a webhook is created, we will
      send a test POST to the `target` with an `X-Hook-Secret` header as
      described in the
      [Resthooks Security documentation](http://resthooks.org/docs/security/).
      The target must respond with a `200 OK` and a matching `X-Hook-Secret`
      header to confirm that this webhook subscription is indeed expected.

      If you do not acknowledge the webhook's confirmation handshake it will
      fail to setup, and you will receive an error in response to your attempt
      to create it. This means you need to be able to receive and complete the
      webhook *while* the POST request is in-flight.
    footer: |
      **Example**

          # Request\
          curl -H "Authorization: Bearer <personal_access_token>" \\
          -X POST https://app.asana.com/api/1.0/webhooks \\
          -d "resource=8675309" \\
          -d "target=https://example.com/receive-webhook/7654"

          # Handshake sent to https://example.com/\
          POST /receive-webhook/7654\
          X-Hook-Secret: <KEY>

          # Handshake response sent by example.com\
          HTTP/1.1 200\
          X-Hook-Secret: <KEY>

          # Response\
          HTTP/1.1 201\
          {\
            "data": {\
              "id": 43214,\
              "resource": {\
                "id": 8675309,\
                "name": "Bugs"\
              },\
              "target": "https://example.com/receive-webhook/7654",\
              "active": false,\
              "last_success_at": null,\
              "last_failure_at": null,\
              "last_failure_content": null\
            }\
          }
  - name: getAll
    class: get
    method: GET
    path: "/webhooks"
    collection: true
    params:
      - name: workspace
        <<: *Param.WorkspaceId
        required: true
        explicit: true
        comment: |
          The workspace to query for webhooks in.
      - name: resource
        <<: *Param.Id
        comment: |
          Only return webhooks for the given resource.
    comment: |
      Returns the compact representation of all webhooks your app has
      registered for the authenticated user in the given workspace.
  - name: getById
    class: get-single
    method: GET
    path: "/webhooks/%s"
    params:
      - name: webhook
        <<: *Param.Id
        required: true
        explicit: true
        comment: |
          The webhook to get.
    comment: |
      Returns the full record for the given webhook.
  - name: deleteById
    class: delete
    method: DELETE
    path: "/webhooks/%s"
    params:
      - name: webhook
        <<: *Param.Id
        required: true
        explicit: true
        comment: |
          The webhook to delete.
    comment: |
      This method permanently removes a webhook. Note that it may be possible
      to receive a request that was already in flight after deleting the
      webhook, but no further requests will be issued.
<commit_msg>Remove beta label from webhooks<commit_after>---
!include ../includes.yaml
name: webhook
comment: |
  Webhooks allow an application to be notified of changes. This is in addition
  to the ability to fetch those changes directly as
  [Events](/developers/api-reference/events) - in fact, Webhooks are just a way
  to receive Events via HTTP POST at the time they occur instead of polling for
  them. For services accessible via HTTP this is often vastly more convenient,
  and if events are not too frequent can be significantly more efficient.

  In both cases, however, changes are represented as Event objects - refer to
  the [Events documentation](/developers/api-reference/events) for more
  information on what data these events contain.

  **NOTE:** While Webhooks send arrays of Event objects to their target, the
  Event objects themselves contain *only IDs*, rather than the actual resource
  they are referencing. So while a normal event you receive via GET /events
  would look like this:

      {\
        "resource": {\
          "id": 1337,\
          "name": "My Task"\
        },\
        "parent": null,\
        "created_at": "2013-08-21T18:20:37.972Z",\
        "user": {\
          "id": 1123,\
          "name": "<NAME>"\
        },\
        "action": "changed",\
        "type": "task"\
      }

  In a Webhook payload you would instead receive this:

      {\
        "resource": 1337,\
        "parent": null,\
        "created_at": "2013-08-21T18:20:37.972Z",\
        "user": 1123,\
        "action": "changed",\
        "type": "task"\
      }

  Webhooks themselves contain only the information necessary to deliver the
  events to the desired target as they are generated.
properties:

  - name: id
    <<: *PropType.Id
    comment: |
      Globally unique ID of the webhook.

  - name: resource
    <<: *PropType.Task
    access: Read-only
    comment: |
      The resource the webhook is subscribed to.

  - name: target
    <<: *PropType.Target
    access: Read-only
    comment: |
      The URL to receive the HTTP POST.

  - name: active
    <<: *PropType.Bool
    comment: |
      If true, the webhook will send events - if false it is considered
      inactive and will not generate events.

  - name: created_at
    <<: *PropType.DateTime
    access: Read-only
    comment: |
      The timestamp when the webhook was created.

  - name: last_success_at
    <<: *PropType.DateTime
    access: Read-only
    comment: |
      The timestamp when the webhook last successfully sent an event to the
      target.

  - name: last_failure_at
    <<: *PropType.DateTime
    access: Read-only
    comment: |
      The timestamp when the webhook last received an error when sending an
      event to the target.

  - name: last_failure_content
    <<: *PropType.FailureContent
    access: Read-only
    comment: |
      The contents of the last error response sent to the webhook when
      attempting to deliver events to the target.

action_classes:
  - name: Create a webhook
    url: create
  - name: Get webhooks
    url: get
  - name: Get webhook
    url: get-single
  - name: Receiving webhook events
    url: receive
    comment: |
      Because multiple events often happen in short succession, a webhook
      payload is designed to be able to transmit multiple events at once. The
      exact model of events is described in the
      [Events documentation](/developers/api-reference/events).

      The HTTP POST that the target receives contains:

       * An `X-Hook-Signature` header, which allows verifying that the payload
      is genuine.  The signature is a SHA256 HMAC using the shared secret
      (transmitted during the handshake) of the request body. Verification is
      **strongly recommended**, as it would otherwise be possible for an
      attacker to POST a malicious payload to the same endpoint. If the target
      endpoint can be kept secret this risk is mitigated somewhat, of course.\
       * A JSON body with a single key, `events`, containing an array of the
      events that have occurred since the last webhook delivery. Note that this
      list may be empty, as periodically we may send a "heartbeat" webhook to
      verify that the endpoint is available.

      Note that events are "skinny" - we expect consumers who desire syncing
      data to make additional calls to the API to retrieve the latest state.
      Because the data may have already changed by the time we send the event,
      it would be misleading to send a snapshot of the data along with the
      event.

      **Example**

          # Request to your server\
          POST /receive-webhook/7654\
          X-Hook-Signature: 1d6207f8818f063890758a32d3833914754ba788cb8993e644701bac7257f59e

          {\
            "events": [\
              {\
                "action": "changed",\
                "created_at": "2013-08-21T18:20:37.972Z",\
                "parent": null,\
                "resource": 1337,\
                "type": "task",\
                "user": 1123\
              },\
              {\
                "action": "changed",\
                "created_at": "2013-08-21T18:22:45.421Z",\
                "parent": null,\
                "resource": 1338,\
                "type": "task",\
                "user": 1428\
              }\
            ]\
          }

  - name: Error handling and retry
    url: retry
    comment: |
      If we attempt to send a webhook payload and we receive an error status
      code, or the request times out, we will retry delivery with exponential
      backoff. In general, if your servers are not available for an hour, you
      can expect it to take no longer than approximately an hour after they
      come back before the paused delivery resumes. However, if we are unable
      to deliver a message for 24 hours the webhook will be deactivated.
  - name: Delete a webhook
    url: delete
actions:

  - name: create
    class: create
    method: POST
    path: "/webhooks"
    params:
      - name: resource
        <<: *Param.Id
        required: true
        explicit: true
        comment: |
          A resource ID to subscribe to. The resource can be a task or project.
      - name: target
        <<: *Param.Target
        required: true
        explicit: true
        comment: |
          The URL to receive the HTTP POST.
    comment: |
      Establishing a webhook is a two-part process. First, a simple HTTP POST
      similar to any other resource creation. Since you could have multiple
      webhooks we recommend specifying a unique local id for each target.

      Next comes the confirmation handshake. When a webhook is created, we will
      send a test POST to the `target` with an `X-Hook-Secret` header as
      described in the
      [Resthooks Security documentation](http://resthooks.org/docs/security/).
      The target must respond with a `200 OK` and a matching `X-Hook-Secret`
      header to confirm that this webhook subscription is indeed expected.

      If you do not acknowledge the webhook's confirmation handshake it will
      fail to setup, and you will receive an error in response to your attempt
      to create it. This means you need to be able to receive and complete the
      webhook *while* the POST request is in-flight.
    footer: |
      **Example**

          # Request\
          curl -H "Authorization: Bearer <personal_access_token>" \\
          -X POST https://app.asana.com/api/1.0/webhooks \\
          -d "resource=8675309" \\
          -d "target=https://example.com/receive-webhook/7654"

          # Handshake sent to https://example.com/\
          POST /receive-webhook/7654\
          X-Hook-Secret: <KEY>

          # Handshake response sent by example.com\
          HTTP/1.1 200\
          X-Hook-Secret: <KEY>

          # Response\
          HTTP/1.1 201\
          {\
            "data": {\
              "id": 43214,\
              "resource": {\
                "id": 8675309,\
                "name": "Bugs"\
              },\
              "target": "https://example.com/receive-webhook/7654",\
              "active": false,\
              "last_success_at": null,\
              "last_failure_at": null,\
              "last_failure_content": null\
            }\
          }
  - name: getAll
    class: get
    method: GET
    path: "/webhooks"
    collection: true
    params:
      - name: workspace
        <<: *Param.WorkspaceId
        required: true
        explicit: true
        comment: |
          The workspace to query for webhooks in.
      - name: resource
        <<: *Param.Id
        comment: |
          Only return webhooks for the given resource.
    comment: |
      Returns the compact representation of all webhooks your app has
      registered for the authenticated user in the given workspace.
  - name: getById
    class: get-single
    method: GET
    path: "/webhooks/%s"
    params:
      - name: webhook
        <<: *Param.Id
        required: true
        explicit: true
        comment: |
          The webhook to get.
    comment: |
      Returns the full record for the given webhook.
  - name: deleteById
    class: delete
    method: DELETE
    path: "/webhooks/%s"
    params:
      - name: webhook
        <<: *Param.Id
        required: true
        explicit: true
        comment: |
          The webhook to delete.
    comment: |
      This method permanently removes a webhook. Note that it may be possible
      to receive a request that was already in flight after deleting the
      webhook, but no further requests will be issued.

{'fraction_non_alphanumeric': 0.08024176740308461, 'fraction_numerical': 0.0212588578574406, 'mean_word_length': 2.0177672955974844, 'pattern_counts': {'":': 78, '<': 68, '<?xml version=': 0, '>': 12, 'https://': 8, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1331021', 'n_tokens_mistral': 5447, 'n_tokens_neox': 5076, 'n_words': 2139}