Human-readable integration guide

KORD Agent API

Let an external agent read workspace context, work with media and prepare posts. Draft access is the safe default; scheduling and publishing are separate permissions.

Access model

How agent access works

An owner or admin creates a token inside one workspace. The token never contains a Facebook, Instagram, LinkedIn, TikTok, YouTube or X credential. KORD keeps provider credentials encrypted and applies workspace, role and channel rules to every request.

Workspace scoped

The token can access only the client or brand where it was created.

Revocable secret

The full token is shown once. Quick tokens expire automatically; 30 or 90 days require a separate increased-risk acknowledgement. Secure tokens belong in secret storage.

Two permission layers

The API checks both token scopes and the creating user's workspace permissions.

Settings default: Schedule posts is selected and must be bound to specific profiles. Choose Prepare drafts when the agent should never publish. Publish remains a separate permission; every schedule or publish action requires a fresh prepare, visible preview and confirmation.

Quick connection · one private task

Choose 24 hours, 7 days, 30 days or 90 days. The 30-day and 90-day options require an extra risk confirmation. Paste the complete confidential setup once into the intended new private task. Quick tokens cannot be non-expiring. Revoke the connection when the task is done.

Secure connection · ongoing automation

Copy the token separately into a secret manager, encrypted credential field or KORD_WORKSPACE_API_TOKEN. Copy setup instructions without the token. A long-lived or non-expiring secure token must never enter a prompt.

Protocol

One base URL. Predictable request metadata.

Base URL

Production requests use https://app.kord.ch/api/v1. Send metadata as UTF-8 JSON over HTTPS; prepared media uses one exact raw-binary PUT. The OpenAPI document itself is public; workspace endpoints require a token.

Bearer authorization

Send Authorization: Bearer <token>. Tokens begin with kord_live_, are displayed once and must never be placed in browser code, URLs, logs or source control. Only a finite Quick setup may be pasted once into its intended private agent task; a secure token never belongs in a prompt.

Request tracing

KORD returns X-Request-Id. A caller may send its own valid request ID for correlation. Keep it when recording errors, without recording the bearer token.

Pagination and time

List endpoints return a cursor for the next page. IDs are UUIDs and timestamps are ISO 8601 UTC values; interpret scheduling with the workspace timezone returned by context.

Authorization

Bearer token

Content-Type

JSON or exact media MIME

Create safety

Idempotency-Key

Rate-limit retry

Retry-After

Quick start

Connect once, then ask for a post

  1. 1

    Copy the complete setup

    In KORD, open the workspace, then go to Settings → Agents → Quick connection. Choose the access level, concrete profiles when using planning or publishing, and an expiry. The 30-day and 90-day options require a separate increased-risk acknowledgement. Accept the warning, create the connection and select Copy complete setup. Paste it once into the intended new private agent task; never use it in a public or shared chat.
  2. 2

    Read the token manifest

    The first request tells the agent exactly which operations and scopes are available.
    curl https://app.kord.ch/api/v1/agent/manifest \
      -H "Authorization: Bearer $KORD_WORKSPACE_API_TOKEN"
  3. 3

    Read workspace context

    Never invent channel or media IDs. Read the current profiles, permissions, provider restrictions, timezone, recent posts and reusable media first.
    curl "https://app.kord.ch/api/v1/publishing/context?mediaLimit=20&postLimit=20" \
      -H "Authorization: Bearer $KORD_WORKSPACE_API_TOKEN"
  4. 4

    Create a draft with an idempotency key

    Use baseText and UUIDs returned by context. Draft creation does not require scheduling or publishing permission.
    curl -X POST https://app.kord.ch/api/v1/publishing/posts \
      -H "Authorization: Bearer $KORD_WORKSPACE_API_TOKEN" \
      -H "Content-Type: application/json" \
      -H "Idempotency-Key: campaign-draft-001" \
      -d '{
        "mode": "draft",
        "baseText": "Summer campaign draft",
        "channelIds": ["<channel UUID from context>"],
        "mediaAssetIds": ["<media UUID from context>"],
        "reason": "User asked the agent to prepare a draft."
      }'
  5. 5

    Review in KORD

    The response includes the post ID and editor URL. The draft appears in the Draft inbox, where a person can edit it, move it to the calendar, schedule it or publish it.
For ongoing automation: choose Advanced secure connection instead. Store the separately copied token in the agent's secret storage, then copy setup instructions that contain no token. Secure expiry options are 30 days, 90 days, 1 year or—after owner re-authentication and explicit acknowledgement—no expiry.

Recommended workflow

Draft first. Escalate deliberately.

  1. 01

    Read the manifest

    Confirm which tools and scopes this exact token may use.

  2. 02

    Read publishing context

    Use returned channel IDs, media IDs, permissions, provider restrictions and workspace timezone.

  3. 03

    Prepare media

    Reuse an existing asset or upload user-provided media. With media.upload, KORD automatically attaches a compatible copy when an image would otherwise fail the chosen profile format. Inspect visible images for clipped products, people, logos or meaningful text; otherwise mark visual review as pending and return the editor link.

  4. 04

    Create a draft

    Use mode: draft by default. The result appears in the workspace Draft inbox for human review.

  5. 05

    Read the result

    Use the returned post ID to read status or update the same editable post later.

Permissions

Grant only what the agent needs.

ScopeRiskAllows
publishing.readReadRead channels, schedules, recent posts and safe workspace state.
media.readReadSearch and inspect media metadata without storage keys.
media.uploadWriteUpload media and create correctly sized image copies.
post.createWriteCreate draft posts with selected channels and media.
post.scheduleElevatedSchedule posts for later using normal channel permissions.
post.publishHigh impactPublish immediately using normal channel permissions.

Endpoint reference

Public Agent API endpoints

GET/api/v1/agent/manifestpublishing.read

Discover granted tools, scopes and token-specific examples.

GET/api/v1/publishing/contextpublishing.read

Read profiles, media, limits, schedules and recent posts.

GET/api/v1/publishing/calendarpublishing.read

List visible posts in an explicit time range with cursor pagination.

GET/api/v1/media/listmedia.read

Search existing workspace media before uploading duplicates.

GET/api/v1/media/getmedia.read

Inspect one media asset by ID.

POST/api/v1/media/transformmedia.upload

Create a correctly sized image copy for one profile and post type.

POST/api/v1/media/uploadsmedia.upload

Prepare an idempotent signed streaming upload.

PUT/api/v1/media/uploads/{uploadId}/contentsigned upload token

Stream the exact raw media bytes without model context.

GET/api/v1/media/uploads/{uploadId}media.upload

Poll an owned upload operation after an ambiguous result.

POST/api/v1/media/uploads/{uploadId}/finalizemedia.upload

Validate and create exactly one media asset.

POST/api/v1/publishing/postspost.create

Create a draft. Direct V1 schedule/publish is blocked for Quick and Secure connections; legacy elevated access exists only during the controlled migration window.

GET/api/v1/publishing/posts/{postId}publishing.read

Read post, approval and publishing status.

PATCH/api/v1/publishing/posts/{postId}post.create

Update an editable draft. Use V2 prepare/confirm for schedule or publish; legacy direct publishing is migration-only.

POST/api/v2/publishing/actions/prepareelevated action

Validate an exact schedule or publish action without changing the post.

GET/api/v2/publishing/actions/{operationId}publishing.read

Poll the owned action after an ambiguous result.

POST/api/v2/publishing/actions/{operationId}/confirmelevated action

Execute only the unchanged action a user just confirmed.

Post lifecycle

Draft, schedule and publish are explicit modes.

V1 post create and update are draft-only for new Quick and Secure agent connections. Scheduling and publishing use V2 prepare/confirm and run full channel and provider validation before a job is created. Direct elevated V1 publishing exists only for legacy tokens during the controlled flag-off migration window; after cutover it returns token_migration_required. Workspace approval rules can convert an elevated request into a draft pending human approval.

ModeRequired scopesBehavior
draftpost.createSaves an editable draft. No provider request or queue job is created.
schedulepost.create + post.scheduleFor agents: prepare, show the exact preview, then confirm. KORD may hold it for approval.
publishpost.create + post.publishHigh impact. For agents: prepare, show the exact external impact, then confirm.
draft

Editable; also used while an approval is pending.

scheduled

Queued for future publishing and editable until 60 seconds before it starts.

publishing

Publishing is in progress; no longer editable.

published

Publishing completed. Inspect every variant for provider-specific evidence.

failed

Publishing failed. Inspect variant errors before editing or retrying.

cancelled

Publishing was cancelled and the post can be edited again.

Publishing evidence: after publishing, read the post and inspect every variant's externalPostId, externalUrl, publishedAt,errorMessage and attempts. A multi-profile post can have different outcomes for different providers.
Agent confirmation boundary: granting post.schedule or post.publish does not grant blanket consent. An agent first calls the V2 prepare endpoint, shows the exact profiles, text, media, concrete time, provider requirements and approval outcome, and waits for a fresh affirmative response. The matching confirm call expires after five minutes and fails if anything changed.

Per-profile variants

Use runtime capabilities, not assumptions.

Each selected profile may receive its own text, media order and options. Read channels[].postTypes, limits, permissions and launch restrictions from publishing context immediately before creating the post. Connected accounts can be more restrictive than the provider's general capability.

Instagram

Set postType from context. Optional keys include instagramUserTags and instagramVideoThumbnail. User-tag coordinates are normalized from 0 to 1.

YouTube

Use one video with postType video or short and optionally set youtubePrivacyStatus to private, unlisted or public. The first text line becomes the title; the complete text becomes the description.

TikTok

One video requires tiktokPrivacyLevel and tiktokConsent: true. Comment, Duet, Stitch, commercial-content and AI-generated declarations must match the connected creator's current restrictions.

The complete schema also covers Facebook Pages, X and LinkedIn, plus current media counts, aspect ratios, text limits and provider launch states. Use the OpenAPI schema for field-level validation and publishing context for account-level availability.

Reliability and errors

Safe retries without duplicate posts.

Idempotency-Key

Send a stable key with every post create or update. Reuse it only when retrying the exact same request; use a new key when the intended request body changes.

Request IDs

Record the X-Request-Id response header when reporting a failed request. Never include the workspace token or provider credentials in a support message.

429 rate limit

Wait for the number of seconds in Retry-After, then retry. Do not create a new Idempotency-Key for the same create operation.

401 and 403

A 401 token is invalid, expired or revoked. A 403 response names a missing scope or a workspace/channel permission that must be granted by a person.

HTTPTypical codeAction
400invalid_* / validation_failedFix the request or provider validation issues.
401missing_bearer_token / invalid_tokenUse a valid, unexpired and non-revoked workspace token.
403missing_scope / actor_*A person must grant the required token and workspace permission.
409idempotency_* / billing_*Resolve the conflict; retry only when retryable is true. X publishing can return billing_x_credits_limit_reached before anything is queued.
413file_too_largeUpload a smaller supported file.
415 / 422upload_type_mismatch / upload_*Prepare a new operation with the exact checksum and safely decodable media.
429rate_limit_exceededWait for Retry-After, then retry with backoff.
500internal_errorRetry safely and retain X-Request-Id for support.
507storage_capacity_exceededFree media capacity or add a storage pack.

Standard error envelope

{
  "status": "error",
  "error": "missing_scope:post.publish",
  "code": "missing_scope",
  "message": "This token is missing the required permission: post.publish.",
  "requestId": "24de532d-878b-441c-9858-0b27142d875e",
  "retryable": false,
  "requiredScopes": ["post.publish"]
}

Optional error fields include details, per-channel issues, requiredScopes, billing limit/maximum and current storage usage. Display message to people and retain code for program logic.

Complete examples

Create a draft from live workspace context.

Both examples discover an active writable profile before creating anything, use a unique idempotency key and stop at a human-reviewable draft. Production clients should also handle rate limits, timeouts and structured errors shown above.

JavaScript

const baseUrl = "https://app.kord.ch/api/v1";
const headers = {
  Authorization: `Bearer ${process.env.KORD_WORKSPACE_API_TOKEN}`,
  "Content-Type": "application/json",
};

const context = await fetch(`${baseUrl}/publishing/context`, { headers })
  .then(async response => {
    if (!response.ok) throw new Error(JSON.stringify(await response.json()));
    return response.json();
  });

const channel = context.data.channels.find(
  item => item.status === "active" && item.permissions.create
);

const draft = await fetch(`${baseUrl}/publishing/posts`, {
  method: "POST",
  headers: { ...headers, "Idempotency-Key": crypto.randomUUID() },
  body: JSON.stringify({
    mode: "draft",
    baseText: "Prepared for human review.",
    channelIds: [channel.id],
    reason: "The user asked the agent to prepare a draft."
  })
}).then(response => response.json());

console.log(draft.data.editorUrl);

Python

import os, uuid, requests

base_url = "https://app.kord.ch/api/v1"
session = requests.Session()
session.headers["Authorization"] = f"Bearer {os.environ['KORD_WORKSPACE_API_TOKEN']}"

context = session.get(f"{base_url}/publishing/context")
context.raise_for_status()
channel = next(c for c in context.json()["data"]["channels"]
               if c["status"] == "active" and c["permissions"]["create"])

response = session.post(
    f"{base_url}/publishing/posts",
    headers={"Idempotency-Key": f"draft-{uuid.uuid4()}"},
    json={
        "mode": "draft",
        "baseText": "Prepared for human review.",
        "channelIds": [channel["id"]],
        "reason": "The user asked the agent to prepare a draft.",
    },
)
response.raise_for_status()
print(response.json()["data"]["editorUrl"])

OpenAPI

Machine-readable specification

The OpenAPI 3.1 document defines the current request parameters, request bodies, success responses and errors for generated clients, validation and agent tool discovery. This page remains the readable explanation of the access and safety model.

KORD Workspace Agent API · OpenAPI 3.1

https://app.kord.ch/api/v1/openapi
Open JSON

Ready to connect?

Start with draft-only access.

  • One workspace per token
  • Provider secrets stay in KORD
  • Revoke access anytime