# Get a post

Fetch one post with the status, platform post ID, URL and error of each target.


```http
GET https://social-publish-api.onrender.com/v1/posts/{id}
```

Returns a single post and all of its targets. Poll this endpoint to follow a post through publishing, or use [webhook events](/docs/api/webhook-events) to be notified instead.

## Headers

| Header | Required | Description |
| --- | --- | --- |
| `x-access-key` | Yes* | Your API key. *Or send `Authorization: Bearer <key>`. |

## Path parameters

| Parameter | Type | Description |
| --- | --- | --- |
| `id` | string (UUID) | The post ID returned by [Create a post](/docs/api/create-post). |

## Request

```bash tab="cURL"
curl https://social-publish-api.onrender.com/v1/posts/a3f8c2d1-9b7e-4c6a-8f5d-2e1b0c9a8d7f \
  -H "x-access-key: $RELAYCAST_API_KEY"
```

```ts tab="Node.js"
const postId = "a3f8c2d1-9b7e-4c6a-8f5d-2e1b0c9a8d7f";
const res = await fetch(`https://social-publish-api.onrender.com/v1/posts/${postId}`, {
  headers: { "x-access-key": process.env.RELAYCAST_API_KEY! },
});
if (res.status === 404) throw new Error("Post not found");
const { data: post } = await res.json();
for (const t of post.targets) console.log(t.platform, t.status, t.externalUrl ?? t.errorMessage);
```

```python tab="Python"
import os, requests

post_id = "a3f8c2d1-9b7e-4c6a-8f5d-2e1b0c9a8d7f"
res = requests.get(
    f"https://social-publish-api.onrender.com/v1/posts/{post_id}",
    headers={"x-access-key": os.environ["RELAYCAST_API_KEY"]},
)
res.raise_for_status()
post = res.json()["data"]
for t in post["targets"]:
    print(t["platform"], t["status"], t["externalUrl"] or t["errorMessage"])
```

## Response

```json title="Response 200"
{
  "data": {
    "id": "a3f8c2d1-9b7e-4c6a-8f5d-2e1b0c9a8d7f",
    "content": "Our new release is live. Faster uploads, a calendar view and more.",
    "media": [{ "url": "https://cdn.example.com/release.jpg", "type": "image", "altText": "Release banner" }],
    "status": "published",
    "scheduledFor": "2026-11-02T15:00:00.000Z",
    "request": {
      "content": "Our new release is live. Faster uploads, a calendar view and more.",
      "targets": [{ "accountId": "6f1c2a7e-4b8d-4f7a-9a51-2d3c4b5a6e7f" }],
      "media": [{ "url": "https://cdn.example.com/release.jpg", "type": "image", "altText": "Release banner" }],
      "publishNow": false,
      "scheduledFor": "2026-11-02T15:00:00Z"
    },
    "createdAt": "2026-10-05T09:30:12.441Z",
    "updatedAt": "2026-11-02T15:00:06.230Z",
    "targets": [
      {
        "id": "e1d2c3b4-a596-4877-8695-a4b3c2d1e0f9",
        "accountId": "6f1c2a7e-4b8d-4f7a-9a51-2d3c4b5a6e7f",
        "platform": "twitter",
        "status": "published",
        "content": null,
        "options": {},
        "attempts": 1,
        "externalPostId": "1852700000000000000",
        "externalUrl": "https://x.com/acme/status/1852700000000000000",
        "errorCode": null,
        "errorMessage": null,
        "publishedAt": "2026-11-02T15:00:06.218Z",
        "createdAt": "2026-10-05T09:30:12.441Z",
        "updatedAt": "2026-11-02T15:00:06.218Z"
      }
    ]
  }
}
```

### Post fields

| Field | Type | Description |
| --- | --- | --- |
| `id` | string (UUID) | Post ID. |
| `content` | string | Shared post text. |
| `media` | object[] | Shared media items (`url`, `type`, optional `altText`, `title`). |
| `status` | string | Overall status, see below. |
| `scheduledFor` | string | When the post was (or will be) sent. For `publishNow` posts, the creation time. |
| `request` | object | The request body as accepted, with defaults filled in. Useful to re-send or debug a post. |
| `createdAt`, `updatedAt` | string | ISO 8601 timestamps. |
| `targets` | object[] | One entry per account. |

### Target fields

| Field | Type | Description |
| --- | --- | --- |
| `id` | string (UUID) | Target ID. |
| `accountId` | string (UUID) | The account posted to. |
| `platform` | string | The account's platform. |
| `status` | string | `queued`, `publishing`, `published` or `failed`. |
| `content` | string \| null | Per-account text override; `null` means the post `content` was used. |
| `options` | object | Platform options sent for this account. |
| `attempts` | integer | Publish attempts so far. |
| `externalPostId` | string \| null | The platform's ID for the published post. |
| `externalUrl` | string \| null | Public URL of the published post, when the platform provides one. |
| `errorCode` | string \| null | Last error: `auth_revoked`, `rate_limited`, `invalid_content`, `media_error` or `platform_error`. |
| `errorMessage` | string \| null | Human-readable error from the last attempt. |
| `publishedAt` | string \| null | When the target was published. |
| `createdAt`, `updatedAt` | string | ISO 8601 timestamps. |

### Statuses

| Post `status` | Meaning |
| --- | --- |
| `scheduled` | Waiting for `scheduledFor`. |
| `publishing` | At least one target is queued or being published. |
| `published` | Every target was published. |
| `partial` | Some targets were published and some failed. |
| `failed` | Every target failed. |

A target whose last attempt hit a temporary problem goes back to `queued` and keeps its `errorCode`/`errorMessage` until a later attempt succeeds. A `published` target can have no `externalUrl`: for example, a TikTok post still in TikTok's moderation, or a TikTok inbox draft. See [Posts](/docs/posts) for details.

## Errors

| Status | Code | When |
| --- | --- | --- |
| 401 | `unauthorized` | Missing or invalid API key. |
| 404 | `not_found` | No post with this ID in the API key's project. |
| 429 | `rate_limited` | Rate limit exceeded for this key. |

```json title="Response 404"
{
  "error": {
    "code": "not_found",
    "message": "Post not found"
  }
}
```
