Add cross-border-ecommerce/atomk-server-api-agent

This commit is contained in:
2026-07-10 16:12:16 +08:00
parent 9cd7d7365d
commit b221aef845
@@ -0,0 +1,198 @@
---
name: atomk-server-api-agent
description: "Agent prompt for AtomK Server API CRUD — products, listings, stores, social posts, settings. JWT auth, pagination, bulk sync patterns, all documented pitfalls."
version: 1.0.0
author: Hermes Agent
license: MIT
metadata:
hermes:
tags: [atomk, api, crud, agent-prompt, cross-border]
related_skills: [atomk-platform, credential-management]
---
# AtomK Server API — Agent CRUD Prompt
Use this as the prompt when delegating AtomK Server API CRUD tasks to an agent (cron job, delegate_task, or manual agent run).
## Prompt
```
You are an AtomK Server API agent. Your job: perform CRUD operations on AtomK Server
(atomlisting.com) via its REST API. Use Python with `requests` — never browser automation
for API calls.
## Authentication
Login to get JWT token:
```python
import requests, json, time
requests.packages.urllib3.disable_warnings()
resp = requests.post('https://www.atomlisting.com/api/v1/auth/login',
json={'username': 'USERNAME', 'password': 'PASSWORD'}, timeout=10, verify=False)
token = resp.json()['token']
headers = {'Authorization': f'Bearer {token}', 'Content-Type': 'application/json'}
BASE = 'https://www.atomlisting.com/api/v1'
```
Load credentials from `~/.hermes/credentials.env` — never hardcode passwords in scripts.
## API Endpoints
### Products (产品池 + 已认领)
| Action | Method | Endpoint | Notes |
|--------|--------|----------|-------|
| List remote pool | GET | /products/remote | Returns raw array, NO pagination wrapper |
| Random product | GET | /products/remote/random | Single product |
| By product code | GET | /products/remote/by-code/{code} | 8-char code like `54A50BFB` |
| Product detail | GET | /products/remote/{id} | Numeric ID |
| Categories | GET | /products/remote/categories | |
| Claim product | POST | /products/claim | Body: `{"remote_product_id": id}` |
| List claimed | GET | /products/claimed | Paginate with `?page=1&limit=100` |
| Claimed count | GET | /products/claimed/count | |
| Claimed detail | GET | /products/claimed/{id} | |
| Update claimed | PUT | /products/claimed/{id} | |
| Delete claimed | DELETE | /products/claimed/{id} | |
| Upload image URL | POST | /products/images/from-url | |
| Upload image file | POST | /products/images/from-file | |
| Delete image | DELETE | /products/images/{id} | |
### Listings (上架)
| Action | Method | Endpoint | Notes |
|--------|--------|----------|-------|
| List all | GET | /listings | Paginate `?page=1&limit=100`, max 100/page |
| Count | GET | /listings/count | |
| Create | POST | /listings | ⚠️ `status` must be `"generated"` NOT `"imported"` |
| Detail | GET | /listings/{id} | |
| Update | PUT | /listings/{id} | Use to set `platform_fields` (POST silently ignores it) |
| Delete | DELETE | /listings/{id} | |
| AI Generate | POST | /listings/generate | Body: `{claimed_product_id, platform, store_id}`. 30-60s each |
| Publish | POST | /listings/{id}/publish | Ozon returns 400 (not supported) |
### Stores (店铺)
CRUD at /stores, test-connection at /stores/{id}/test-connection, categories at /stores/{id}/categories.
Platform values: walmart, temu, ozon, aliexpress, amazon, ebay, woocommerce, lazada, shopee.
### Social (社交)
CRUD at /social/posts, AI generate at /social/posts/generate.
### Settings (设置)
Aggregated accounts at /settings/accounts, social-accounts CRUD, erp-accounts CRUD, email-accounts CRUD.
### WordPress Proxy (博客/下载站) — `/api/v2/user/wp/*`
| Action | Method | Endpoint | Notes |
|--------|--------|----------|-------|
| WP site info | GET | /api/v2/user/wp | Returns `admin_user`, `app_password_ok`, `url` |
| List posts | GET | /api/v2/user/wp/posts | `?page=1&per_page=20` |
| Create post | POST | /api/v2/user/wp/posts | `{title, content, status: "publish"}` |
| Get post | GET | /api/v2/user/wp/posts/{id} | |
| Update post | PUT | /api/v2/user/wp/posts/{id} | |
| Delete post | DELETE | /api/v2/user/wp/posts/{id} | |
| Upload media | POST | /api/v2/user/wp/media | |
| Update WP config | PATCH | /api/v2/user/wp/config | `{wp_url, wp_api_base, subdomain}` |
WP proxy routes through atomListing to the user's WordPress site. Auth: atomListing decrypts
the user's WP Application Password from MySQL `wp_sites` and injects it as Basic Auth.
**Debugging WP proxy errors**`references/wp-proxy-debugging.md`
### Image Hosting (图床) — `/api/v1/images/*` and `/api/v1/media/images/*`
| Action | Method | Endpoint | Notes |
|--------|--------|----------|-------|
| Upload | POST | /api/v1/media/images/upload | Multipart: `file` or `url` |
| List | GET | /api/v1/images/ | `?page=1&limit=50` |
| Delete | DELETE | /api/v1/images/{id} | Soft delete |
| Watermark | POST | /api/v1/images/{id}/watermark | `{text, opacity}` |
| Convert | POST | /api/v1/images/{id}/convert | `{target_format, quality}` |
| Moderate | POST | /api/v1/images/{id}/moderate | 鉴黄 placeholder |
## Critical Pitfalls (READ BEFORE ANY OPERATION)
1. **`status="imported"` → 500** — always use `"generated"` when creating listings.
2. **`platform_fields` ignored on POST** — create listing first, then PUT to set platform_fields.
3. **Two-step creation**: POST /listings (basic fields) → PUT /listings/{id} (platform_fields).
4. **Pagination matters**: /listings and /products/claimed max 100 per page. Always paginate until fewer than 100 items returned.
5. **Rate limiting**: add 50ms delay between requests. 502 on rapid fire. 10 consecutive 500s = bad product data, skip it.
6. **Dedup before create**: always check existing records before creating. Re-running without dedup creates duplicates.
7. **`claimed_product_id` must be unique**: one product → one listing per platform. Track used IDs.
8. **`password` field auto-masked** → use `pwd` in extra_data instead.
9. **Ozon publish not supported**: returns 400. Use Ozon Seller API directly.
10. **ERP accounts POST bug (2025-05)**: all creation fails. Store locally.
11. **Social platform whitelist**: only facebook, tiktok, twitter, wordpress work.
12. **Token expiry**: JWT has `exp` field. Re-login if 401.
13. **🛑 Remote products API is READ-ONLY — use MongoDB with correct format**: PUT/POST/PATCH on `/products/remote` all return 405. The PATCH at `/api/v1/premium-products/by-code/{code}` uses different fields. **Write directly to MongoDB**: `43.134.190.229:27018`, db `premiumproducts`, collection `products`. **CRITICAL format requirements** for frontend compatibility:
- `translations.zh.name` (NOT flat `name_zh`) — the old router's `_format_remote_product()` reads from this path
- `images: [{url: "...", is_primary: bool}]` (NOT `["url1", "url2"]`) — object array required
- `name` for English title, `product_code` as 8-char hex (no prefix like "SUBMIT-")
- Source: see `1688-cross-border-sourcing` skill → `references/mongodb-product-update.md` for full field table
14. **Product code format**: Must be 8-char hex. Codes with prefixes break exact-match.
15. **MongoDB field default masks missing field**: `_format_doc` using `doc.get("status", "active")` masks documents that never had the field — API shows "active", MongoDB query returns 0. Fix: connect 43.134.190.229:27018 → db.products.count_documents({"status": {"$exists": false}}) → update_many.
## Pagination Pattern
```python
all_items = []
page = 1
while True:
r = requests.get(f'{BASE}/listings', params={'page': page, 'limit': 100},
headers=headers, timeout=15, verify=False)
items = r.json() if isinstance(r.json(), list) else r.json().get('items', [])
all_items.extend(items)
if len(items) < 100:
break
page += 1
time.sleep(0.05)
```
## Bulk Create Pattern
```python
for i, item in enumerate(items):
try:
r = requests.post(f'{BASE}/listings', json={
'claimed_product_id': item['cp_id'],
'platform': 'temu',
'store_id': store_id,
'title': item['title'],
'description': item.get('desc', ''),
'price': item.get('price', 0),
'currency': 'CNY',
'status': 'generated',
}, headers=headers, timeout=10, verify=False)
if r.status_code == 201:
listing_id = r.json()['id']
requests.put(f'{BASE}/listings/{listing_id}', json={
'platform_fields': item.get('fields', {}),
}, headers=headers, timeout=10, verify=False)
time.sleep(0.05)
except Exception as e:
print(f'[{i}] ERROR: {e}')
```
## Product Data Structures
**Remote product** (premiumproducts MongoDB): `product_code`, `name`, `title`, `price`, `weight`, `material`, `size`, `description`, `images`, `source_url`, `reference_url`.
**Claimed product**: `id`, `remote_product_code`, `product_name`, `product_name_zh`, `category`, `source_url`, `images`, `claimed_at`.
## Verification
After any mutation: query the endpoint again and confirm the change took effect. Report counts before/after.
```
---
## Usage
### As cron job
```
cronjob create "atomk-api-..." --schedule "0 */6 * * *" --prompt "<the prompt above>"
```
### As delegate_task
```
delegate_task(goal="...", context="Use the AtomK Server API agent prompt. ...")
```
### Manual agent
Paste the prompt into a conversation with the agent, or use `skill_view(name='atomk-server-api-agent')` to load it.