---
title: "Update posting schedule"
method: PUT
path: "/api/businesses/{business_id}/posting-schedule"
tags: ["posts"]
---

# Update posting schedule

`PUT /api/businesses/{business_id}/posting-schedule`

## Request

- Base URL: `https://api.mymarky.ai`
- URL: `https://api.mymarky.ai/api/businesses/{business_id}/posting-schedule`
- Auth: HTTP bearer

Replace a business's recurring posting schedule, or pause it.

Send the full set of weekly timeslots in `DAY HH:MM` 24-hour form, either on
the business's own clock with `timeslots_local` (e.g. 1 PM local is
`{"timeslots_local": ["MON 13:00", "WED 13:00"]}`) or in UTC with
`timeslots` (`{"timeslots": ["MON 18:00", "WED 18:00"]}`). Send exactly one.
When the owner names a time, use `timeslots_local`: it is the hour they said.
This replaces the whole schedule (it is not a merge). The next publish time is
recomputed automatically from the new slots. Check `timeslots_local` in the
response before telling the owner what was saved.

**To stop posting without losing anything, send `paused: true`** alongside the
current timeslots. Nothing publishes while a schedule is paused; the slots and
every queued post are kept, and `paused: false` resumes from the next upcoming
slot. Sending an empty `timeslots` is NOT a pause — it is a request to delete
the schedule, and it is refused.

Errors:
    400 invalid_value: The business_id is not a valid UUID.
    401 authentication_required: API key or token is missing, invalid, or revoked.
    403 permission_denied: Your plan does not include API access, or this business is not in your org.
    404 resource_not_found: No business with that ID exists.
    422 invalid_request: A timeslot is not in 'DAY HH:MM' 24-hour form, or both `timeslots` and `timeslots_local` were sent.
    422 SCHEDULE_HAS_NO_TIMESLOTS: No timeslots were sent. Send `paused: true` to stop posting instead.
    429 rate_limit_exceeded: You sent too many requests this minute.

## Path parameters

- `business_id` string, required: A UUID identifier.

## Headers

- `Marky-Version` '2026-04-08' | '2026-07-17' | '2026-08-02' | '2026-08-04' | '2026-08-06'

## Request body

- PostingScheduleUpdateRequest
  - `timeslots` string[]: Weekly recurring slots in UTC, 'DAY HH:MM' 24h form, e.g. ['MON 15:00', 'FRI 09:30']. Replaces the whole schedule. These are UTC, NOT the business's local time: to use the hour the owner said (e.g. '1pm' in Chicago), send `timeslots_local` instead. Send exactly one of the two.
  - `timeslots_local` string[], nullable: The same weekly slots on the business's own clock, 'DAY HH:MM' 24h form, e.g. ['MON 13:00'] for 1 PM local. Prefer this when the owner names a time: it is converted to UTC for you, and the response's `timeslots_local` echoes it back. Replaces the whole schedule. Send exactly one of `timeslots` / `timeslots_local`.
  - `jitter_minutes` integer: Random +/- minutes applied to each slot (0-720). Defaults to 0.
  - `paused` boolean, nullable: Stop or resume posting without changing the schedule. true pauses it: no queued post publishes, and the timeslots and every queued post are kept exactly as they are. false resumes from the next upcoming slot. Omit it to leave the pause state alone — pausing is a separate axis from the cadence, so editing the slots does not resume a schedule someone deliberately stopped.

## Response `200`

Successful Response

- PostingScheduleResponse: A business's recurring posting schedule (its daily publish queue).
  - `queue_id` string, required: ID of the publish queue backing this schedule.
  - `business_id` string, required: Business this schedule belongs to.
  - `timeslots` string[], required: Weekly recurring slots in 'DAY HH:MM' 24h form, e.g. ['MON 15:00', 'FRI 09:30']. A queued post publishes at the next upcoming slot.
  - `jitter_minutes` integer, required: Random +/- minutes applied to each slot so posts don't fire at the exact same second every day.
  - `next_publish_time` string, nullable: When the next queued post is due to publish, computed from the schedule. Null if not yet computed, or if the schedule is paused.
  - `next_publish_time_local` string, nullable: The same moment in the business's timezone, ready to show a person, e.g. "Wed Sep 23, 6:00 PM MSK". Quote it as-is instead of converting the UTC value.
  - `timeslots_local` string[]: `timeslots` on the business's clock, same order, e.g. 'MON 15:00' (UTC) is 'MON 18:00' in Moscow. The day can change when the offset crosses midnight.
  - `timezone` string, nullable: IANA timezone the `*_local` times are in: the business's calendar timezone, or "UTC" when the business hasn't set one (see `timezone_source`).
  - `timezone_source` 'business' | 'unset_utc', nullable: Where `timezone` came from: `business` (the business's own setting) or `unset_utc` (no timezone saved yet, so times are shown in UTC).
  - `paused` boolean: True while the schedule is paused: no queued post publishes, and the timeslots and queued posts are kept as they are.

## Other responses

- `400`: Bad request — the input was malformed or otherwise invalid.
- `401`: Authentication failed — the API key is missing or invalid.
- `403`: Forbidden — the key is valid but may not access this resource.
- `404`: Not found — no resource matches the id in the path.
- `422`: Validation error — one or more fields failed validation.
- `429`: Rate limited — retry after the window resets (see Retry-After).
- `500`: Server error — something failed on our side; retry or quote X-Request-Id.

---

[API](https://skmtc.dev/mymarky/apis/marky-public-api.md) · [All operations](https://skmtc.dev/mymarky/apis/marky-public-api/llms.txt) · [OpenAPI document](https://skmtc.dev/mymarky/apis/marky-public-api/revisions/25aeacae455c?raw)
