# TrackPost — Documentation

Last reviewed: 11 October 2026

[HTML](https://docs.trackpost.io/)

A clear path from campaign idea to approved social content.

## Getting started

1. Create and verify one Cloud account. 2. Select or create the organization that owns the integration. 3. Create a project for the website, shop or brand whose data must stay together. 4. Open the product workspace and confirm that it is enabled before copying credentials or sending production traffic.

That is the complete account setup. The remaining sections are implementation guides. Credentials are always project-scoped; server secrets must never be placed in browser code, public repositories or client-side environment variables.

## Connect a destination before publishing

Open TrackPost → Connections and connect at least one account you are authorized to use. Select the displayed destination in the post or API request; TrackPost prevents publishing to unavailable or unauthorized destinations.

## Connect publishing accounts

Once enabled, each user can connect the Facebook Pages, Instagram professional accounts, Threads profiles, Google Business locations, LinkedIn profiles or LinkedIn organization pages they are authorized to publish through. The OAuth callback imports eligible accounts as stable connection IDs; applications never collect provider access tokens themselves.

A LinkedIn member target remains bound to the person who connected it. Provider availability and permissions are validated per connection.

## Create a TrackPost API key

Open TrackPost → API. An organization owner or administrator creates a named key; the complete tp_live_ token is shown once and must be stored in a server-side secret manager. The same panel displays the exact project endpoint plus every usable platform and connection ID. Keys expire and can be revoked.

## Publish or schedule with post.publish

POST one post.publish event to the endpoint displayed in the workspace using Authorization: Bearer <token>. eventId is the integration's stable idempotency identifier. post accepts text, an HTTPS link, an HTTPS media URL or a combination; destinations contains 1–25 objects with the selected platform and exact connectionId. scheduledAt is optional and uses an ISO-8601 timestamp.

Accepted platform values are facebook, instagram, threads, google_business and linkedin. TrackPost verifies that every platform matches the stored connection. A platform name alone never publishes to every account. Existing integrations may keep the legacy targets string array, but a request must use exactly one of destinations or targets.

### cURL

```bash
curl --request POST "$TRACKPOST_API_URL" \
  --header "Authorization: Bearer $TRACKPOST_API_KEY" \
  --header "Content-Type: application/json" \
  --header "X-Request-Id: release_2030_001" \
  --data '{
  "eventId": "blog_release_2030_001",
  "type": "post.publish",
  "scheduledAt": "2030-01-15T14:00:00.000Z",
  "post": {
    "text": "Our new article is live.",
    "linkUrl": "https://example.com/blog/article"
  },
  "destinations": [
    {
      "platform": "linkedin",
      "connectionId": "CONNECTION_ID"
    }
  ]
}'
```

### Node.js

```javascript
const response = await fetch(process.env.TRACKPOST_API_URL, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.TRACKPOST_API_KEY}`,
    "Content-Type": "application/json",
    "X-Request-Id": "release_2030_001",
  },
  body: JSON.stringify({
    "eventId": "blog_release_2030_001",
    "type": "post.publish",
    "scheduledAt": "2030-01-15T14:00:00.000Z",
    "post": {
      "text": "Our new article is live.",
      "linkUrl": "https://example.com/blog/article"
    },
    "destinations": [
      {
        "platform": "linkedin",
        "connectionId": "CONNECTION_ID"
      }
    ]
  }),
});

if (!response.ok) throw new Error(`Request failed: ${response.status}`);
console.log(await response.json());
```

### Python

```python
import os
import requests

payload = {
    "eventId": "blog_release_2030_001",
    "type": "post.publish",
    "scheduledAt": "2030-01-15T14:00:00.000Z",
    "post": {
        "text": "Our new article is live.",
        "linkUrl": "https://example.com/blog/article",
    },
    "destinations": [
        {
            "platform": "linkedin",
            "connectionId": "CONNECTION_ID",
        },
    ],
}

response = requests.post(
    os.environ["TRACKPOST_API_URL"],
    headers={
        "Authorization": f"Bearer {os.environ['TRACKPOST_API_KEY']}",
        "Content-Type": "application/json",
        "X-Request-Id": "release_2030_001",
    },
    json=payload,
    timeout=10,
)
response.raise_for_status()
print(response.json())
```

### PHP

```php
<?php

$payload = [
    'eventId' => 'blog_release_2030_001',
    'type' => 'post.publish',
    'scheduledAt' => '2030-01-15T14:00:00.000Z',
    'post' => [
        'text' => 'Our new article is live.',
        'linkUrl' => 'https://example.com/blog/article',
    ],
    'destinations' => [
        [
            'platform' => 'linkedin',
            'connectionId' => 'CONNECTION_ID',
        ],
    ],
];
$curl = curl_init(getenv('TRACKPOST_API_URL'));

curl_setopt_array($curl, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('TRACKPOST_API_KEY'),
        'Content-Type: application/json',
        'X-Request-Id: release_2030_001',
    ],
    CURLOPT_POSTFIELDS => json_encode($payload, JSON_THROW_ON_ERROR),
    CURLOPT_TIMEOUT => 10,
]);

$response = curl_exec($curl);
if ($response === false) {
    throw new RuntimeException(curl_error($curl));
}
$status = curl_getinfo($curl, CURLINFO_RESPONSE_CODE);
curl_close($curl);
if ($status >= 400) {
    throw new RuntimeException("Request failed: $status");
}
echo $response;
```

## Channel cases and scheduling

One event creates one delivery per selected destination after its policy allows scheduling. An immediate request with a draft_only key remains a draft; approval_required waits for a reviewer. Once scheduled, immediate requests start processing and future scheduledAt values wait for the scheduler. Instagram professional publishing requires suitable media.

## Social media with AI agents

An agent may prepare channel-specific text and media references, but it should hand the final structured post.publish payload to an authorized server workflow. Keep content generation, human review, target selection and publication as separate auditable steps; never give the API key or provider tokens to browser-side agent code.

## Approval and idempotency

Review the exact content, destination and policy before approving a draft or approval-required post. Repeating the same eventId with the same key and payload returns status=duplicate. Store requestId, postId and status; never invent a new eventId merely because a response timed out.

## Responses, failures and measurement

A new plan returns HTTP 202; an idempotent replay returns HTTP 200. Correct 400 invalid_request, 401 invalid_token, 403 permission and 409 idempotency_conflict errors before retrying. Respect Retry-After on 429 and use bounded backoff for transient 503 errors.

TrackAny.Click parameters on owned links measure visits and downstream outcomes, not proof that a post was viewed. Publishing status and website attribution remain separate signals.

## Set a publishing policy for API keys

A new TrackPost API key defaults to draft_only. A post.publish request made with that key creates a draft and does not publish, even when scheduledAt is omitted. Choose approval_required to route matching destinations and formats to a human reviewer, or policy_auto_publish only for explicitly allowed connections, formats and campaigns.

TrackPost rejects destinations or formats outside the key's policy. A person with project publishing rights can approve or reject a draft or approval-required post. Acceptance of an API request is not a delivery confirmation; inspect the post and each destination's status.

## Check a publishing destination

Connect an account you are authorized to publish through and select the exact connection ID shown in TrackPost. A connected destination must be usable in the workspace before a post.publish request can be sent. The person who connected a LinkedIn member profile must remain the authorized publisher for that profile.

Prepare content and review it for each channel before scheduling. Keep the API key on your server, store eventId for safe retries, and check each destination's delivery result after acceptance.

## Products

- [TrackMailer](https://docs.markengroup.cloud/trackmailer.md): Reach customers reliably and keep every delivery clearly visible.
- [TrackAny.Click](https://docs.markengroup.cloud/trackany.md): Invest in the campaigns and customer journeys that create value.
- [TrackPost](https://docs.trackpost.io/index.md): Create relevant content quickly and keep every decision clear.
- [LeadScoutEngine](https://docs.markengroup.cloud/leadscoutengine.md): Find and prioritize companies from your criteria, then unlock only the intelligence your team needs.
