Back to Blog
NotionTimeToPostAPI integrationsocial media schedulingwebhooks

How to connect Notion to TimeToPost through the API, without a no-code middleman

T
TimeToPost Team

TL;DR: Connect a Notion workspace to TimeToPost directly by reading database items, mapping them into `POST /api/posts`, optionally uploading media with `POST /api/media/presign`, and saving the returned post id back to Notion. TimeToPost’s REST API is the same API the dashboard uses, so you get deterministic control without a no-code middleman.

Decide whether API wiring is actually the right path

If you want a direct Notion to TimeToPost connection with deterministic control, the REST API is the clean route. TimeToPost says its REST API is the same API the web dashboard uses, so anything you can click in the dashboard can be scripted over HTTPS against https://timetopost.co/api with your active organization scope. That is a lot less magical than a no-code middleman, which is often the point.

If you later decide you want an agent-based path instead of raw HTTP, the official TimeToPost MCP docs show the product’s MCP option without leaving the TimeToPost ecosystem.

What you need before you start

Here is the short list so this does not turn into a scavenger hunt:

  • A personal API token from Settings → API
  • A Notion source of post data
  • A TimeToPost organization connection scoped to the active organization

A few token details matter. TimeToPost says API tokens are shown exactly once at creation, only a hash is stored, and you should copy the token immediately. Authentication is bearer auth, sent like Authorization: Bearer ttp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx. Tokens act with your full account permissions, and API tokens cannot create or revoke other tokens.

Map Notion fields to the TimeToPost post payload

The main job is translation. A Notion database item becomes one JSON payload for POST /api/posts.

TimeToPost accepts these documented fields for creating a post:

Notion field TimeToPost field Notes
Caption or body text content Required post text
Target account choice accountIds or platforms Use specific connected accounts or platform names
Media attachment mediaUrls Optional array of media URLs
Publish time scheduledAt Optional, future ISO 8601 timestamp

A few rules keep the scheduler from doing anything weird:

  • scheduledAt must be a valid ISO 8601 timestamp in the future
  • past timestamps are rejected with a validation error
  • if you omit scheduledAt, TimeToPost saves a draft

That last bit is handy. No publish time, no fire. Just a draft sitting there like it knows it has homework.

Worked example: one Notion database item becomes one scheduled post

This is a hypothetical Notion row.

Notion field Value
caption New feature drop: exports now speak API.
publish time 2026-07-01T15:00:00.000Z
target platform linkedin
media URL https://media.example.com/launch-card.jpg

Mapped to the documented TimeToPost request shape:

{
  "content": "New feature drop: exports now speak API.",
  "platforms": ["linkedin"],
  "mediaUrls": ["https://media.example.com/launch-card.jpg"],
  "scheduledAt": "2026-07-01T15:00:00.000Z"
}

If you prefer connected accounts instead of platform names, swap platforms for accountIds and use the integration ids returned by GET /api/integrations.

Expected result, per the docs, is a 201 response and a created scheduled post. If scheduledAt is omitted, the same request shape creates a draft instead.

Build the integration flow

A straightforward direct flow looks like this:

  1. Read the Notion item
  2. Transform the item into the JSON payload TimeToPost expects
  3. Send it to POST /api/posts with the bearer token
  4. Store the returned TimeToPost post id back in Notion for traceability

If media is involved, use the documented upload flow first:

  1. Request a presigned URL from POST /api/media/presign
  2. Upload the file directly to the returned URL with PUT
  3. Put the returned publicUrl into mediaUrls

TimeToPost says uploads go directly to storage, the file never proxies through the API, and storage credentials never reach the client. Nice and boring, which is exactly what you want from file handling.

Handle success, validation errors, and retries

The API error classes that matter here are the simple, annoying ones:

  • 400, validation problems
  • 401, missing or invalid token
  • 403, plan or permission limits
  • 404, not found, including posts owned by other organizations

Two more behaviors are worth keeping in your code path:

  • past scheduledAt values are rejected
  • DELETE /api/posts/:id can cancel a scheduled post before it fires

For status sync, webhooks are the clean answer. TimeToPost’s webhook docs say webhooks tell your own systems what happened to a post without polling. You can use them to update the Notion record when a post is scheduled, published, partially published, failed, or approved, which keeps the workspace in sync without hammering the API like it owes you money.

Verification checklist for a human review pass

Use this as the final sanity check:

  • The Notion item maps to the correct TimeToPost payload
  • The API token authenticates successfully
  • scheduledAt is future-dated
  • The returned post id is saved back into Notion
  • Webhook updates arrive and update the record

If you want the callback path documented in one place, the official TimeToPost webhook docs help verify event handling and signature checks.

What this approach does not do

TimeToPost does not have a one-click importer. Posts move through the other system’s export plus the REST API or MCP tools, and historical analytics from other tools are not imported. TimeToPost records metrics only for posts it publishes.

That is the whole trick, really. Notion stays your source of truth, TimeToPost stays the scheduler, and the API is the part that keeps everyone honest.

Put these strategies into action

TimeToPost helps you schedule content, track performance, and grow your audience, all in one place.

No card for your first post. TimeToPost posts it at your best time.