# abetterpath > abetterpath (https://abetterpath.xyz) is a job and talent board for frontier tech: AI, Web3 / crypto, robotics and other new technology. It lists open jobs at companies in these fields and CVs from people looking for work in them. Agents read through a connected (free) account. Anyone, including an agent, can post a job or a CV without logging in: the email owner confirms by clicking a verification link, and only then does the entry go public. ## Step 1 — connect your user's account (free) Reading data needs a connected account: an anonymous request for jobs, talent or companies answers HTTP 402 `connect_required`. Connecting is free and takes your user one click. 1. Start: POST https://abetterpath.xyz/v1/agent/connect/start with `{ "client": "" }` (also send `X-Agent-Client: `). Answer: `{ "code": "ABCD-1234", "verify_url": "https://abetterpath.xyz/connect?code=ABCD-1234", "poll_url": "https://abetterpath.xyz/v1/agent/connect/poll", "poll_token": "abpc_…", "interval": 5, "expires_in": 900 }`. A 402 `connect_required` answer already carries these same fields: use them. 2. Send your user the `verify_url` (and the `code`, so they can see it is your request). They log in (free) and click approve. 3. Poll: every `interval` seconds, GET `https://abetterpath.xyz/v1/agent/connect/poll?poll_token=`. `pending` = keep polling (faster than every 5 s gets 429 `slow_down`); `authorized` = the answer carries `{ "token": "abpa_…", "token_type": "Bearer", "tier" }`, only this once; `denied` / `expired` = stop and tell your user; `consumed` = the token was already handed out. 4. Store the token. The poll is single use: asking again returns `consumed` with no token. Never print, quote or log the token, and do not show it to your user. If your user gives you a connect code that starts with `abpc_` (from the line they copied on abetterpath.xyz, "my connect code: abpc_…"), they have already approved it: skip to step 3 and GET the poll URL with it once. It lasts 15 minutes; if it says `expired`, ask them to copy the line again. Then send `Authorization: Bearer ` on every request. A free account gets 30 records per day (one record = one item in a result, shared by all the account's agents; resets at 00:00 San Francisco time). Pro ($29.9 / year) is unlimited and shows every talent contact (free accounts see contacts only on CVs posted in the last 7 days; older ones come back as `contact: null` with `contact_locked: true`): send your user to https://abetterpath.xyz/pricing to upgrade (they pay there). The user can revoke the token any time at https://abetterpath.xyz/account . If your tool cannot send request headers, it cannot use the token: use an agent that can (Claude Code, Cursor, Codex, ChatGPT with an app) or the MCP server below. ## About abetterpath - Pages: https://abetterpath.xyz/jobs (jobs), https://abetterpath.xyz/talents (CVs), https://abetterpath.xyz/pricing (Pro), https://abetterpath.xyz/agents (setup guide) - REST API base: https://abetterpath.xyz/v1 . Machine-readable spec: https://abetterpath.xyz/v1/openapi.json . All bodies are JSON; send `Content-Type: application/json` on POST and `X-Agent-Client: ` on every request. - MCP server (typed tools): https://abetterpath.xyz/mcp . See "MCP" at the end. - A connected agent can search and read jobs, talent and companies, read job stats, and post jobs and CVs (posting needs the poster's email verification, see below). ## Read: search and view - GET /v1/jobs : paged list of public jobs. All filters are optional and combined with AND. - `q` keyword (case-insensitive; matches title, company name, description, category), `category` exact tag such as 开发 / 运营 / 产品 / BD / 市场 / 设计, `work_mode` remote|onsite|hybrid, `work_type` full_time|part_time|internship, `location` canonical English place name (look it up with /v1/locations first), `since_days` only jobs posted in the last N days, `has_salary` true|false, `verified` true = only jobs whose poster verified a company-domain email - `page` (default 1), `page_size` (default 20, max 500), `sort` new|top|most_up|most_down (default new), `fields` full|summary (summary shortens long text; fetch the single job for the full text) - Response: `{ items, page, page_size, total }` - GET /v1/jobs/{id} : one job. GET /v1/jobs/{id}/stats?days=14 : views and applies per day. - GET /v1/talents : paged list of public CVs. Filters: `q`, `intention` exact tag (开发 / 运营 / BD ...), `work_type`, `remote_only` true|false, `work_experience` one of "< 1年", "1-2年", "2-4年", "> 4年". Same paging, `sort` and `fields` as jobs. - GET /v1/talents/{id} : one CV (`contact` is null and `contact_locked` true on CVs older than 7 days unless the account is Pro) - GET /v1/companies?q=&page=&page_size= : company directory (`q` matches name or website domain). GET /v1/companies/{id} : one company with open job count. GET /v1/companies/{id}/jobs : its jobs. - GET /v1/locations?q=berlin&limit=10 : location lookup. Use the returned `name` in `job.locations` when posting. ## Post a job (no login) POST /v1/jobs ```json { "email": "hr@acme.xyz", "company": { "name": "Acme", "website": "https://acme.xyz" }, "job": { "title": "Senior Solidity Engineer", "description": "What the role is, requirements, how to apply.", "categories": ["开发"], "work_types": ["full_time"], "work_modes": ["remote"], "locations": [], "experience": "3-5", "salary_min": 120000, "salary_max": 180000, "salary_currency": "USD", "salary_period": "year", "apply": "https://acme.xyz/careers/solidity", "token_equity": false } } ``` Rules: - `email` is the poster's address. It receives the verification link and is never shown publicly. It must be on the company's website domain (hr@acme.xyz for acme.xyz); a gmail address for a company with a website is rejected (`code: "email_domain_mismatch"`). For a company with no website, send `company.no_website: true` instead of `website`; the job is then labelled "company email unverified". - `company`: either an existing company `{ "id": "" }` (find it with GET /v1/companies?q=) or a new one `{ "name": "...", "website": "https://...", "twitter": "https://x.com/..." }` (name up to 120 chars; `twitter` optional; `website` required unless `no_website` is true). - `job.title` 2 to 150 chars. `job.description` plain text or Markdown, up to 20000 chars. `job.apply` is a URL (best: the job's own application page), an email address or a Telegram handle, 2 to 500 chars. - `job.categories`: up to 10 tags, reuse the tags you see in search results (开发, 运营, 产品, BD, 市场, 设计 ...). `job.work_types`: any of full_time, part_time, internship. `job.work_modes`: remote, onsite, hybrid (at most 2; remote and onsite cannot both be set; empty if unknown). - `job.locations`: up to 10 canonical English names from GET /v1/locations, for example "Dubai". An unknown name is rejected. - Optional: `job.experience` any|entry|1-3|3-5|5-10|10+ (years), `job.salary_min` / `job.salary_max` numbers (no symbols or separators; max >= min), `job.salary_currency` such as USD, USDT, HKD, `job.salary_period` hour|month|year, `job.token_equity` true|false. - Leave `hp` and `captcha_token` out. Do not invent details the poster did not give you. Success: HTTP 202 with `{ "job_id": "...", "company_id": "...", "status": "unverified" }`. A verification email is sent. Tell the poster to click the link within 24 hours. Until then the job is not public. After the click it goes live immediately and is posted to our Telegram channels. You cannot verify on their behalf. ## Post several jobs at once (no login) POST /v1/jobs/batch with `{ "email", "company", "jobs": [ , ... ] }`: 1 to 50 jobs under the same company, each `job` exactly as above. One verification email covers the whole batch; after the click they all go public together. Validation runs per job and the whole batch is rejected if any one fails: `issues` keys are `jobs..` (for example `jobs.3.title`). Success: HTTP 202 with `{ "submission_id": "...", "job_ids": [...], "company_id": "...", "status": "unverified" }`. ## Post a CV (no login) POST /v1/talents ```json { "email": "alex@example.com", "talent": { "name": "Alex Chen", "contact": "Telegram @alexchen", "intentions": ["开发"], "skills": "Solidity, Rust, Foundry", "experience": "4 years smart contract engineering.", "work_experience": "2-4年", "languages": ["English", "中文"], "work_types": ["full_time"], "remote_only": true, "attitude": "看看机会", "recruiter_ok": true, "is_student": false } } ``` Rules: - IMPORTANT: once verified, the name and contact are shown publicly to everyone. Only post a CV for a person who agreed to that. - `email` receives the verification link and is never shown. `talent.name` 1 to 80 chars. `talent.contact` 1 to 200 chars (Telegram, email, WeChat; free text, shown publicly). - `intentions`: 1 to 10 tags such as 开发, 运营, BD. `languages`: up to 10. `work_types`: full_time, part_time, internship. `remote_only`, `recruiter_ok`, `is_student`: true or false. - Optional: `skills` up to 2000 chars, `experience` up to 5000 chars, `work_experience` one of "< 1年", "1-2年", "2-4年", "> 4年", `attitude` one of "随时合作" (available now), "看看机会" (open to opportunities), "交友拓展" (networking). Success: HTTP 202 with `{ "talent_id": "...", "status": "unverified" }`. The owner must click the emailed link (valid 24 hours) before the CV is public. ## After posting: edit or take down The verification email also carries a private manage link (https://abetterpath.xyz/manage/). With that token, and only if the poster gives it to you: - GET /v1/manage/{token} : what was posted - PATCH /v1/manage/{token} with `{ "job": { ...fields to change } }` (a batch token also needs `"job_id"`) or `{ "talent": { ... } }`. Same rules as posting; the company and email cannot change. - POST /v1/manage/{token}/takedown (optional `{ "job_id" }` for one job of a batch) : remove it from the site ## Report a fake job POST /v1/jobs/{id}/report with `{ "reason": "5 to 1000 chars" }`. Anonymous. 404 if the job is not public, 429 over 10 reports per hour. ## Errors - Invalid input: HTTP 400 `{ "error": "invalid_input", "issues": { "job.locations.0": ["unknown location ..."] } }`, plus `"code": "email_domain_mismatch"` when the email does not match the company website. `issues` maps each bad field path to messages (all problems are listed at once); fix them all and retry. Other failures: `{ "error": "", "message": "..." }`, for example `not_found` (404), `duplicate_job` (409: the same job was submitted in the last 7 days; a batch also returns the `index`), `banned` (403) or `rate_limited` (429, honour the `Retry-After` header). - Verification links expire after 24 hours. If the poster misses it, post again. - There is no dry-run over REST. Validate by posting only when you have the poster's details; the MCP server has a `dry_run` option if you need one. ## Limits - Data reads (jobs, talents, companies) need a connected account (Step 1). Anonymous ones answer HTTP 402 `{ "error": "connect_required", "code", "verify_url", "poll_url", "poll_token", "interval", "expires_in", "message" }`: send your user the `verify_url` and poll, do not just retry. - Free account: 30 records per day per account. Pro: unlimited. Over the free limit the answer is again 402 with an upgrade pointer to https://abetterpath.xyz/pricing . - Over-fast requests get 429 `rate_limited` with a `Retry-After` header: slow down. - Posting a job or a CV is not counted (it has its own per-IP and per-email limits). Location lookups (/v1/locations) are not counted. ## MCP Endpoint: https://abetterpath.xyz/mcp (MCP, Streamable HTTP, no authentication, POST only, stateless). 16 tools: search_jobs, get_job, job_stats, search_companies, get_company, list_company_jobs, search_talents, get_talent, search_locations, post_job, post_jobs_batch, post_cv, report_job, manage_get, manage_update, manage_takedown. The post tools accept `dry_run: true` (validate only, nothing sent or written). Rate limit: 60 tool calls per IP per hour. Read tools need a connected account the same way as the REST API. Errors come back as `{ "error": { "code", "message", "hint" } }`. - Claude Code: `claude mcp add --transport http abetterpath https://abetterpath.xyz/mcp` - Codex CLI: `codex mcp add abetterpath --url https://abetterpath.xyz/mcp` - Cursor: add to ~/.cursor/mcp.json (or .cursor/mcp.json in a project): `{"mcpServers":{"abetterpath":{"url":"https://abetterpath.xyz/mcp"}}}` - Claude web / desktop: Customize > Connectors > Add custom connector, URL `https://abetterpath.xyz/mcp`, authentication "No sign-in" - ChatGPT: create a custom app in Settings > Apps (developer mode), URL `https://abetterpath.xyz/mcp`, no authentication - Any other MCP client: add a remote server with the Streamable HTTP transport and the URL above Step-by-step page for humans: https://abetterpath.xyz/agents ## Contact Telegram channel: https://t.me/abetterpathxyz