GUIDES for developers

Gan Jing World — Article Upload API Guide

This guide describes the complete workflow for programmatically publishing article content to a Gan Jing World channel account using the Platform API.


Overview

Publishing an article to Gan Jing World is a 5-step process that spans two API hosts:

HostPurposeAuthorization
gw.ganjingworld.comPlatform API — authentication, content managementRaw ACCESS_TOKEN (no Bearer prefix)
imgapi.cloudokyo.cloudImage CDN — poster and inline image upload and resizingBearer <UPLOAD_TOKEN>

Important: The Platform API (gw.ganjingworld.com) expects the raw access token in the Authorization header. The CDN API (cloudokyo.cloud) expects a Bearer prefix. Mixing these up will cause 401 errors.

Workflow Summary

1. Authenticate            →  Obtain ACCESS_TOKEN + REFRESH_TOKEN
2. Get Upload Token        →  Exchange ACCESS_TOKEN for UPLOAD_TOKEN
3. Upload Images           →  Upload poster image and all inline article images
4. Create Article Content  →  Create article entry with HTML body via /add-content
5. Update Article Content  →  (Optional) Update the article via /update-content

Key Difference from Video Upload: Articles do not require video file upload (TUS protocol), upload ID registration, or transcoding status polling. The article is published as soon as the /add-content call succeeds.


Step 1: Authentication

Initial Login

Obtain your ACCESS_TOKEN and REFRESH_TOKEN through the Gan Jing World login flow. These tokens are typically extracted from the browser session after logging into your channel account.

Please log in or create a new account to get the token.

Token Refresh

Access tokens expire after approximately 10 days. Refresh tokens remain valid for 3 months. Use the refresh endpoint to obtain a new access token before it expires.

curl -X POST 'https://gw.ganjingworld.com/v1.1/auth/token/refresh' \
  -H 'Content-Type: application/json' \
  -d '{"refresh_token": "<REFRESH_TOKEN>"}'

Response:

{
  "access_token": "<NEW_ACCESS_TOKEN>",
  "refresh_token": "<NEW_REFRESH_TOKEN>",
  "expires_in": 864000
}

Note: The response may wrap tokens in a body or data field depending on the API version. Check data.access_token, body.access_token, and the top-level access_token field. The expires_in value is in seconds (864000 = 10 days). Always store and use the new refresh token from the response, as the previous one may be invalidated.

Best Practice: Implement proactive token refresh — refresh the token when it is within 1 hour of expiry rather than waiting for a 401 error. If you do receive a 401, refresh the token and retry the request once.


Step 2: Get Upload Token (VOD Token)

Exchange your access token for a short-lived upload token used with the CDN APIs.

curl -X GET 'https://gw.ganjingworld.com/v1.0c/get-vod-token' \
  -H 'Authorization: <ACCESS_TOKEN>' \
  -H 'Accept: application/json'

Note: The Authorization header uses the raw access token — do NOT include a Bearer prefix.

Response:

{
  "body": {
    "token": "<UPLOAD_TOKEN>"
  },
  "status_code": 200
}

Note: The token may appear at different paths in the response: body.token, data.token, body.upload_token, or body.vod_token. Check multiple paths for robustness.

The UPLOAD_TOKEN is used for all subsequent CDN image upload operations.


Step 3: Upload Images

Articles require image uploads for two purposes:

  1. Poster image — The thumbnail/cover image displayed in listings and at the top of the article.
  2. Inline images — Any images embedded within the article HTML body.

Both types use the same image upload endpoint on the CDN.

Upload an Image

curl -X POST 'https://imgapi.cloudokyo.cloud/api/v2/image' \
  -H 'Authorization: Bearer <UPLOAD_TOKEN>' \
  -H 'resizing-list: 140,240,360,380,480,580,672,960,1280,1920' \
  -F 'file=@"image.jpg"'

Important notes:

  • The endpoint is /api/v2/image (not /api/v1/image).
  • Only send the file field in the multipart form — do NOT include a name field.
  • Authorization uses Bearer <UPLOAD_TOKEN>.

Response:

{
  "body": {
    "image_id": "abc123",
    "image_url": [
      "https://image5-us-west.cloudokyo.cloud/.../140.jpg",
      "https://image5-us-west.cloudokyo.cloud/.../240.webp",
      "https://image5-us-west.cloudokyo.cloud/.../480.jpg",
      "https://image5-us-west.cloudokyo.cloud/.../480.webp",
      "https://image5-us-west.cloudokyo.cloud/.../672.webp",
      "https://image5-us-west.cloudokyo.cloud/.../960.webp",
      "https://image5-us-west.cloudokyo.cloud/.../1280.webp",
      "https://image5-us-west.cloudokyo.cloud/.../1920.webp",
      "https://image5-us-west.cloudokyo.cloud/.../origin.webp"
    ]
  },
  "file_upload": "abc123",
  "status_code": 200
}

Selecting Poster URLs

From the image_url array of the poster image upload, select two URLs:

FieldSize KeyPurpose
poster_url672.webpStandard definition poster (used in listings)
poster_hd_urlorigin.webpHigh definition poster (used on article page)

Fallback order for poster_url: 672 → 480 → 580 → 360 → 240 → 140 Fallback order for poster_hd_url: origin → 1920 → 1280 → 960 → 672

Prefer .webp over .jpg when both are available at the same size.

Using Inline Image URLs in Article Body

For images embedded in the article HTML body, use the appropriate size URL from the upload response. Reference these URLs directly in <img> tags within the meta.text HTML content (see Step 4).

Example inline image tag:

<img src="https://image1-us-east.cloudokyo.cloud/image/v14/.../960.webp" alt="Description" />

Important: All images that need to be embedded in the article body must be uploaded through the imgapi.cloudokyo.cloud image upload process first. Do not reference external image URLs that have not been uploaded to the CDN.


Step 4: Create Article Content

Create the article content entry with metadata and the HTML body. This uses the same /add-content endpoint as video upload, but with type set to "News" and the article body provided in the meta.text field.

curl -X POST 'https://gw.ganjingworld.com/v1.0c/add-content' \
  -H 'Authorization: <ACCESS_TOKEN>' \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json' \
  -H 'Cache-Control: no-cache' \
  -H 'Origin: https://studio.ganjingworld.com' \
  -d '{
    "user_id2": "<CHANNEL_ID>",
    "type": "News",
    "mode": "ready",
    "lang": "en-US",
    "category_id": "cat22",
    "title": "Article Title Here",
    "description": "Optional short description or summary",
    "visibility": "public",
    "poster_url": "https://image1-us-east.cloudokyo.cloud/.../672.webp",
    "poster_hd_url": "https://image1-us-east.cloudokyo.cloud/.../origin.webp",
    "meta": {
      "text": "<p style=\"margin-left:0px;\">Your article HTML content here...</p>"
    },
    "keywords": [],
    "hashtags": ["#topic1", "#topic2"],
    "premium": 0,
    "use_schedule": false,
    "made_for_kids": false,
    "user_made_for_kids": false,
    "protected_type": "",
    "slug": "",
    "deleteTranslations": []
  }'

Key Differences from Video Upload:

  • type is "News" (not "Video").
  • mode is set to "ready" — this indicates the article content is complete and ready to publish. (For video uploads, mode is typically omitted to allow auto-publish after transcoding.)
  • The meta object with a text field contains the full article body as HTML.
  • No video file upload or transcoding is needed — the article is published once this call succeeds.

Request Body Fields

FieldTypeRequiredDescription
user_id2stringYesYour GJW channel ID
typestringYesAlways "News" for articles
modestringYesSet to "ready" for immediate publish
langstringYesLanguage code (e.g., "en-US")
category_idstringYesContent category (e.g., "cat22")
titlestringYesArticle title
descriptionstringNoShort description or summary (can be empty string)
visibilitystringYes"public", "unlisted", or "private"
poster_urlstringYesStandard poster URL (from Step 3)
poster_hd_urlstringYesHD poster URL (from Step 3)
metaobjectYesContains the text field with article HTML body
meta.textstringYesFull article content as HTML (see format below)
keywordsarrayNoList of keyword strings
hashtagsarrayNoList of hashtag strings (e.g., ["#topic"])
premiumnumberNo0 for free content, 1 for premium
use_schedulebooleanNoWhether to use scheduled publishing
time_schedulednumberNoUnix timestamp in milliseconds for scheduled publish time (only used if use_schedule is true)
made_for_kidsbooleanYesWhether content is made for children
user_made_for_kidsbooleanYesWhether the creator marked it as for children
protected_typestringNoContent protection type (empty string for none)
slugstringNoCustom URL slug (empty string for auto-generated)
deleteTranslationsarrayNoList of translation language codes to delete
thumbnail_scoreobjectNoThumbnail quality score with raw_score (float) and score (int)

Article HTML Body Format (meta.text)

The meta.text field accepts HTML content. The following HTML elements and patterns are supported:

Paragraphs:

<p style="margin-left:0px;">Paragraph text here.</p>

Links:

<a target="_blank" rel="noopener noreferrer" href="https://example.com">Link text</a>

Inline images (uploaded via Step 3):

<img src="https://image1-us-east.cloudokyo.cloud/image/v14/.../960.webp" alt="Description" />

Bold / Italic / Underline:

<strong>Bold text</strong>
<em>Italic text</em>
<u>Underlined text</u>

HTML entities: Use &amp; for &, &nbsp; for non-breaking spaces, etc.

Example full meta.text value:

<p style="margin-left:0px;">
  First paragraph of the article with <strong>bold text</strong> and a
  <a target="_blank" rel="noopener noreferrer" href="https://example.com">link</a>.
</p>
<p style="margin-left:0px;">&nbsp;</p>
<p style="margin-left:0px;">Second paragraph continues the article content.</p>

Note: Empty paragraphs with &nbsp; can be used as spacers between content blocks.

Response:

{
  "content_id": "<CONTENT_ID>",
  "owner_id": "<CHANNEL_ID>",
  "type": "News",
  "title": "Article Title Here",
  "visibility": "public",
  "created_at": "2025-01-15T10:30:00Z"
}

Note: The content_id may also appear at data.content_id, data.id, or id depending on the response structure.


Step 5: Update Article Content (Optional)

To update an existing article (e.g., fix typos, update content, change metadata), use the /update-content endpoint with the CONTENT_ID from Step 4.

curl -X POST 'https://gw.ganjingworld.com/v1.0c/update-content' \
  -H 'Authorization: <ACCESS_TOKEN>' \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json' \
  -d '{
    "content_id": "<CONTENT_ID>",
    "user_id2": "<CHANNEL_ID>",
    "type": "News",
    "mode": "ready",
    "title": "Updated Article Title",
    "description": "Updated description",
    "meta": {
      "text": "<p style=\"margin-left:0px;\">Updated article HTML content...</p>"
    },
    "poster_url": "https://image1-us-east.cloudokyo.cloud/.../672.webp",
    "poster_hd_url": "https://image1-us-east.cloudokyo.cloud/.../origin.webp",
    "visibility": "public",
    "category_id": "cat22",
    "lang": "en-US",
    "keywords": [],
    "hashtags": ["#updated"],
    "made_for_kids": false,
    "user_made_for_kids": false
  }'

Note: Include all fields you want to preserve in the update request — fields not included may be reset to defaults.


Published Article URL

After successful creation, the article is accessible at:

https://www.ganjingworld.com/news/<CONTENT_ID>

Comparison: Article vs. Video Upload

AspectArticle (News)Video (Video)
Content type"News""Video"
Mode"ready"Omit (auto-publish after transcode)
Body contentmeta.text (HTML)Video file (TUS upload)
Image uploadPoster + inline images via CDNPoster only via CDN
Video uploadNot requiredTUS resumable upload required
Upload ID registrationNot requiredRequired (Step 5 in video guide)
Transcoding / pollingNot requiredRequired (poll until .m3u8 URL)
Steps to publish4 (auth → token → images → create)8 (auth → token → thumbnail → create → register → upload → poll → finalize)
Published URL path/news/<CONTENT_ID>/video/<CONTENT_ID>

Error Handling Best Practices

  1. Token Expiry: Proactively refresh tokens within 1 hour of expiry. Implement 401 retry as a safety net.
  2. Image Upload Failures: Retry with exponential backoff on 5xx errors. Verify the returned image_url array contains the expected sizes before proceeding.
  3. HTML Content Validation: Ensure all image URLs in meta.text point to successfully uploaded CDN images. Broken image references will result in missing images in the published article.
  4. Large Articles: For articles with many inline images, upload all images first and collect all CDN URLs before constructing the meta.text HTML body.
  5. Special Characters: Properly escape special characters in the JSON payload — use &amp; for & in HTML, and escape quotes in the JSON string (\").
  6. Non-ASCII Content: Ensure the request uses UTF-8 encoding for international content.
Copyright © 2026