Files

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
hermes
tags related_skills
atomk
api
crud
agent-prompt
cross-border
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 errorsreferences/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
  1. Product code format: Must be 8-char hex. Codes with prefixes break exact-match.
  2. 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

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.