{"id":13582414,"url":"https://github.com/grokify/chathooks","last_synced_at":"2026-01-25T22:31:58.093Z","repository":{"id":17394416,"uuid":"79632611","full_name":"grokify/chathooks","owner":"grokify","description":"Service to convert webhook messages to your favorite chat / team messaging format. Run transparently as a formatting webhook proxy.","archived":false,"fork":false,"pushed_at":"2026-01-13T16:32:54.000Z","size":6945,"stargazers_count":42,"open_issues_count":6,"forks_count":10,"subscribers_count":3,"default_branch":"master","last_synced_at":"2026-01-14T15:49:56.800Z","etag":null,"topics":["glip","glip-webhook","go","golang","slack","slack-webhook","webhook"],"latest_commit_sha":null,"homepage":"https://grokify.github.io/chathooks/","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/grokify.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2017-01-21T08:05:37.000Z","updated_at":"2025-12-27T19:14:03.000Z","dependencies_parsed_at":"2023-02-16T09:16:27.773Z","dependency_job_id":"00f20124-aa33-4ecb-b1da-14d3e0611084","html_url":"https://github.com/grokify/chathooks","commit_stats":{"total_commits":577,"total_committers":4,"mean_commits":144.25,"dds":"0.23396880415944543","last_synced_commit":"59e7f50664f8b698008492d960e6d10737470a69"},"previous_names":["grokify/webhookproxy","grokify/glip-webhook-proxy-go","grokify/webhook-proxy-go"],"tags_count":45,"template":false,"template_full_name":null,"purl":"pkg:github/grokify/chathooks","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grokify%2Fchathooks","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grokify%2Fchathooks/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grokify%2Fchathooks/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grokify%2Fchathooks/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/grokify","download_url":"https://codeload.github.com/grokify/chathooks/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grokify%2Fchathooks/sbom","scorecard":{"id":326103,"data":{"date":"2025-08-11","repo":{"name":"github.com/grokify/chathooks","commit":"49e30aaea98f323e14c0d1594a49276ae66a956c"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":4.4,"checks":[{"name":"Code-Review","score":0,"reason":"Found 0/3 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":10,"reason":"26 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/ci.yaml:1","Warn: no topLevel permission defined: .github/workflows/lint.yaml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yaml:20: update your workflow using https://app.stepsecurity.io/secureworkflow/grokify/chathooks/ci.yaml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yaml:24: update your workflow using https://app.stepsecurity.io/secureworkflow/grokify/chathooks/ci.yaml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/lint.yaml:13: update your workflow using https://app.stepsecurity.io/secureworkflow/grokify/chathooks/lint.yaml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/lint.yaml:15: update your workflow using https://app.stepsecurity.io/secureworkflow/grokify/chathooks/lint.yaml/master?enable=pin","Warn: containerImage not pinned by hash: Dockerfile:1","Warn: containerImage not pinned by hash: Dockerfile:14: pin your Docker image by updating heroku/heroku:16 to heroku/heroku:16@sha256:6e4edac1ff75e0743b3ca5e57a185af9661647ec755a10bc19b4d8b0a1055f15","Info:   0 out of   3 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   1 third-party GitHubAction dependencies pinned","Info:   0 out of   2 containerImage dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 27 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-18T02:31:05.652Z","repository_id":17394416,"created_at":"2025-08-18T02:31:05.653Z","updated_at":"2025-08-18T02:31:05.653Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28760646,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-25T20:56:06.009Z","status":"ssl_error","status_checked_at":"2026-01-25T20:54:48.203Z","response_time":113,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["glip","glip-webhook","go","golang","slack","slack-webhook","webhook"],"created_at":"2024-08-01T15:02:41.698Z","updated_at":"2026-01-25T22:31:58.076Z","avatar_url":"https://github.com/grokify.png","language":"Go","funding_links":[],"categories":["Go"],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n# Chathooks\n\n[![](docs/logos/logo_chathooks_long_600x150.png \"\")](https://github.com/grokify/chathooks)\n\nA webhook formatter for chat\n\n[![Build Status][build-status-svg]][build-status-url]\n[![Lint Status][lint-status-svg]][lint-status-url]\n[![Go Report Card][goreport-svg]][goreport-url]\n[![Docs][docs-godoc-svg]][docs-godoc-url]\n[![License][license-svg]][license-url]\n[![Heroku][heroku-svg]][heroku-url]\n\n\u003c/div\u003e\n\n## Overview\n\nChathooks is a webhook proxy service that converts generic outbound webhook messages to a canonical [CommonChat](https://github.com/commonchat) message format which is then sent to any chat / team messaging platform supported by the [CommonChat](https://github.com/grokify/commonchat) chat post abstraction library.\n\nThis is useful because:\n\n* many services with outbound webhooks need to be formatted before they can be consumed by an inbound webhook. This proxy service does the conversion so you don't have to. The code is all open source so customizations can be done easily.\n* the conversion can be done one time for all chat / team messaging solutions supported by CommonChat.\n* one service can proxy an arbitrary number of webhook sources and event types so you don't have to configure multiple inbound webhooks going to the same group / channel.\n\nSee the following video to get started quickly:\n\n* [Getting Started YouTube Video](https://youtu.be/H9nbsOmqrI8)\n\n### Supported HTTP Engines\n\nChathooks supports multiple HTTP engines including the following:\n\n* [net/http](https://golang.org/pkg/net/http/)\n* [valyala/fasthttp](https://github.com/valyala/fasthttp)\n* [aws/aws-lambda-go](https://github.com/aws/aws-lambda-go)\n\n### Supported Webhook Formats\n\nMultiple input webhook formats are supported via handlers. New ones can be easily created by using the `handlers.Handler` interface.\n\n1. [Aha!](https://support.aha.io/hc/en-us/articles/202000997-Integrate-with-Webhooks)\n1. [AppSignal](http://docs.appsignal.com/application/integrations/webhooks.html)\n1. [Apteligent/Crittercism]()\n1. [Bugsnag](https://docs.bugsnag.com/product/integrations/webhook/)\n1. [Circle CI](https://circleci.com/docs/1.0/configuration/#notify)\n1. [Codeship](https://documentation.codeship.com/basic/getting-started/webhooks/)\n1. [Confluence](https://developer.atlassian.com/static/connect/docs/beta/modules/common/webhook.html)\n1. [Datadog](http://docs.datadoghq.com/integrations/webhooks/)\n1. [Desk.com](https://support.desk.com/customer/portal/articles/869334-configuring-webhooks-in-desk-com-apps)\n1. [Enchant](https://dev.enchant.com/webhooks)\n1. [GoSquared](https://www.gosquared.com/customer/portal/articles/1996494-webhooks)\n1. [Heroku](https://devcenter.heroku.com/articles/deploy-hooks#http-post-hook)\n1. [Librato](https://www.librato.com/docs/kb/alert/service_integrations/webhook/)\n1. [Magnum CI](https://github.com/magnumci/documentation/blob/master/webhooks.md)\n1. [Marketo](http://developers.marketo.com/webhooks/)\n1. [Nixstats](https://help.nixstats.com/en/article/nixstats-slack-integration-outgoing-webhook-oui1lg/) (Slack webhook proxy)\n1. [OpsGenie](https://docs.opsgenie.com/docs/webhook-integration)\n1. [Papertrail](http://help.papertrailapp.com/kb/how-it-works/web-hooks/)\n1. [Pingdom](https://www.pingdom.com/resources/webhooks)\n1. [Raygun](https://raygun.com/docs/integrations/webhooks)\n1. [Runscope](https://www.runscope.com/docs/api-testing/notifications#webhook)\n1. [Semaphore CI](https://semaphoreci.com/docs/post-build-webhooks.html), [Deploy](https://semaphoreci.com/docs/post-deploy-webhooks.html)\n1. [StatusPage](https://help.statuspage.io/knowledge_base/topics/webhook-notifications)\n1. [Travis CI](https://docs.travis-ci.com/user/notifications#Configuring-webhook-notifications)\n1. [Userlike](https://www.userlike.com/en/public/tutorial/addon/api)\n1. [VictorOps](https://help.victorops.com/knowledge-base/custom-outbound-webhooks/)\n\nHere is an exmaple Webhook Message from Travis CI formatted for Glip.\n\n![](src/handlers/travisci/travisci_glip.png)\n\nThe above are \"outbound\" webhook formats from the perspective of the service providing the events.\n\nA special webhook format supported is the Slack \"inbound\" webhook format. This format message isn't sent by Slack but is accepted by Slack. It is useful to allow modification of messages already formatted for Slack.\n\n* [Slack](https://api.slack.com/incoming-webhooks)\n\n### Supported Chat Services\n\nChathooks can post messages to any service supported by [CommonChat](https://github.com/grokify/commonchat). New services can be added by creating an adapter using the `commonchat.Adapter` interface.\n\nNote: The emoji to URL is designed to take a `icon_emoji` value and convert it to a URL. `EmojiURLFormat` is a [`fmt`](https://golang.org/pkg/fmt/) `format` string with one `%s` verb to represent the emoji string without `:`. You can use any emoji image service. The example shows the emoji set from [github.com/wpeterson/emoji](https://github.com/wpeterson/emoji) forked and hosted at [grokify.github.io/emoji/](https://grokify.github.io/emoji/).\n\n## Installation\n\n### Local\n\n```\n$ go get github.com/grokify/chathooks\n```\n\n### Heroku\n\n[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy)\n\nor\n\n```sh\n$ heroku create\n$ git push heroku master\n$ heroku open\n```\n\n### AWS Lambda\n\nThe following will generate a `main.zip` file to upload to AWS Lambda.\n\n```\n$ go get github.com/grokify/chathooks\n$ cd chathooks\n$ sh aws-package.sh\n$ ls main.zip\n```\n\n## Configuration\n\n### Environment Variables\n\nChathooks uses two environment variables:\n\n| Variable Name | Value |\n|---------------|-------|\n| `CHATHOOKS_ENGINE` | The engine to be used: `awslambda` for `aws/aws-lambda-go`, `nethttp` for `net/http` and `fasthttp` for `valyala/fasthttp`. Leave empty for `eawsy/aws-lambda-go-shim` as it does not require a server to be started. |\n| `CHATHOOKS_TOKENS` | Comma-delimited list of verification tokens. No extra leading or trailing spaces. |\n\n### Using the `net/http` and `fasthttp` Engines\n\n1. To adjust supported handlers, edit server.go to add and remove handlers.\n1. Set the `CHATHOOKS_ENGINE` environment variable to `nethttp` or `fasthttp`.\n1. Start the service in `main.go`.\n\nFor testing purposes, use:\n\n```bash\n$ go run main.go\n```\n\nFor production services, compile and run the binary:\n\n```bash\n$ go build main.go\n$ ./main\n```\n\n### Using the AWS Engine\n\nTo use the AWS Lambda engine, you need an AWS account. If you don't hae one, the [free trial account](https://aws.amazon.com/s/dm/optimization/server-side-test/free-tier/free_np/) includes 1 million free Lambda requests per month forever and 1 million free API Gateway requests per month for the first year.\n\n#### Installing using the AWS Lambda UI\n\n#### Installation via AWS Lambda\n\nSee the AWS docs for deployment:\n\nhttps://docs.aws.amazon.com/lambda/latest/dg/lambda-go-how-to-create-deployment-package.html\n\nUsing the [`aws-cli`](https://aws.amazon.com/cli/) you can use the following approach:\n\n```\n$ GOOS=linux go build main.go\n$ zip main.zip ./main\n# --handler is the path to the executable inside the .zip\n$ aws lambda create-function \\\n  --region region \\\n  --function-name Chathook \\\n  --memory 128 \\\n  --role arn:aws:iam::account-id:role/execution_role \\\n  --runtime go1.x \\\n  --zip-file fileb://main.zip \\\n  --handler main\n```\n\nYou can use the `aws-package.sh` shell script to package your handler.\n\nNote: you can install the `aws-cli` using the appropriate command below:\n\n```\n$ pip install awscli\n$ pip3 install awscli\n```\n\nAfter installation, you may need to add your Python `bin` directory to your path. The following are examples for OS X.\n\n```\n$ export PATH=$PATH:/Users/~/Library/Python/2.7/bin\n$ export PATH=$PATH:/Library/Frameworks/Python.framework/Versions/3.6/bin\n```\n\n#### Update Lambda Code:\n\nYou can update the Lambda function code using the following:\n\nhttps://docs.aws.amazon.com/cli/latest/reference/lambda/update-function-code.html\n\n`$ aws lambda update-function-code --function-name='MyFunction' --zip-file='fileb://main.zip' --publish --region='us-east-1'`\n\nThe `aws-update.sh` file has this command with default settings.\n\nMake sure to set your AWS credentials file.\n\n#### Manual Setup\n\n* Configure AWS Lambda Function\n  1. Create AWS Lambda function\n  2. Set `CHATHOOKS_ENGINE` to `awslambda`\n  3. Set `CHATHOOKS_TOKEN` as desired\n  4. Set Handler to `main`\n* Configure API Gateway\n  1. Create \"REST\" API\n  2. Select \"New API\"\n  1. Enter \"API name\"\n  1. Click \"Create API\"\n  3. Select \"Actions\" \u003e \"Create Resource\" on \"/\"\n  4. Click \"Configure as proxy resource\"\n  5. Use Resource Path `{proxy+}`\n  6. Click \"Enable API Gateway CORS\"\n  7. Click \"Create Resource\"\n  8. Leave \"Integration Type\" as \"Lambda Function Proxy\"\n  8. In \"Lambda Function\", paste in your Lamda ARN\n  9. Click \"Save\"\n  10. Click \"Actions\" \u003e \"Deploy API\" and create stage if necessary.\n  11. Copy \"Invoke URL\" which should end in `{stageName}`\n\n#### Troubleshooting\n\n* 401 Unauthorized Error: If you can run a test on API Gateway and have deployed your API but are running into a HTTP Status 401 Unauthorized error, check to see if you have configured the `CHATHOOKS_TOKEN` environment variable but not entered a `token` query string parameter.\n\n## Usage\n\n### Creating the Glip Webhook\n\n1. create a Glip webhook\n2. use webhook URL's GUID to create the proxy URL as shown below\n3. use the proxy URL in your outbound webhook service\n\n| Query Parameter | Required? | URL |\n|-----------------|-----------|-----|\n| `inputType` | required | An handler service like `marketo` |\n| `outputType` | required | An adapter service like `glip` |\n| `outputURL` | required | A webhook URL or UID, e.g. `11112222-3333-4444-5555-666677778888` |\n| `outputFormat` | optional | one of [`nocard`,`card`] |\n| `token` | optional | Must be included if service is configured to use auth tokens |\n\nThe webhook proxy URLs support both inbound and outbound formats. When available, these should be represented in the handler key.\n\nTo create the Glip webhook and receive a webhook URL do the following:\n\n#### Add the Webhook Integration\n\nAt the top of any conversation page, click the Settings gear icon and then click `Add Integration`.\n\n![](docs/images/glip_webhook_step-1_add-integration.png)\n\nSelect the `Glip Webhooks` integration.\n\n![](docs/images/glip_webhook_step-2_add-webhook.png)\n\n#### Get the Webhook URL\n\nOnce you get the URL, the proxy URL is created by appending the GUID (e.g. `1112222-3333-4444-5555-666677778888`) to the proxy URL base, `hooks?inputType=slack\u0026outputType=glip` (e.g. `https://glip-proxy.example.com/hooks?inputType=slack\u0026outputType=glip\u0026url=1112222-3333-4444-5555-666677778888`). Use the proxy URL in the app that is posting the Slack webhook and the payload will be sent to Glip.\n\n![](docs/images/glip_webhook_step-3_details.png)\n\n## Development\n\n### Testing new handlers\n\nIt's easy to test handlers by sending messages using the example messages per service.\n\nCode is provided to both send the message locally (without HTTP) and over HTTP.\n\n* [`local_send.go` without HTTP](https://github.com/grokify/chathooks/tree/master/examples/local_send)\n* [`proxy_send.go` over HTTP](https://github.com/grokify/chathooks/tree/master/examples/proxy_send)\n\n#### cURL\n\nThe following is an example curl command that can be used with any host, local or remote.\n\n`curl -XPOST 'https://example.com/webhook?inputType=datadog\u0026outputType=glip\u0026url=https://hooks.glip.com/webhook/11111111-2222-3333-4444-555566667777' --data \"@docs/handlers/datadog/event-example_formatted1.json\" -H 'Content-Type: application/json' --verbose`\n\n### Adding Handlers\n\nThe easiest way to add a handler is to inspect the code of an existing handler and build something similar. It needs satisfy the `handlers.Handler` interface.\n\n## Notes\n\n### Maintenance\n\nUse [`godep`](https://github.com/tools/godep) to rebuild the `vendor` directory with:\n\n```\n$ rm -rf Godeps\n$ export GO15VENDOREXPERIMENT=1\n$ godep save ./...\n```\n\nMore information on deploying Go on Heroku here:\n\n* https://devcenter.heroku.com/articles/go-support\n\n#### Heroku\n\nSet up your own Go app on Heroku easily using [`goheroku`](https://github.com/grokify/goheroku).\n\n\n## Credits\n\nChathooks is built using:\n\n* [net/http](https://golang.org/pkg/net/http/)\n* [valyala/fasthttp](https://github.com/valyala/fasthttp)\n* [aws/aws-lambda-go](https://github.com/aws/aws-lambda-go)\n\n* [buaazp/fasthttprouter](https://github.com/buaazp/fasthttprouter)\n* [rs/zerolog](https://github.com/rs/zerolog)\n\n [build-status-svg]: https://github.com/grokify/chathooks/actions/workflows/ci.yaml/badge.svg?branch=master\n [build-status-url]: https://github.com/grokify/chathooks/actions/workflows/ci.yaml\n [lint-status-svg]: https://github.com/grokify/chathooks/actions/workflows/lint.yaml/badge.svg?branch=master\n [lint-status-url]: https://github.com/grokify/chathooks/actions/workflows/lint.yaml\n [coverage-status-svg]: https://coveralls.io/repos/grokify/chathooks/badge.svg?branch=master\n [coverage-status-url]: https://coveralls.io/r/grokify/chathooks?branch=master\n [goreport-svg]: https://goreportcard.com/badge/github.com/grokify/chathooks\n [goreport-url]: https://goreportcard.com/report/github.com/grokify/chathooks\n [codeclimate-status-svg]: https://codeclimate.com/github/grokify/chathooks/badges/gpa.svg\n [codeclimate-status-url]: https://codeclimate.com/github/grokify/chathooks\n [docs-godoc-svg]: https://pkg.go.dev/badge/github.com/grokify/chathooks\n [docs-godoc-url]: https://pkg.go.dev/github.com/grokify/chathooks\n [loc-svg]: https://tokei.rs/b1/github/grokify/chathooks\n [repo-url]: https://github.com/grokify/chathooks\n [license-svg]: https://img.shields.io/badge/license-MIT-blue.svg\n [license-url]: https://github.com/grokify/chathooks/blob/master/LICENSE\n [heroku-svg]: https://img.shields.io/badge/%E2%86%91_deploy-Heroku-7056bf.svg?style=flat\n [heroku-url]: https://heroku.com/deploy\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgrokify%2Fchathooks","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgrokify%2Fchathooks","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgrokify%2Fchathooks/lists"}