API Developer Guide
Base URL: https://powerdigital.sg/api/v1/ · All responses are JSON · UTF-8
This API powers the Power Digital CMS. Read endpoints are public (no auth). Write endpoints
(create / update / delete articles and categories) require HTTP Basic Auth with the
seo-agent credentials. All POST/PATCH bodies must be application/json.
Dates are ISO 8601. UUIDs are used as primary keys for write operations.
Write endpoints use HTTP Basic Auth. Encode username:password in base64
and pass it in the Authorization header. The SEO agent account is pre-provisioned on the server.
seo-agent / Password: provided separately by the project owner.On the server, run
python manage.py create_seo_agent to provision the user.
# -u flag encodes username:password automatically curl -s -u "seo-agent:<password>" \ -X POST "https://powerdigital.sg/api/v1/articles/" \ -H "Content-Type: application/json" \ -d '{"title": "My Article"}'
import requests AUTH = ("seo-agent", "<password>") BASE = "https://powerdigital.sg/api/v1" r = requests.post(f"{BASE}/articles/", json={"title": "My Article"}, auth=AUTH) r.raise_for_status() article = r.json()
# 401 — missing or wrong credentials {"error": "Invalid credentials."} # 409 — slug conflict {"error": "Slug 'my-slug' already exists."}
Returns service status. Use this before any write operation to confirm the API is reachable.
curl -s "https://powerdigital.sg/api/v1/health/"
{
"status": "ok",
"service": "powerdigital-api",
"version": "1.0"
}
Blog posts. GET endpoints are public and filterable. POST/PATCH/DELETE require seo-agent auth.
The UUID returned in id is used for write operations; the slug is used for public reads.
List published articles. Use query params to filter.
| Param | Type | Description |
|---|---|---|
status | string | Filter by status: published (default), draft, archived, all |
category | slug | Filter by category slug |
tag | slug | Filter by tag slug |
search | string | Full-text search on title, slug, excerpt, content |
featured | bool | 1 or 0 |
limit | int | Page size 1–100 (default 20) |
offset | int | Pagination offset (default 0) |
include_content | bool | 1 to include full HTML body |
curl -s "https://powerdigital.sg/api/v1/articles/?status=all&limit=10&include_content=1"
Fetch a single article by slug. Always includes full content.
curl -s "https://powerdigital.sg/api/v1/articles/my-article-slug/"
Create a new article. title is the only required field. Slug is auto-generated from title if omitted.
Tags are auto-created if they don't exist. Image URLs are fetched and saved locally.
The CMS renders
content directly as HTML. Sending Markdown (e.g. # Heading, **bold**, - list) will appear as raw text on the page. Always convert to HTML before posting: use <h2>, <strong>, <ul><li>, <p>, etc.
{
"title": "How to rank on Google in Singapore", // required
"slug": "rank-on-google-singapore", // optional — auto from title
"content": "<h2>Section Heading</h2><p>Body paragraph.</p>", // HTML only — no Markdown
"excerpt": "Short summary shown in listings.",
"status": "published", // draft | published | archived
"is_featured": false,
"published_at": "2026-06-21T00:00:00Z", // ISO 8601 — defaults to now if published
"categories": ["seo", "digital-marketing"], // category slugs (must exist)
"tags": ["seo", "google-ranking", "singapore"], // tag slugs — auto-created
"meta_title": "Rank on Google Singapore | Power Digital",
"meta_description": "Learn how to rank #1 on Google...",
"meta_keywords": ["seo singapore", "google ranking"],
"og_title": "Rank on Google Singapore",
"og_description": "Our proven SEO framework...",
"featured_image_url": "https://example.com/image.jpg", // fetched + saved locally
"long_image_url": "https://example.com/long.jpg",
"og_image_url": "https://example.com/og.jpg"
}
curl -s -u "seo-agent:<password>" \ -X POST "https://powerdigital.sg/api/v1/articles/" \ -H "Content-Type: application/json" \ -d '{"title":"My Article","status":"published","tags":["seo"]}'
Returns 201 with the full article object including its id (UUID). Save this for PATCH/DELETE.
Partial update — only send the fields you want to change. Use the id UUID from the create response.
ARTICLE_ID="839fd4bd-36d3-4b5a-aee8-a389998f787f" curl -s -u "seo-agent:<password>" \ -X PATCH "https://powerdigital.sg/api/v1/articles/${ARTICLE_ID}/" \ -H "Content-Type: application/json" \ -d '{"status":"published","is_featured":true}'
Permanently delete an article. Returns {"deleted": true, "id": "..."}.
curl -s -u "seo-agent:<password>" \ -X DELETE "https://powerdigital.sg/api/v1/articles/${ARTICLE_ID}/"
Article categories with optional parent/child hierarchy and featured image.
| Param | Description |
|---|---|
parent=root | Only top-level categories (no parent) |
parent=<slug> | Children of a specific category |
search | Search name, slug, description |
include_content=1 | Include full content field |
curl -s "https://powerdigital.sg/api/v1/categories/?parent=root"
Returns the category plus its children and a list of articles in that category.
curl -s "https://powerdigital.sg/api/v1/categories/seo/?article_limit=5"
{
"name": "SEO", // required
"slug": "seo", // optional — auto from name
"description": "Search engine optimisation articles.",
"excerpt": "Short listing summary.",
"content": "<p>Long HTML description.</p>",
"parent": "digital-marketing", // parent category slug
"featured_image_url": "https://example.com/seo.jpg", // fetched + saved locally
"meta_title": "SEO Articles | Power Digital",
"meta_description": "Expert SEO tips and strategies.",
"meta_keywords": ["seo", "search engine optimisation"]
}
curl -s -u "seo-agent:<password>" \ -X POST "https://powerdigital.sg/api/v1/categories/" \ -H "Content-Type: application/json" \ -d '{"name":"SEO","description":"SEO articles"}'
Partial update. Same fields as POST, all optional. Use UUID from create response.
Delete a category. Articles in this category lose the category association (M2M).
Returns available time slots for a given date.
curl -s "https://powerdigital.sg/api/v1/bookings/available-slots/?date=2026-07-01"
{
"full_name": "Jane Smith",
"email": "jane@example.com",
"phone": "+65 9123 4567",
"date": "2026-07-01",
"start_time": "10:00",
"message": "Looking for SEO services."
}
CMS pages. Params: status, search, limit, offset, include_content.
Single page with full block data.
CMS content blocks. Params: type, active, include_data=1.
curl -s "https://powerdigital.sg/api/v1/blocks/?type=home_hero&include_data=1"
Generate SEO suggestions for a given content snippet.
{
"content": "Your page content here..."
}
| Field | Type | Required | Notes |
|---|---|---|---|
title | string | required | Max 255 chars |
slug | string | optional | Auto-generated from title. Must be unique. |
content | HTML string | optional | HTML only. Rendered directly — Markdown is not parsed. Use <h2>/<p>/<ul> etc. |
excerpt | string | optional | Plain-text summary for listings (no HTML needed). |
status | enum | optional | draft (default) · published · archived |
type | enum | optional | post (default) · page |
is_featured | bool | optional | Pinned to top of blog listing. |
published_at | ISO 8601 | optional | Defaults to now when status = published. |
categories | slug[] | optional | Array of existing category slugs. |
tags | slug[] | optional | Array of tag slugs. Auto-created if not found. |
meta_title | string | optional | Override <title> tag. |
meta_description | string | optional | <meta name="description"> |
meta_keywords | string[] | optional | Array of keyword strings. |
og_title | string | optional | Open Graph title override. |
og_description | string | optional | Open Graph description override. |
featured_image_url | URL | optional | Remote image — fetched and saved locally (10 MB cap). |
long_image_url | URL | optional | Tall format image for listings. |
og_image_url | URL | optional | Social share image. |
| Field | Type | Required | Notes |
|---|---|---|---|
name | string | required | Max 100 chars |
slug | string | optional | Auto-generated from name. Must be unique. |
description | string | optional | Plain text description. |
excerpt | string | optional | Short listing text. |
content | HTML string | optional | Long-form HTML description. |
parent | slug | optional | Parent category slug. Omit for top-level. |
featured_image_url | URL | optional | Remote image — fetched and saved locally. |
meta_title | string | optional | |
meta_description | string | optional | |
meta_keywords | string[] | optional |
Each service page automatically shows articles whose tags match its cluster list. Tag your articles with these slugs to have them appear on the relevant service page.
| Service | URL | Tags to use on articles |
|---|---|---|
| Web Development | /services/web-development-singapore/ |
web-development · web-design · website-design-singapore · performance-optimisation · ecommerce · cms |
| Web Applications | /services/web-application-development/ |
web-application · saas · platform-development · custom-software · django · nodejs |
| Mobile Apps | /services/mobile-application-development/ |
mobile-app · flutter · ios-development · android-development · react-native · mobile-development |
| 3D Development | /services/3d-development/ |
3d-development · webgl · unity · virtual-reality · augmented-reality · immersive |
| Game Development | /services/game-development/ |
game-development · mobile-games · unity-game · gamification · educational-games |
| SEO | /services/seo/ |
seo · digital-marketing · search-engine-optimisation · content-strategy · keyword-research · link-building |
curl -s -u "seo-agent:<password>" \ -X POST "https://powerdigital.sg/api/v1/articles/" \ -H "Content-Type: application/json" \ -d '{ "title": "10 SEO Tips for Singapore Businesses", "status": "published", "tags": ["seo", "digital-marketing", "keyword-research"], "categories": ["seo"], "meta_description": "Proven SEO strategies for Singapore SMEs." }'
This article will automatically appear in the "Further Resources" section at the bottom of
/services/seo/ once it is published.