{"id":20779124,"url":"https://github.com/solidusio/solidus_webhooks","last_synced_at":"2026-02-17T17:33:21.542Z","repository":{"id":49224390,"uuid":"262330893","full_name":"solidusio/solidus_webhooks","owner":"solidusio","description":"Add support for incoming webhooks to your Solidus store.","archived":false,"fork":false,"pushed_at":"2023-10-05T13:15:37.000Z","size":78,"stargazers_count":7,"open_issues_count":0,"forks_count":2,"subscribers_count":11,"default_branch":"main","last_synced_at":"2026-02-11T06:59:12.611Z","etag":null,"topics":["hacktoberfest","solidus","solidus-extensions"],"latest_commit_sha":null,"homepage":"http://solidus.io","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/solidusio.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"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},"funding":{"open_collective":"solidus"}},"created_at":"2020-05-08T13:29:02.000Z","updated_at":"2025-01-11T08:52:32.000Z","dependencies_parsed_at":"2024-02-03T18:05:01.881Z","dependency_job_id":"5563eafd-4e01-4df1-a538-788aff7d05a8","html_url":"https://github.com/solidusio/solidus_webhooks","commit_stats":null,"previous_names":["solidusio-contrib/solidus_webhooks"],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/solidusio/solidus_webhooks","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/solidusio%2Fsolidus_webhooks","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/solidusio%2Fsolidus_webhooks/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/solidusio%2Fsolidus_webhooks/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/solidusio%2Fsolidus_webhooks/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/solidusio","download_url":"https://codeload.github.com/solidusio/solidus_webhooks/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/solidusio%2Fsolidus_webhooks/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29551257,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-17T14:33:00.708Z","status":"ssl_error","status_checked_at":"2026-02-17T14:32:58.657Z","response_time":100,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: 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":["hacktoberfest","solidus","solidus-extensions"],"created_at":"2024-11-17T13:26:09.129Z","updated_at":"2026-02-17T17:33:21.525Z","avatar_url":"https://github.com/solidusio.png","language":"Ruby","readme":"# Solidus Webhooks\n\n[![CircleCI](https://circleci.com/gh/solidusio/solidus_webhooks.svg?style=shield)](https://circleci.com/gh/solidusio/solidus_webhooks)\n[![codecov](https://codecov.io/gh/solidusio/solidus_webhooks/branch/main/graph/badge.svg)](https://codecov.io/gh/solidusio/solidus_webhooks)\n\n\u003c!-- Explain what your extension does. --\u003e\n\n## Installation\n\nAdd solidus_webhooks to your Gemfile:\n\n```ruby\ngem 'solidus_webhooks'\n```\n\nBundle your dependencies and run the installation generator:\n\n```shell\nbin/rails generate solidus_webhooks:install\n```\n\n## Usage\n\n\u003c!-- Explain how to use your extension once it's been installed. --\u003e\n\nA Webhook receiver is just a callable and can be registered in the Solidus configuration as follows:\n\n```ruby\nSolidusWebhooks.config.register_webhook_handler :tracking_number, -\u003e payload {\n  order = Spree::Order.find_by!(number: payload[:order])\n  shipment = order.shipments.find_by!(number: payload[:shipment])\n  shipment.update!(tracking: payload[:tracking])\n}\n```\n\nThis will enable sending `POST` requests to `/webhooks/tracking-number` with a JSON payload like this:\n\n```json\n{\n  \"order\": \"R1234567890\",\n  \"shipment\": \"S1234567890\",\n  \"tracking\": \"T123-456-789\"\n}\n```\n\n### Handlers requirements\n\nThe only requirement on handlers is for them to respond to `#call` and accept a payload.\n\nExample:\n\n```ruby\nmodule TrackingNumberHandler\n  def self.call(payload)\n    order = Spree::Order.find_by!(number: payload[:order])\n    shipment = order.shipments.find_by!(number: payload[:shipment])\n    shipment.update!(tracking: payload[:tracking])\n  end\nend\n\nSolidusWebhooks.config.register_webhook_handler :tracking_number, TrackingNumberHandler\n```\n\n\n### Making the handler asynchronous\n\nTo make a handler asynchronous just make its implementation internally call your preferred job handler (e.g. ActiveJob). In most cases you'll want to filter, prepare, and validate the payload for the job of your choice, to avoid ingesting and invalid input.\n\nExample:\n\n```ruby\nSolidusWebhooks.config.register_webhook_handler :tracking_number, -\u003e payload {\n  UpdateTrackingNumberJob.perform_later(\n    order: payload.fetch(:order)\n    shipment: payload.fetch(:shipment)\n    tracking: payload.fetch(:tracking)\n  )\n}\n```\n\n\n### Payload routing\n\nIf your handler can receive different kind of payloads the most common technique is to route them to appropriate sub-handlers (that can be an ActiveJob class or a service class).\n\n```ruby\nSolidusWebhooks.config.register_webhook_handler :tracking_number, -\u003e payload {\n  case payload[:tracking]\n  when /^FOO(\\d+-)+/\n    UpdateFooTrackingNumberJob.perform_later(\n      order: payload.fetch(:order)\n      shipment: payload.fetch(:shipment)\n      tracking: payload.fetch(:tracking)\n    )\n  when /^BAR(\\d+-)+/\n    UpdateBarTrackingNumberJob.perform_later(\n      order: payload.fetch(:order)\n      shipment: payload.fetch(:shipment)\n      tracking: payload.fetch(:tracking)\n    )\n  else raise \"unknown tracking service\"\n  end\n}\n```\n\n### Restricting Permissions\n\nIt's good practice not to use admin-user tokens for webhooks, instead you should define a permission set tied to the webhook handler you're providing. Use the standard Solidus permission-sets to do that.\n\nExample:\n\n```ruby\nmodule ReceiveTrackingWebhookPermission \u003c Spree::PermissionSets::Base\n  def activate!\n    can :receive, Spree::Webhook do |webhook|\n      webhook.id == :tracking_number\n    end\n  end\nend\n\nSpree::RoleConfiguration.configure do |config|\n  config.assign_permissions :foo_tracking_service, %w[\n    ReceiveTrackingWebhookPermission\n  ]\nend\n```\n\n### Accessing the API User\n\nIf you need to access the API user that is making the call to the webhook, you can just accept an additional argument in the callable handler.\n\nExample:\n\n```ruby\nSolidusWebhooks.config.register_webhook_handler :tracking_number, -\u003e payload, user {\n  Rails.logger.info \"Received payload from user #{user.email}: #{payload.to_json}\"\n  # …\n}\n```\n\n## Development\n\n### Testing the extension\n\nFirst bundle your dependencies, then run `bin/rake`. `bin/rake` will default to building the dummy\napp if it does not exist, then it will run specs. The dummy app can be regenerated by using\n`bin/rake extension:test_app`.\n\n```shell\nbin/rake\n```\n\nTo run [Rubocop](https://github.com/bbatsov/rubocop) static code analysis run\n\n```shell\nbundle exec rubocop\n```\n\nWhen testing your application's integration with this extension you may use its factories.\nSimply add this require statement to your spec_helper:\n\n```ruby\nrequire 'solidus_webhooks/factories'\n```\n\n### Running the sandbox\n\nTo run this extension in a sandboxed Solidus application, you can run `bin/sandbox`. The path for\nthe sandbox app is `./sandbox` and `bin/rails` will forward any Rails commands to\n`sandbox/bin/rails`.\n\nHere's an example:\n\n```\n$ bin/rails server\n=\u003e Booting Puma\n=\u003e Rails 6.0.2.1 application starting in development\n* Listening on tcp://127.0.0.1:3000\nUse Ctrl-C to stop\n```\n\n### Updating the changelog\n\nBefore and after releases the changelog should be updated to reflect the up-to-date status of\nthe project:\n\n```shell\nbin/rake changelog\ngit add CHANGELOG.md\ngit commit -m \"Update the changelog\"\n```\n\n### Releasing new versions\n\nPlease refer to the dedicated [page](https://github.com/solidusio/solidus/wiki/How-to-release-extensions) on Solidus wiki.\n\n## License\n\nCopyright (c) 2020 Nebulab srls, released under the New BSD License.\n","funding_links":["https://opencollective.com/solidus"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsolidusio%2Fsolidus_webhooks","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsolidusio%2Fsolidus_webhooks","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsolidusio%2Fsolidus_webhooks/lists"}