Custom Website Integration
Not using WordPress or Shopify? Connect SEO Agent to any website that has a REST API.
api Two Integration Methods
A Custom API Recommended
Already have a REST API? Connect directly with configurable endpoints and field mapping.
- ✓ Use your existing API as-is
- ✓ Flexible auth: Bearer, Basic, API Key
- ✓ Map field names to your API format
- ✓ JSON or multipart/form-data
B WordPress API Bridge
Implement WordPress REST API format on your server. More work, but full feature parity.
- ✓ Full media upload support
- ✓ Categories & tags management
- ✓ Scheduling support
- ✓ Uses same flow as WordPress sites
A Custom API Integration
settings How It Works
SEO Agent connects to your existing API and maps its own fields to your API's field names. You configure everything in the dashboard β no code changes needed on your server.
1. API Base URL
Your API endpoint
2. Authentication
Bearer, Basic, API Key
3. Field Mapping
title → tieude, etc.
4. Response Mapping
data.id, data.url, etc.
1 Setup in Dashboard
- Go to Dashboard → Publishing Sites
- Click "Add Website"
- Select platform: "Custom API"
- Fill in your API details (see configuration below)
- Click "Save" — SEO Agent will test the connection automatically
2 Configuration Reference
Authentication Types
| Type | Header Sent | Use Case |
|---|---|---|
| Bearer Token | Authorization: Bearer <token> | Direct token or SHA-256(contract_id + secret) |
| Basic Auth | Authorization: Basic base64(user:pass) | Username + password |
| API Key | X-API-Key: <key> (configurable header name) | API key in custom header |
| None | (no auth header) | Public API or IP-whitelisted |
Field Mapping
Map SEO Agent's fields to your API's field names. Leave empty to skip a field.
| SEO Agent Field | Default | Example Custom | Description |
|---|---|---|---|
| title | title | tieude | Article title |
| content | content | noidung | HTML content body |
| excerpt | excerpt | mota | Short description |
| slug | slug | slug | URL-friendly slug |
| featured_image | featured_image | photo | Image URL or file field |
| seo_title | seo_title | title | SEO <title> tag |
| seo_keywords | seo_keywords | keyword | Meta keywords |
| seo_description | seo_description | description | Meta description |
| tags | tags | tags | Comma-separated tags |
| category | category | category | Category name |
Response Mapping (dot notation)
Tell SEO Agent where to find the post ID and URL in your API's response. Use dot notation for nested fields.
{
"status": 200,
"message": "Success",
"data": {
"id": 123,
"namevi": "Article Title",
"slugvi": "article-slug"
}
}
Post ID: data.id # extracts 123
Post URL: data.slugvi # extracts "article-slug"
Post Title: data.namevi # extracts "Article Title"
Post Slug: data.slugvi # extracts "article-slug"
3 Real-World Example
Here's how to configure SEO Agent for a custom Vietnamese CMS API:
Base URL: https://yoursite.com/api/v1
Auth: Bearer Token (SHA-256 of contract_id + secret)
Create Post: POST /post/create (multipart/form-data)
Update Post: POST /post/edit/{id}
Delete Post: DELETE /post/{id}
List Posts: GET /posts
# Connection
API Base URL: https://yoursite.com/api/v1
Authentication: Bearer Token
Contract ID: 25916725
Secret: YOUR_SECRET_KEY
(token = SHA-256 of "25916725" + "YOUR_SECRET_KEY")
Content-Type: multipart/form-data
# Endpoints
Create: /post/create
Update: /post/edit/{id}
Delete: /post/{id}
List (for test): /posts
# Field Mapping
title → tieude
content → noidung
excerpt → mota
slug → slug
image → photo
seo_title → title
seo_keywords → keyword
seo_desc → description
# Response Mapping
Post ID: data.id
Post URL: data.slugvi
Post Title: data.namevi
Post Slug: data.slugvi
What SEO Agent sends: When publishing an article, SEO Agent sends a POST request to https://yoursite.com/api/v1/post/create with your Bearer token and fields mapped to your API format.
checklist Minimum API Requirements
Your API needs at minimum:
A "create post" endpoint
Accepts title + HTML content, returns a post ID in the response.
A "list/test" endpoint
Any GET endpoint that returns HTTP 200 when authenticated. Used to test the connection.
JSON response with post ID (recommended)
SEO Agent needs to know the created post's ID for tracking. Return it somewhere in the JSON response.
Note: Categories, tags, media upload, and page creation are handled automatically when available in your API. If not, SEO Agent will skip those features gracefully.
bug_report Testing Your API
Test your API with cURL before adding to SEO Agent:
# Bearer Token auth
curl -H "Authorization: Bearer YOUR_TOKEN" \
https://yoursite.com/api/v1/posts
# Basic Auth
curl -u "username:password" \
https://yoursite.com/api/v1/posts
# API Key auth
curl -H "X-API-Key: YOUR_KEY" \
https://yoursite.com/api/v1/posts
# Create a test post (JSON)
curl -X POST https://yoursite.com/api/v1/post/create \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"tieude":"Test","noidung":"<p>Hello</p>"}'
# Create a test post (multipart)
curl -X POST https://yoursite.com/api/v1/post/create \
-H "Authorization: Bearer YOUR_TOKEN" \
-F "tieude=Test" \
-F "noidung=<p>Hello</p>"
B WordPress API Bridge
Alternative: implement the WordPress REST API format on your custom server. This gives full feature parity (media uploads, categories, tags, scheduling) but requires more development work.
lock Base URL & Authentication
All endpoints must be under the /wp-json/wp/v2/ path. Authentication uses HTTP Basic Auth.
# Base URL
https://yoursite.com/wp-json/wp/v2/
# Authentication Header
Authorization: Basic base64("username:app_password")
Tip: When adding your site in SEO Agent, select "WordPress" as platform and enter the same username and password. SEO Agent will send them as Basic Auth on every request.
route Required Endpoints
Implement these WordPress-compatible endpoints:
| Method | Endpoint | Purpose |
|---|---|---|
| GET | /wp-json/wp/v2/users/me | Auth test |
| POST | /wp-json/wp/v2/posts | Create post |
| POST | /wp-json/wp/v2/posts/{id} | Update post |
| GET | /wp-json/wp/v2/posts | List posts |
| POST | /wp-json/wp/v2/media | Upload image |
| POST | /wp-json/wp/v2/categories | Create category |
| POST | /wp-json/wp/v2/tags | Create tag |
For detailed request/response format for each endpoint, refer to the WordPress REST API documentation.
code Code Examples (WordPress API Bridge)
Choose your framework below. Each example shows how to set up the WordPress-compatible API routes on your server.
const express = require('express');
const multer = require('multer');
const app = express();
const upload = multer({ dest: 'uploads/' });
app.use(express.json());
// Middleware: Basic Auth
function auth(req, res, next) {
const header = req.headers.authorization || '';
if (!header.startsWith('Basic ')) return res.status(401).json({
code: 'rest_not_logged_in', message: 'Unauthorized', data: {status: 401}
});
const [user, pass] = Buffer.from(header.slice(6), 'base64')
.toString().split(':');
// TODO: validate user:pass from your database
if (!isValidUser(user, pass)) return res.status(401).json({
code: 'rest_not_logged_in', message: 'Invalid credentials', data: {status: 401}
});
req.userId = getUserId(user);
next();
}
// 1. Auth test
app.get('/wp-json/wp/v2/users/me', auth, (req, res) => {
res.json({ id: req.userId, name: 'Admin', slug: 'admin', roles: ['administrator'] });
});
// 2. Create post
app.post('/wp-json/wp/v2/posts', auth, (req, res) => {
const { title, content, status, excerpt, slug, categories, tags, featured_media } = req.body;
// TODO: insert into your database
const post = createPost({ title, content, status, excerpt, slug, categories, tags, featured_media });
res.status(201).json({
id: post.id,
title: { raw: post.title, rendered: post.title },
slug: post.slug,
link: `https://yoursite.com/${post.slug}/`,
status: post.status
});
});
// 3. Update post
app.post('/wp-json/wp/v2/posts/:id', auth, (req, res) => {
const post = updatePost(req.params.id, req.body);
res.json({ id: post.id, title: { raw: post.title, rendered: post.title }, slug: post.slug });
});
// 4. List posts
app.get('/wp-json/wp/v2/posts', auth, (req, res) => {
const { per_page = 10, page = 1, status } = req.query;
const { posts, total } = listPosts({ per_page, page, status });
res.set('X-WP-Total', total);
res.set('X-WP-TotalPages', Math.ceil(total / per_page));
res.json(posts);
});
// 5. Upload media
app.post('/wp-json/wp/v2/media', auth, upload.single('file'), (req, res) => {
const { title, alt_text, post } = req.body;
// TODO: move file to public folder, save to DB
const media = saveMedia(req.file, { title, alt_text, post_id: post });
res.status(201).json({ id: media.id, source_url: media.public_url });
});
// 6. Categories
app.get('/wp-json/wp/v2/categories', auth, (req, res) => {
const cats = listCategories(req.query);
res.json(cats); // [{id, name, slug, count}, ...]
});
app.post('/wp-json/wp/v2/categories', auth, (req, res) => {
const existing = findCategoryBySlug(req.body.slug || slugify(req.body.name));
if (existing) return res.status(400).json({
code: 'term_exists', message: 'Category exists', data: { term_id: existing.id }
});
const cat = createCategory(req.body);
res.status(201).json(cat);
});
// 7. Tags
app.get('/wp-json/wp/v2/tags', auth, (req, res) => {
const tags = searchTags(req.query); // supports ?search= and ?slug=
res.json(tags);
});
app.post('/wp-json/wp/v2/tags', auth, (req, res) => {
const existing = findTagByName(req.body.name);
if (existing) return res.status(400).json({
code: 'term_exists', message: 'Tag exists', data: { term_id: existing.id }
});
const tag = createTag(req.body);
res.status(201).json(tag);
});
// 8. Delete post
app.delete('/wp-json/wp/v2/posts/:id', auth, (req, res) => {
deletePost(req.params.id);
res.json({ deleted: true, id: parseInt(req.params.id) });
});
app.listen(3000);
bug_report Testing WordPress API Bridge
Use cURL to verify each endpoint before connecting to SEO Agent:
# 1. Test auth
curl -u "admin:yourpassword" https://yoursite.com/wp-json/wp/v2/users/me
# 2. Create a test post
curl -u "admin:yourpassword" -X POST https://yoursite.com/wp-json/wp/v2/posts \
-H "Content-Type: application/json" \
-d '{"title":"Test Post","content":"<p>Hello</p>","status":"draft"}'
# 3. Upload an image
curl -u "admin:yourpassword" -X POST https://yoursite.com/wp-json/wp/v2/media \
-F "[email protected]" -F "title=Test Image" -F "alt_text=Test"
# 4. Create a category
curl -u "admin:yourpassword" -X POST https://yoursite.com/wp-json/wp/v2/categories \
-H "Content-Type: application/json" -d '{"name":"Tech","slug":"tech"}'
Tip: When adding the site in SEO Agent, select "WordPress" as platform (not Custom API). SEO Agent will communicate using the standard WordPress REST API format.
check_circle Which Method Should I Choose?
Choose Custom API (Option A) if:
- ✓ You already have a REST API
- ✓ You want minimal development effort
- ✓ You only need article publishing
- ✓ Your API uses Bearer/Basic/API Key auth
Choose WP Bridge (Option B) if:
- ✓ You need full media upload (images to your server)
- ✓ You need category/tag auto-creation
- ✓ You want scheduled post support
- ✓ You're building a new API from scratch
Need help? Contact us at [email protected]