---
title: "Send the article"
method: POST
path: "/v1/orders/{order_id}/content"
tags: ["Content"]
---

# Send the article

`POST /v1/orders/{order_id}/content`

## Request

- Base URL: `https://api.placementapi.com`
- URL: `https://api.placementapi.com/v1/orders/{order_id}/content`
- Auth: HTTP bearer

For an awaiting_content or content_revision_requested order. Validated against the publisher's spec; 422 lists the problems. `status: "draft"` stores a version without submitting (nothing charged, order status unchanged) — Papi's draft for approval; resend with `status: "submitted"` to approve. A submission moves the order to `ordered` for the next batch. Nothing further is charged; the papi_written fee was taken with the order. Requires the `order` scope.

## Path parameters

- `order_id` string, required

## Request body

- object: An article. Send body_markdown, body_html or doc_url. A doc_url alone cannot be validated and is accepted with a warning.
  - `title` string, nullable
  - `body_markdown` string, nullable
  - `body_html` string, nullable
  - `doc_url` string, uri, nullable
  - `meta_description` string, nullable
  - `status` 'draft' | 'submitted'
  - `submitted_by` 'customer' | 'papi'

## Response `201`

OK

- object
  - `order_id` string
  - `version` integer
  - `content_status` 'draft' | 'submitted'
  - `order_status` 'ordered' | 'awaiting_content' | 'content_revision_requested' | 'awaiting_operator' | 'submitted_to_vendor' | 'delivered' | 'cancelled' | 'refunded' | 'failed'
  - `charged_credits` integer
  - `validation` ContentValidation: Will this pass the publisher? Word count against the spec, external links against the allowance, the target linked exactly once with the anchor the order names, no forbidden anchor type.
    - `ok` boolean
    - `word_count` integer, nullable
    - `links_found` integer
    - `target_link_found` boolean
    - `problems` string[]
    - `warnings` string[]
  - `next` string

## Other responses

- `400`: Malformed request. `error` is `bad_request` (with a zod `detail`), `invalid_json`, or `unknown_parameter` / `unknown_field` (with `unknown[]` and `accepted[]`).
- `401`: Missing, malformed or revoked Bearer credential: `{ error: "unauthorized" }`.
- `402`: A safety-net papi_written charge could not be covered; carries `validation`.
- `403`: `insufficient_scope` when the key lacks the `order` scope; `customer_key_required` when the operator token is used where a customer must be attributable.
- `404`: `order_not_found`.
- `409`: `content_not_expected` (publisher or supplier writes), `order_not_open`, `content_already_submitted`.
- `422`: `content_invalid`, with `validation`. Send status 'draft' to store it anyway.
- `503`: `server_misconfigured` when the store is not configured; `upstream_unfunded` when the measurement provider's prepaid balance is exhausted (fresh profiles, gap maps and SERPs pause; cached results and catalogue are unaffected); `upstream_unavailable` on a provider error; `payments_unavailable` when card payments are not configured.

---

[API](https://skmtc.dev/placementapi/apis/placement-api.md) · [All operations](https://skmtc.dev/placementapi/apis/placement-api/llms.txt) · [OpenAPI document](https://skmtc.dev/placementapi/apis/placement-api/revisions/fc4e7866eaf7?raw)
