Timothe AI(ティモシーAI)

Effective date: August 5, 2026

Send articles to your own endpoint from Growth Calendar

When your site is not one of the connected CMSs, Growth Calendar can POST each finished article to an address you control. Your receiver decides what to do with it: commit it to a repository, write it into your own database, hand it to a static site generator.

Articles are sent as Markdown, so nothing has to be un-rendered on your side.

There is one setting for the whole workspace, under CMS in the top right of Growth Calendar.

What you need

An endpoint that accepts POST over https, and a secret you invent. The secret is sent with every request so your receiver can tell Growth Calendar apart from anyone who learns the URL.

Connecting

  1. Open CMS in the top right of Growth Calendar and select Webhook.
  2. Enter the full endpoint URL, path included, such as https://example.com/api/articles.
  3. Enter the shared secret and select Connect.

Connecting sends one test request to the address, so the receiver has to be deployed before this step. The test is a POST with this body:

{ "event": "ping" }

Anything that answers 2xx passes. A receiver that ignores the body entirely still connects.

The URL has to use https, cannot include a query string, and cannot use a non-standard port. A trailing slash is removed, so https://example.com/api/articles/ is stored as https://example.com/api/articles. If your framework treats those as different routes, register the one without the slash.

What gets sent

Every article arrives as a POST with these headers:

Authorization: Bearer <your secret>
Content-Type: application/json

And this body:

{
  "event": "article.publish",
  "articleId": "trk_abc:2026-08-05",
  "trackId": "trk_abc",
  "date": "2026-08-05",
  "status": "published",
  "title": "SEO basics",
  "slug": "seo-basics",
  "description": "Where to start with search.",
  "markdown": "# SEO basics\n\nSee [keyword research](https://example.com/blog/keyword-research).",
  "imageUrls": ["https://cdn.timothe.ai/…/a.webp"],
  "url": "https://example.com/blog/seo-basics"
}
FieldWhat it is
eventarticle.publish or article.draft, matching how the article was sent
articleIdStable across re-sends of the same article. Use it as your key
trackIdThe track the article belongs to
dateThe day in the calendar the article was written for
statuspublished or draft
titleThe article title
slugThe URL slug the article was written for
descriptionThe meta description
markdownThe article body, with internal links already resolved
imageUrlsAddresses of the images used in the article
urlWhere the article will live once public. Only present once a public site URL is set

Fields may be added over time. Existing field names will not change or disappear.

What your receiver has to do

Answer 2xx only when you have stored the article. A 2xx is taken as success and the article is marked as sent. If your receiver accepts the request and then fails to save it, Growth Calendar has no way to know.

Treat the same articleId as the same article. Revising an article and sending it again reuses the id, so a receiver that inserts blindly will accumulate duplicates.

Answering with a body is optional. If you return JSON like this, both values are used:

{ "id": "your-own-id", "url": "https://example.com/blog/seo-basics" }

id replaces articleId as the key sent on later requests for this article, and url is recorded as where the article lives. Returning nothing at all is fine.

Setting the public site URL

Because a receiver is not asked where the article ended up, Growth Calendar does not know the address unless you say. Fill in Public site URL on the same settings screen, such as https://example.com/blog, and articles are treated as living at that address plus their slug.

Without it, sibling articles cannot link to anything sent through the webhook. See the section on internal links below.

Choosing how articles are sent

Once connected, the same screen offers three choices.

SettingWhat happens
ManualNothing is sent automatically. Articles go only when you select "Publish to CMS".
Send as draftEvery finished article is sent with status: "draft".
Publish automaticallyEvery finished article is sent with status: "published".

What draft means is up to your receiver. Growth Calendar only reports which one was asked for.

Sending a single article

Use Publish to CMS at the top right of an article. The control next to it switches between sending it as a draft and as published.

Growth Calendar links articles in the same cluster to each other. When an article is sent, links to siblings that already have an address become real URLs; the rest are unwrapped to plain text, because a link to an address that does not exist would send readers to an error page.

For webhook destinations, an article has an address once the public site URL is set. Without it, no article sent this way is ever linked to by another.

About images

Images keep their Timothe-hosted addresses in imageUrls and in the Markdown. They are not uploaded anywhere. Copy them into your own storage in your receiver if you would rather not depend on those addresses.

When it does not work

"Could not reach that endpoint"

Nothing answered at that address. Check the receiver is deployed and reachable from the public internet, and that the URL has no typo. An address that resolves to a private or internal network is refused.

"The endpoint refused the secret"

The receiver answered 401 or 403. Check that it compares the same value that was entered here, against the Authorization header, in the form Bearer <secret>.

"Nothing is listening at that URL"

The receiver answered 404. The domain is right and the path is not. Enter the full path to the endpoint, not just the domain.

"That endpoint does not accept POST"

The receiver answered 405. Every article is sent as a POST, including the test request.

"Site URL must use https" / "must not contain a query or fragment" / "must not specify a port"

The endpoint has to be a plain https URL. If your receiver expects a token in the query string, put it in the shared secret instead and read it from the Authorization header.

"The endpoint rejected the article"

The receiver answered with an error while an article was being sent. The status code is in the message; check the receiver's own logs for the request that carries that articleId.

Other CMSs

WordPress, Ghost, Shopify and Notion connect from the same screen, and publish to those directly rather than through your own code.