9.2 KiB
name, description, version, author, license, metadata
| name | description | version | author | license | metadata | |||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| atomk-server-api-agent | Agent prompt for AtomK Server API CRUD — products, listings, stores, social posts, settings. JWT auth, pagination, bulk sync patterns, all documented pitfalls. | 1.0.0 | Hermes Agent | MIT |
|
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)
status="imported"→ 500 — always use"generated"when creating listings.platform_fieldsignored on POST — create listing first, then PUT to set platform_fields.- Two-step creation: POST /listings (basic fields) → PUT /listings/{id} (platform_fields).
- Pagination matters: /listings and /products/claimed max 100 per page. Always paginate until fewer than 100 items returned.
- Rate limiting: add 50ms delay between requests. 502 on rapid fire. 10 consecutive 500s = bad product data, skip it.
- Dedup before create: always check existing records before creating. Re-running without dedup creates duplicates.
claimed_product_idmust be unique: one product → one listing per platform. Track used IDs.passwordfield auto-masked → usepwdin extra_data instead.- Ozon publish not supported: returns 400. Use Ozon Seller API directly.
- ERP accounts POST bug (2025-05): all creation fails. Store locally.
- Social platform whitelist: only facebook, tiktok, twitter, wordpress work.
- Token expiry: JWT has
expfield. Re-login if 401. - 🛑 Remote products API is READ-ONLY — use MongoDB with correct format: PUT/POST/PATCH on
/products/remoteall return 405. The PATCH at/api/v1/premium-products/by-code/{code}uses different fields. Write directly to MongoDB:43.134.190.229:27018, dbpremiumproducts, collectionproducts. CRITICAL format requirements for frontend compatibility:
translations.zh.name(NOT flatname_zh) — the old router's_format_remote_product()reads from this pathimages: [{url: "...", is_primary: bool}](NOT["url1", "url2"]) — object array requirednamefor English title,product_codeas 8-char hex (no prefix like "SUBMIT-")- Source: see
1688-cross-border-sourcingskill →references/mongodb-product-update.mdfor full field table
- Product code format: Must be 8-char hex. Codes with prefixes break exact-match.
- MongoDB field default masks missing field:
_format_docusingdoc.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
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
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 ""
### 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.