> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mymarky.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Schedule post

> Schedule a post for publishing at a specific time.

The post must be in NEW or SCHEDULED status. Set `scheduled_publish_time` to a
future datetime (ISO 8601). The post will be published automatically at that
time to all connected platforms, or to specific platforms if
`restrict_publish_to` is set.

Errors:
    400 invalid_request: The post status is not NEW or SCHEDULED, or scheduled_publish_time is not in the future.
    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 post with that ID exists, or it is not in this business.
    429 rate_limit_exceeded: You sent too many requests this minute.



## OpenAPI

````yaml public-openapi.json post /api/businesses/{business_id}/posts/{post_id}/schedule
openapi: 3.1.0
info:
  title: Marky Public API
  version: '2026-04-08'
  description: Create and schedule posts, manage businesses, library, media, and webhooks.
servers:
  - url: https://api.mymarky.ai
    description: Production
security: []
paths:
  /api/businesses/{business_id}/posts/{post_id}/schedule:
    post:
      tags:
        - public-api
      summary: Schedule post
      description: >-
        Schedule a post for publishing at a specific time.


        The post must be in NEW or SCHEDULED status. Set
        `scheduled_publish_time` to a

        future datetime (ISO 8601). The post will be published automatically at
        that

        time to all connected platforms, or to specific platforms if

        `restrict_publish_to` is set.


        Errors:
            400 invalid_request: The post status is not NEW or SCHEDULED, or scheduled_publish_time is not in the future.
            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 post with that ID exists, or it is not in this business.
            429 rate_limit_exceeded: You sent too many requests this minute.
      operationId: schedule_post
      parameters:
        - name: business_id
          in: path
          required: true
          schema:
            type: string
            description: A UUID identifier.
            title: Business Id
          description: A UUID identifier.
        - name: post_id
          in: path
          required: true
          schema:
            type: string
            description: A UUID identifier.
            title: Post Id
          description: A UUID identifier.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PostScheduleRequest'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PostResponse'
        '400':
          description: Error (Stripe-style envelope — match on error.code, not the message)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '401':
          description: Error (Stripe-style envelope — match on error.code, not the message)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '403':
          description: Error (Stripe-style envelope — match on error.code, not the message)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '404':
          description: Error (Stripe-style envelope — match on error.code, not the message)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '409':
          description: Error (Stripe-style envelope — match on error.code, not the message)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '429':
          description: Error (Stripe-style envelope — match on error.code, not the message)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '500':
          description: Error (Stripe-style envelope — match on error.code, not the message)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
      security:
        - HTTPBearer: []
components:
  schemas:
    PostScheduleRequest:
      properties:
        scheduled_publish_time:
          type: string
          format: date-time
          title: Scheduled Publish Time
          description: When to publish (ISO 8601 datetime, must be in the future)
        restrict_publish_to:
          anyOf:
            - items:
                type: string
                enum:
                  - facebook
                  - instagram
                  - twitter
                  - linkedIn
                  - linkedInProfile
                  - tiktok
                  - pinterest
                  - googleBusiness
                  - instagramStory
                  - youtube
              type: array
            - type: 'null'
          title: Restrict Publish To
          description: >-
            Restrict publishing to these platforms (e.g. instagram, facebook,
            linkedIn). Case-insensitive. Omit or set null to publish to ALL
            connected platforms.
      additionalProperties: false
      type: object
      required:
        - scheduled_publish_time
      title: PostScheduleRequest
    PostResponse:
      properties:
        id:
          type: string
          title: Id
          description: Post ID
        business_id:
          type: string
          title: Business Id
          description: Business this post belongs to
        caption:
          anyOf:
            - type: string
            - type: 'null'
          title: Caption
          description: Post caption text
        status:
          anyOf:
            - type: string
            - type: 'null'
          title: Status
          description: >-
            Post status. One of: NEW (draft, incl. freshly generated), SCHEDULED
            (queued for a future time), PUBLISHED (already posted). Same values
            the `list_posts` status filter accepts.
        media_urls:
          anyOf:
            - items:
                type: string
              type: array
            - type: 'null'
          title: Media Urls
          description: Attached media URLs
        link:
          anyOf:
            - type: string
            - type: 'null'
          title: Link
          description: >-
            Clickable destination URL for platforms that support link posts: the
            Facebook link attachment, the Google Business CTA button, and the
            Pinterest pin destination. Other platforms ignore it — put links in
            the caption there. Must be http(s).
        restrict_publish_to:
          anyOf:
            - items:
                type: string
              type: array
            - type: 'null'
          title: Restrict Publish To
          description: >-
            Platforms this post is restricted to. Null means ALL connected
            platforms.
        scheduled_publish_time:
          anyOf:
            - type: string
              format: date-time
            - type: 'null'
          title: Scheduled Publish Time
          description: >-
            The exact time this post is scheduled to publish (set via
            `schedule`). Null for drafts, queued posts, and already-published
            posts.
        published_at:
          anyOf:
            - type: string
              format: date-time
            - type: 'null'
          title: Published At
          description: >-
            When the post was actually published (past timestamp). Null until it
            publishes.
        metadata:
          anyOf:
            - additionalProperties:
                type: string
              type: object
            - type: 'null'
          title: Metadata
          description: >-
            Caller-defined string key/value pairs set at create/update time —
            your own analytics dimensions (e.g. media_type, format, style, hook,
            topic). Marky returns them verbatim and never interprets them.
        platform_overrides:
          anyOf:
            - items:
                $ref: '#/components/schemas/PlatformOverrideModel'
              type: array
            - type: 'null'
          title: Platform Overrides
          description: >-
            Per-platform content overrides on this post, if any. Each platform
            publishes its override fields where set, the post's own fields
            otherwise.
        publish_results:
          items:
            $ref: '#/components/schemas/PublishResultResponse'
          type: array
          title: Publish Results
          description: >-
            Per-platform publish outcomes — one entry per platform this post was
            sent to. Poll this until every entry has a terminal status
            (`success` or `failed`) to know publishing is complete.
        queue:
          anyOf:
            - $ref: '#/components/schemas/QueueInfo'
            - type: 'null'
          description: >-
            Daily-queue placement. Present only when the post is in a recurring
            daily queue (status SCHEDULED with no `adhoc_publish_time`). Null
            for drafts, adhoc-scheduled, and published posts.
        created_at:
          type: string
          format: date-time
          title: Created At
          description: When the post was created
        updated_at:
          anyOf:
            - type: string
              format: date-time
            - type: 'null'
          title: Updated At
          description: Last update time
        url:
          type: string
          title: Url
          description: >-
            Link to view this post in the Marky app (openable/shareable — show
            it to the user). This is where the post lives in Marky; `link` is
            the outbound URL published with the post.
          readOnly: true
        scheduled_posts_url:
          anyOf:
            - type: string
            - type: 'null'
          title: Scheduled Posts Url
          description: >-
            Link to the workspace's scheduled-posts list in the Marky app —
            where the user sees this post waiting in the lineup. Present once
            the post is SCHEDULED; null otherwise.
          readOnly: true
      type: object
      required:
        - id
        - business_id
        - created_at
        - url
        - scheduled_posts_url
      title: PostResponse
    ErrorEnvelope:
      description: >-
        The body of every non-2xx response.


        `detail` is retained on internal routes for backward-compatibility while
        the

        frontend migrates to reading `error.code`.
      properties:
        error:
          $ref: '#/components/schemas/ErrorDetail'
      required:
        - error
      title: ErrorEnvelope
      type: object
    HTTPValidationError:
      properties:
        detail:
          items:
            $ref: '#/components/schemas/ValidationError'
          type: array
          title: Detail
      type: object
      title: HTTPValidationError
    PlatformOverrideModel:
      properties:
        platform:
          type: string
          enum:
            - facebook
            - instagram
            - twitter
            - linkedIn
            - linkedInProfile
            - tiktok
            - pinterest
            - googleBusiness
            - instagramStory
            - youtube
          title: Platform
          description: >-
            Platform this override applies to (e.g. instagram, linkedIn,
            twitter). Case-insensitive.
        caption:
          anyOf:
            - type: string
            - type: 'null'
          title: Caption
          description: >-
            Caption this platform gets instead of the post's caption. Tailor
            length, hashtag count, and link placement to the platform.
        media_urls:
          anyOf:
            - items:
                type: string
              type: array
            - type: 'null'
          title: Media Urls
          description: Media this platform gets instead of the post's media_urls.
        title:
          anyOf:
            - type: string
            - type: 'null'
          title: Title
          description: >-
            Title, on platforms that have one (Pinterest pin title, YouTube
            video title).
        link:
          anyOf:
            - type: string
            - type: 'null'
          title: Link
          description: >-
            Destination link, on platforms that support one (e.g. Pinterest,
            Google Business).
        first_comment:
          anyOf:
            - type: string
            - type: 'null'
          title: First Comment
          description: >-
            Comment auto-posted right after publishing on this platform — the
            usual home for hashtags and links on Instagram/LinkedIn.
      additionalProperties: false
      type: object
      required:
        - platform
      title: PlatformOverrideModel
      description: |-
        Per-platform variant of a post's content.

        At publish time each platform uses its override field when set and falls
        back to the post's own field when not. Overrides for platforms the post
        doesn't publish to are inert.
    PublishResultResponse:
      properties:
        platform:
          type: string
          title: Platform
          description: Platform identifier (facebook, instagram, etc.)
        status:
          type: string
          title: Status
          description: 'Publish status on this platform: success, failed, in_progress, etc.'
        publish_id:
          anyOf:
            - type: string
            - type: 'null'
          title: Publish Id
          description: >-
            External post ID on the platform — use with `GET
            /businesses/{business_id}/integrations/{integration_id}/posts/{external_post_id}/stats`
        post_url:
          anyOf:
            - type: string
            - type: 'null'
          title: Post Url
          description: Public URL of the published post on the platform
        error_type:
          anyOf:
            - type: string
            - type: 'null'
          title: Error Type
          description: Error type if status is failed (e.g. REFRESH_TOKEN_EXPIRED, TIMEOUT)
        error_message:
          anyOf:
            - type: string
            - type: 'null'
          title: Error Message
          description: Human-readable error message if status is failed
        updated_at:
          anyOf:
            - type: string
              format: date-time
            - type: 'null'
          title: Updated At
          description: When this result was last updated
      type: object
      required:
        - platform
        - status
      title: PublishResultResponse
    QueueInfo:
      properties:
        queue_id:
          type: string
          title: Queue Id
          description: ID of the daily queue this post belongs to.
        position:
          type: integer
          title: Position
          description: 1-based rank among the queued posts (1 = next to publish).
        estimated_publish_time:
          anyOf:
            - type: string
              format: date-time
            - type: 'null'
          title: Estimated Publish Time
          description: >-
            Best estimate of when this post will publish, projected from the
            queue's recurring timeslots. Ignores jitter and skipped slots, so
            treat it as approximate. Null if it can't be computed.
      type: object
      required:
        - queue_id
        - position
      title: QueueInfo
      description: |-
        Where a post sits in its business's recurring daily publishing queue.

        Only present on posts that are in a queue (status SCHEDULED with no
        `adhoc_publish_time`). Lets an API user confirm a queued post is really
        queued and see roughly when it will publish.
    ErrorDetail:
      properties:
        type:
          type: string
          title: Type
          description: >-
            Broad error category derived from the HTTP status
            (invalid_request_error, authentication_error, permission_error,
            not_found_error, rate_limit_error, api_error).
        code:
          $ref: '#/components/schemas/ErrorCode'
          description: >-
            Stable, machine-readable error code. Match on THIS, never on the
            message. Codes never change even when the message is reworded.
        message:
          type: string
          title: Message
          description: Human-readable explanation. For display/logging only — do not parse.
        doc_url:
          type: string
          title: Doc Url
          description: Link to the docs entry for this error code.
        param:
          anyOf:
            - type: string
            - type: 'null'
          title: Param
          description: The offending request field, when the error is field-specific.
        request_id:
          anyOf:
            - type: string
            - type: 'null'
          title: Request Id
          description: >-
            The id of this request (also returned as the X-Request-Id header).
            Quote it to support so they can find the exact request in our logs.
      type: object
      required:
        - type
        - code
        - message
        - doc_url
      title: ErrorDetail
    ValidationError:
      properties:
        loc:
          items:
            anyOf:
              - type: string
              - type: integer
          type: array
          title: Location
        msg:
          type: string
          title: Message
        type:
          type: string
          title: Error Type
      type: object
      required:
        - loc
        - msg
        - type
      title: ValidationError
    ErrorCode:
      type: string
      enum:
        - authentication_required
        - permission_denied
        - resource_not_found
        - rate_limit_exceeded
        - validation_error
        - internal_error
        - already_exists
        - invalid_request
        - WORKSPACE_NOT_SUPPORTED
        - INSUFFICIENT_CREDITS
        - BUSINESS_CREDIT_LIMIT_EXCEEDED
        - NO_ENABLED_TOPICS
        - GENERATION_CAP_REACHED
        - CHECKOUT_BLOCKED
        - INVALID_API_KEY
        - SOCIAL_TOKEN_EXPIRED
        - PAYMENT_REQUIRED
        - NO_CONNECTED_SOCIALS
        - NOT_ENOUGH_POSTS_FOR_TOPICS
        - WORKSPACE_LIMIT_EXCEEDED
        - PHONE_NOT_VERIFIED
        - FILE_TOO_LARGE
        - SUBSCRIPTION_ALREADY_ACTIVE
        - UPSTREAM_PROVIDER_ERROR
        - PLATFORM_MEDIA_UNSUPPORTED
        - SOCIAL_CONNECT_FAILED
        - NO_PHOTO_SOURCE
        - TEMPLATE_FORMAT_MISMATCH
        - INVALID_CSV_ROW
        - IMAGE_GENERATION_FAILED
        - POST_RENDER_FAILED
        - POST_DESIGN_SELECTION_FAILED
        - POST_CONTENT_GENERATION_FAILED
        - POST_IDEATION_FAILED
        - IDEMPOTENCY_KEY_CONFLICT
      title: ErrorCode
      description: >-
        The full set of stable `error.code` values the API can return.


        Two groups: (1) GENERIC codes the global handler derives from the HTTP
        status

        or message keyword for plain raises (see api_errors._error_code + the
        handlers),

        and (2) the typed BUSINESS codes (mirror of ErrorType) for raises the
        frontend

        must tell apart from other same-status errors.


        This enum exists so OpenAPI emits an `enum` for error.code — a canonical
        list in

        the docs and a typed union for codegen — instead of a bare string. It
        does NOT

        validate runtime responses (those are plain dicts built in
        _build_error_response),

        so a code missing here only means incomplete docs, never a 500. The

        test_error_code_enum_covers_* tests keep it in sync with ErrorType +
        _error_code

        so it can't silently drift.
  securitySchemes:
    HTTPBearer:
      type: http
      scheme: bearer

````