One controller action — signed articles arrive ready to save.
Rails renders the blog; DraftSEO delivers the posts. The recipe is a controller action with a route in routes.rb — request.raw_post gives you the exact body, and you skip_before_action :verify_authenticity_token since an external POST carries no CSRF token. ActiveSupport::SecurityUtils.secure_compare verifies before you create the record.
| Connection | A controller action — routes.rb, CSRF token skipped, recipe provided |
|---|---|
| Security | HMAC-signed + timestamped — secure_compare over ${timestamp}.${raw_post}, replay-window protected |
| Payload | Full article JSON — title, HTML, images, meta, slug, language |
| Images | DraftSEO CDN URLs — URLs ride in the payload; rehost to your own storage if you prefer |
| Framework fit | Turbo / Hotwire friendly — it is just a controller; render posts however your app does |
Who does what
Add the controller action and route, skip the CSRF check, verify the HMAC over request.raw_post, then Post.create the record. After the green test, nothing per article.
Your migrations, Active Record and views stay yours.
Setup
Connect a site → Ruby on Rails. You get a signing secret and the controller recipe.
~1 minute
Register the POST route in routes.rb, skip the CSRF check, verify the signature and save the record — the recipe shows it all.
~10 minutes
DraftSEO sends a signed test event; a green check confirms the connection.
~1 minute
Every generated article is delivered to your controller action on cadence.
Ongoing · zero clicks
FAQ
A JSON body { event, deliveryId, data } — data holds the title, HTML article, slug, language, meta fields and image URLs, ready to map onto an Active Record model.
Each request is HMAC-signed over ${timestamp}.${raw_post} with a timestamp header; you recompute it with OpenSSL::HMAC and compare using ActiveSupport::SecurityUtils.secure_compare, rejecting anything past the 5-minute window. Skip verify_authenticity_token — the HMAC is the auth.
Completely — the receiver is just a controller action that writes a record. How you render the post (Turbo Streams, a normal view, an API) is entirely up to your app; the webhook does not touch the view layer.
No card required. Signed test delivery in under a minute.