Home Feed 🎬 Shorts Login

Publishing API

Approved organisation pages can publish to Vise automatically β€” from a CMS, an RSS tool or a script. Automation is welcome when it is honest: every API post shows a small β€œvia API” label, and pages never get paid reach.

Interactive reference (OpenAPI): /api/docs

1. Get an API key

2. Endpoints

Method & pathAuthPurpose
GET /api/v1/pages/{handle}β€”Public page info
GET /api/v1/pages/{handle}/postsβ€”Public posts of the page
POST /api/v1/pages/{handle}/mediaAPI keyUpload one image (multipart field β€œfile”), returns an image id
POST /api/v1/pages/{handle}/postsAPI keyPublish a post (JSON)
GET /api/v1/pages/{handle}/posts/{id}β€”One post
PATCH /api/v1/pages/{handle}/posts/{id}API keyEdit a post; only the fields you send change (PUT and POST to the same URL work too). Shown as β€œedited”.
DELETE /api/v1/pages/{handle}/posts/{id}API keyDelete a post (with its comments and images)

Post fields

bodyText (required unless images are attached). #hashtags become topics.
title, kindkind: text | longform (longform needs a title)
visibilitypublic (default) | members
languagee.g. de, en, hu
media_ids, altUp to 4 image ids from /media, plus one description
linkCanonical article URL, appended to the body
link_previewtrue = show a preview card (title, summary, picture from your page's Open Graph tags) for link. Default false β€” useful when you don't upload an image yourself.
content_labelsnudity | erotic | graphic if they apply

Text is plain text: HTML tags are removed and HTML entities (e.g. ö, …) are decoded automatically. Line breaks are kept.

Limits & errors

3. Examples

# 1) upload an image (optional)
curl -X POST http://vise.social/api/v1/pages/pesterlloyd/media \
  -H "X-Vise-Api-Key: $VISE_KEY" -F "[email protected]"
# β†’ {"id": "img_…", "url": "/media/img_…/medium", "width": 1080, "height": 720}

# 2) publish
curl -X POST http://vise.social/api/v1/pages/pesterlloyd/posts \
  -H "X-Vise-Api-Key: $VISE_KEY" -H "Content-Type: application/json" \
  -d '{"kind": "longform", "title": "Schlagzeile", "body": "Teaser … #ungarn",
       "language": "de", "link": "https://www.pesterlloyd.net/…",
       "media_ids": ["img_…"], "alt": "Parlament in Budapest"}'

WordPress

A minimal plugin: publish new WordPress posts to Vise (title, excerpt, link, featured image), update them when edited, delete them when trashed. Store the key in wp-config.php as VISE_API_KEY.

<?php
/**
 * Plugin Name: Vise Publisher
 * Description: Publishes and updates posts on the Vise page via the Vise API.
 */
const VISE_BASE = 'http://vise.social';
const VISE_PAGE = 'pesterlloyd';

function vise_text($html) {
    return trim(html_entity_decode(wp_strip_all_tags($html), ENT_QUOTES | ENT_HTML5, 'UTF-8'));
}

function vise_upload_image($attachment_id) {
    $path = get_attached_file($attachment_id);
    if (!$path) return null;
    $ch = curl_init(VISE_BASE . '/api/v1/pages/' . VISE_PAGE . '/media');
    curl_setopt_array($ch, [
        CURLOPT_POST => true,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPHEADER => ['X-Vise-Api-Key: ' . VISE_API_KEY],
        CURLOPT_POSTFIELDS => ['file' => new CURLFile($path)],
    ]);
    $res = json_decode(curl_exec($ch), true);
    curl_close($ch);
    return $res['id'] ?? null;
}

function vise_payload($post) {
    $thumb_id = get_post_thumbnail_id($post->ID);
    $media_id = $thumb_id ? vise_upload_image($thumb_id) : null;
    return [
        'kind' => 'longform',
        'title' => vise_text(get_the_title($post)),
        'body' => vise_text(get_the_excerpt($post)),
        'link' => get_permalink($post),
        'language' => 'de',
        'media_ids' => $media_id ? [$media_id] : [],
        'alt' => $thumb_id ? vise_text(get_post_meta($thumb_id, '_wp_attachment_image_alt', true)) : '',
    ];
}

function vise_request($method, $path, $payload = null) {
    return wp_remote_request(VISE_BASE . '/api/v1/pages/' . VISE_PAGE . $path, [
        'method' => $method,
        'headers' => ['X-Vise-Api-Key' => VISE_API_KEY, 'Content-Type' => 'application/json'],
        'body' => $payload ? wp_json_encode($payload) : null,
        'timeout' => 20,
    ]);
}

// Publish new posts; edit already-sent posts; delete on trash.
add_action('transition_post_status', function ($new, $old, $post) {
    if ($post->post_type !== 'post') return;
    $vise_id = get_post_meta($post->ID, '_vise_post_id', true);

    if ($new === 'publish' && !$vise_id) {
        $res = vise_request('POST', '/posts', vise_payload($post));
        if (!is_wp_error($res) && wp_remote_retrieve_response_code($res) === 201) {
            update_post_meta($post->ID, '_vise_post_id', json_decode(wp_remote_retrieve_body($res), true)['id']);
        }
    } elseif ($new === 'trash' && $vise_id) {
        vise_request('DELETE', '/posts/' . $vise_id);
        delete_post_meta($post->ID, '_vise_post_id');
    }
}, 10, 3);

add_action('post_updated', function ($post_id, $after, $before) {
    $vise_id = get_post_meta($post_id, '_vise_post_id', true);
    if (!$vise_id || $after->post_status !== 'publish' || $after->post_type !== 'post') return;
    vise_request('PATCH', '/posts/' . $vise_id, vise_payload($after));
}, 10, 3);

Questions or need more endpoints (e.g. editing, deleting)? [email protected]