PostPost

Post Logs

Get detailed publish attempt history for a post group. Useful for debugging failed posts and understanding the publish timeline.

Endpoint

GET https://api.postpost.dev/api/v1/post-logs/:postGroupId

Headers

HeaderRequiredDescription
x-api-keyYesYour API key
x-postpost-user-idNoManaged user ID (workspace only)
x-postpost-clientNoSet to mcp for MCP tool access

MCP access: If the x-postpost-client: mcp header is sent, the server validates entitlements.features.mcpAccess and returns 403 "MCP access is not enabled for this account" if the feature is not enabled.

Path Parameters

ParameterTypeDescription
postGroupIdstringThe post group ID

Note: Results are limited to the first 100 log entries per post group (sorted ascending by creation time, oldest first).

Response

{
  "success": true,
  "logs": [
    {
      "_id": "65f8a1b2c3d4e5f6a7b8c9d0",
      "postGroupId": "507f1f77bcf86cd799439011",
      "postId": "507f1f77bcf86cd799439012",
      "platform": "linkedin",
      "event": "processing",
      "createdAt": "2026-02-22T14:30:00.000Z"
    },
    {
      "_id": "65f8a1b2c3d4e5f6a7b8c9d1",
      "postGroupId": "507f1f77bcf86cd799439011",
      "postId": "507f1f77bcf86cd799439012",
      "platform": "linkedin",
      "event": "publish_attempted",
      "retryCount": 0,
      "createdAt": "2026-02-22T14:30:01.000Z"
    },
    {
      "_id": "65f8a1b2c3d4e5f6a7b8c9d2",
      "postGroupId": "507f1f77bcf86cd799439011",
      "postId": "507f1f77bcf86cd799439012",
      "platform": "linkedin",
      "event": "publish_succeeded",
      "createdAt": "2026-02-22T14:30:03.000Z"
    },
    {
      "_id": "65f8a1b2c3d4e5f6a7b8c9d3",
      "postGroupId": "507f1f77bcf86cd799439011",
      "event": "processing",
      "createdAt": "2026-02-22T14:30:00.000Z"
    },
    {
      "_id": "65f8a1b2c3d4e5f6a7b8c9d4",
      "postGroupId": "507f1f77bcf86cd799439011",
      "postId": "507f1f77bcf86cd799439013",
      "platform": "threads",
      "event": "publish_attempted",
      "retryCount": 1,
      "createdAt": "2026-02-22T14:30:01.000Z"
    },
    {
      "_id": "65f8a1b2c3d4e5f6a7b8c9d5",
      "postGroupId": "507f1f77bcf86cd799439011",
      "postId": "507f1f77bcf86cd799439013",
      "platform": "threads",
      "event": "publish_failed",
      "error": "Error validating access token",
      "httpStatus": 401,
      "retryCount": 1,
      "metadata": {
        "errorCode": "PLATFORM_AUTH_EXPIRED",
        "retryable": false
      },
      "createdAt": "2026-02-22T14:30:02.000Z"
    }
  ]
}

Note: Response also includes updatedAt (auto-managed by Mongoose) and __v (Mongoose version key) fields, omitted from examples for brevity.

Log Fields

FieldTypeDescription
_idstringUnique log entry ID
postGroupIdstringParent post group ID
postIdstring/undefinedIndividual platform post ID. May be absent for group-level events (e.g., initial processing).
platformstring/undefinedPlatform name (twitter, linkedin, etc.). May be absent for group-level events.
eventstringEvent type (see table below)
errorstring or absentError message (for failed events). Absent from the response when there is no error (not null).
httpStatusnumber or absentHTTP status code from platform. Absent from the response when not applicable (not null).
retryCountnumber or absentNumber of retry attempts. Absent if no retries have occurred -- do not assume it defaults to 0.
metadataobject or absentAdditional event data. Absent from the response when there is no metadata (not null).
createdAtstringEvent timestamp
updatedAtstringLast update timestamp (auto-managed by Mongoose)
__vnumberMongoose version key. Present in responses but not part of the documented schema — can be safely ignored.

Event Types

EventDescription
scheduledPost was scheduled
processingPost started processing
publish_attemptedPublish request sent to platform
publish_succeededSuccessfully published
publish_failedPublishing failed
status_changedPost status changed

Examples

JavaScript (fetch)

const postGroupId = '507f1f77bcf86cd799439011';
const response = await fetch(
  `https://api.postpost.dev/api/v1/post-logs/${postGroupId}`,
  { headers: { 'x-api-key': 'YOUR_API_KEY' } }
);
const { logs } = await response.json();

// Group logs by platform
const byPlatform = logs.reduce((acc, log) => {
  if (!acc[log.platform]) acc[log.platform] = [];
  acc[log.platform].push(log);
  return acc;
}, {});

// Check for failures
const failures = logs.filter(l => l.event === 'publish_failed');
if (failures.length > 0) {
  console.log('Failed platforms:');
  failures.forEach(f => {
    console.log(`  ${f.platform}: ${f.error} (HTTP ${f.httpStatus})`);
  });
}

Python (requests)

import requests

post_group_id = '507f1f77bcf86cd799439011'
response = requests.get(
    f'https://api.postpost.dev/api/v1/post-logs/{post_group_id}',
    headers={'x-api-key': 'YOUR_API_KEY'}
)
logs = response.json()['logs']

# Find failed publish attempts
failures = [l for l in logs if l['event'] == 'publish_failed']
for failure in failures:
    print(f"❌ {failure['platform']}: {failure['error']}")
    if failure.get('metadata', {}).get('retryable'):
        print("   (This error may succeed on retry)")

cURL

curl https://api.postpost.dev/api/v1/post-logs/507f1f77bcf86cd799439011 \
  -H "x-api-key: YOUR_API_KEY"

Debug Failed Post

async function debugFailedPost(postGroupId) {
  const [postResponse, logsResponse] = await Promise.all([
    fetch(`https://api.postpost.dev/api/v1/get-post/${postGroupId}`, {
      headers: { 'x-api-key': process.env.PUBLORA_API_KEY }
    }),
    fetch(`https://api.postpost.dev/api/v1/post-logs/${postGroupId}`, {
      headers: { 'x-api-key': process.env.PUBLORA_API_KEY }
    })
  ]);

  const postData = await postResponse.json();
  const logsData = await logsResponse.json();

  console.log('=== Post Status ===');
  for (const post of postData.posts) {
    console.log(`${post.platform}: ${post.status}`);
    if (post.error) {
      console.log(`  Error: ${post.error.code} - ${post.error.message}`);
      console.log(`  Retryable: ${post.error.retryable}`);
    }
  }

  console.log('\n=== Timeline ===');
  for (const log of logsData.logs) {
    const time = new Date(log.createdAt).toISOString();
    console.log(`[${time}] ${log.platform}: ${log.event}`);
    if (log.error) {
      console.log(`  └─ ${log.error}`);
    }
  }
}

Errors

StatusErrorCause
400"Invalid x-postpost-user-id"The x-postpost-user-id header value is not a valid ID
401"API key is required"x-api-key header is missing entirely
401"Invalid API key"x-api-key is present but invalid
401"Invalid API key owner"API key exists but the associated user account was not found
403"API access is not enabled for this account"The user's account does not have API access enabled
403"MCP access is not enabled for this account"The x-postpost-client: mcp header was sent but entitlements.features.mcpAccess is not enabled
403"Workspace access is not enabled for this key"API key does not have workspace access enabled
403"User is not managed by key"Managed user does not belong to the API key owner's workspace
404"Post group not found"Invalid ID or post belongs to another user
500"Failed to get post logs"Server error

Note: If an invalid ObjectId format is passed as postGroupId (e.g., a non-hex string or wrong length), the endpoint returns 500 "Failed to get post logs" instead of 404 "Post group not found". This is because Mongoose throws a CastError for invalid ObjectIds, which is caught by the generic error handler before the post group lookup can return a 404.


On this page