Inbound webhooks

A Petals webhook URL is a secret address that anything can POST to. Each POST creates a post in your garden. No code, no API keys, no OAuth — the secret is baked into the URL itself.

1. Get your secret URL

Open Settings → Connections and create a webhook URL. It looks like:

https://petals.blog/api/hook/YOUR-SECRET-TOKEN

Treat it like a password — anyone with the URL can post to your garden. Lost it or leaked it? Rotate it; the old URL stops working immediately.

2. What to send

POST JSON or form-encoded data. Every field is optional, but send at least one of title, url, body, or image (an empty payload is rejected). Common aliases are accepted so you rarely have to rename anything:

Post fieldAccepted keys (first match wins)
Titletitle, subject, name, headline
Linkurl, link, permalink, href
Bodybody, content, text, description, message
Imageimage, image_url, thumbnail, thumb, photo
Dateposted_at, date, published, published_at, timestamp, created_at (falls back to now)

HTML in the body is sanitized through the same allowlist as blog posts. Posting the same url twice updates that post instead of duplicating it.

curl (the one-liner)

curl -X POST https://petals.blog/api/hook/YOUR-SECRET-TOKEN \
  -H "Content-Type: application/json" \
  -d '{"title":"Hello","url":"https://example.com/post","body":"Posted from curl."}'

Form-encoded works too:

curl -X POST https://petals.blog/api/hook/YOUR-SECRET-TOKEN \
  -d title="Hello" -d url="https://example.com/post" -d body="Posted from curl."

Zapier

Add a Webhooks by Zapier → POST action. Set URL to your secret URL, Payload Type to json, and map your trigger's fields into title, url, body, image, posted_at.

IFTTT

Use the Webhooks service as the action (Make a web request). Method POST, Content Type application/json, and a body like {"title":"{{Title}}","url":"{{EntryUrl}}","body":"{{EntryContent}}"} using your trigger's ingredients.

Make (Integromat)

Add an HTTP → Make a request module. URL = your secret URL, method POST, body type Raw / JSON, and map fields from earlier modules.

n8n

Add an HTTP Request node. Method POST, your secret URL, Body Content Type JSON, and add parameters title, url, body, etc.

Pipedream

Add an HTTP / Send POST Request action (or a few lines in a Node/Python step) pointing at your secret URL with a JSON body built from steps.trigger.event.

GitHub Actions

Post from a workflow step — e.g. announce a release. Store the secret URL as a repo secret (PETALS_WEBHOOK_URL):

- name: Post to Petals
  run: |
    curl -X POST "$PETALS_WEBHOOK_URL" \
      -H "Content-Type: application/json" \
      -d '{"title":"${{ github.event.repository.name }} ${{ github.ref_name }}","url":"${{ github.event.release.html_url }}","body":"New release published."}'
  env:
    PETALS_WEBHOOK_URL: ${{ secrets.PETALS_WEBHOOK_URL }}

Services that emit webhooks natively

Some tools can POST to a URL directly — point them straight at your secret URL. Their payloads differ, so a thin transform (a Zapier/Make/n8n step) gives the cleanest mapping, but many fields line up out of the box:

Strava

Strava's webhook events carry IDs rather than full activities, so route them through Zapier/Make/n8n (or a tiny relay) to fetch the activity, then POST title + url to your Petals URL.

Discourse

Admin → API → Webhooks → New. Set Payload URL to your secret URL, content type application/json, and subscribe to Post or Topic events. Discourse sends title and post fields that map closely.

GitHub

Repo Settings → Webhooks → Add webhook. Payload URL = your secret URL, content type application/json. Push/release events include a name/html_url; a transform step gives the tidiest result.

Trello

Create a webhook via Trello's API pointed at your secret URL to mirror new cards. Trello's model wraps data under action.data, so a transform step that flattens it to title/url works best.

Ready? Create your webhook URL →