← Back to Skills Marketplace
vndck

Automate your Job Search

by VNDCK · GitHub ↗ · v1.0.7 · MIT-0
cross-platform ✓ Security Clean
345
Downloads
0
Stars
0
Active Installs
8
Versions
Install in OpenClaw
/install auto-apply
Description
Automate your job search and application process with Mokaru. Search thousands of jobs, tailor your resume to each role, track applications through your pipe...
README (SKILL.md)

\r \r

Mokaru Job Search & Application Tracker\r

\r You can search for jobs, save and track job applications, and read the user's career profile through the Mokaru API.\r \r Important: This skill does NOT submit job applications on behalf of the user. It helps with the preparation: finding jobs, saving them to a tracker, updating application status, and reviewing the user's profile. The user (or their browser agent) must visit the applyLink from search results to actually apply. When the user says "apply", save the job to their tracker and provide the apply link so they can complete the application themselves.\r \r

Authentication\r

\r Every request requires a Bearer token. The token is stored in the MOKARU_API_KEY environment variable and starts with mk_.\r \r Include this header on all requests:\r \r

Authorization: Bearer $MOKARU_API_KEY\r
```\r
\r
## Base URL\r
\r
```\r
https://api.mokaru.ai\r
```\r
\r
All endpoints are under `/v1/`.\r
\r
---\r
\r
## Endpoints\r
\r
### 1. Search Jobs\r
\r
**When to use:** The user wants to find job listings. They might say "find me React jobs in New York" or "search for remote marketing roles."\r
\r
**Method:** `POST /v1/jobs/search`\r
\r
**Required scope:** `jobs:search`\r
\r
**Rate limit:** 30 requests per minute\r
\r
**Request body (JSON):**\r
\r
| Field               | Type     | Required | Description                                                        |\r
|---------------------|----------|----------|--------------------------------------------------------------------|\r
| `query`             | string   | Yes      | Job search keywords (e.g. "software engineer")                     |\r
| `location`          | string   | No       | City, state, or country (e.g. "San Francisco, CA")                 |\r
| `remote`            | boolean  | No       | Filter for remote jobs only                                        |\r
| `workArrangement`   | string   | No       | One of: `remote`, `hybrid`, `onsite`                               |\r
| `employmentType`    | string   | No       | E.g. "fulltime", "parttime", "contract"                            |\r
| `datePosted`        | string   | No       | Recency filter (e.g. "today", "3days", "week", "month")            |\r
| `salaryMin`         | number   | No       | Minimum annual salary filter                                       |\r
| `country`           | string   | No       | Country code or name                                               |\r
| `benefits`          | string[] | No       | Required benefits to filter on                                     |\r
| `includeKeywords`   | string[] | No       | Keywords that must appear in the job                               |\r
| `excludeKeywords`   | string[] | No       | Keywords that must NOT appear in the job                           |\r
| `includeCompanies`  | string[] | No       | Limit to specific companies                                        |\r
| `excludeCompanies`  | string[] | No       | Exclude specific companies                                         |\r
| `cursor`            | string   | No       | Opaque pagination cursor from a previous response's `nextCursor`   |\r
\r
**Curl example:**\r
\r
```bash\r
curl -s -X POST https://api.mokaru.ai/v1/jobs/search \\r
  -H "Authorization: Bearer $MOKARU_API_KEY" \\r
  -H "Content-Type: application/json" \\r
  -d '{\r
    "query": "frontend engineer",\r
    "location": "New York",\r
    "remote": true\r
  }' | jq .\r
```\r
\r
**Response shape:**\r
\r
```json\r
{\r
  "data": [\r
    {\r
      "id": "clx...",\r
      "title": "Frontend Engineer",\r
      "company": "Acme Corp",\r
      "companyLogo": "https://...",\r
      "companyWebsite": "https://...",\r
      "location": "New York, NY",\r
      "city": "New York",\r
      "state": "NY",\r
      "country": "US",\r
      "isRemote": true,\r
      "employmentType": "fulltime",\r
      "applyLink": "https://...",\r
      "applyIsDirect": false,\r
      "publisher": "LinkedIn",\r
      "description": "\x3Cp>We are looking for a Frontend Engineer...\x3C/p>",\r
      "highlights": { "qualifications": [...], "responsibilities": [...] },\r
      "benefits": ["Health insurance", "401k"],\r
      "salaryMin": 120000,\r
      "salaryMax": 160000,\r
      "salaryPeriod": "year",\r
      "postedAt": "2026-03-10T..."\r
    }\r
  ],\r
  "total": 142,\r
  "hasMore": true,\r
  "nextCursor": "eyJwYWdlIjoyfQ=="\r
}\r
```\r
\r
**Pagination:** Pass the `nextCursor` from a response as `cursor` in the next request to fetch more results. When `hasMore` is `false`, `nextCursor` is `null`.\r
\r
**How to use the results:** Present jobs in a readable list. Include the title, company, location, salary range (if available), and the apply link. If `hasMore` is true, fetch the next page with `cursor`.\r
\r
---\r
\r
### 2. Create Application\r
\r
**When to use:** The user wants to save or track a job. They might say "save this job" or "add this to my tracker." You can also use this right after a search to save a result.\r
\r
**Method:** `POST /v1/tracker/applications`\r
\r
**Required scope:** `tracker:write`\r
\r
**Rate limit:** 20 requests per minute\r
\r
**Request body (JSON):**\r
\r
| Field            | Type   | Required | Description                                                                                      |\r
|------------------|--------|----------|--------------------------------------------------------------------------------------------------|\r
| `jobTitle`       | string | Yes      | Job title (max 200 chars)                                                                        |\r
| `company`        | string | Yes      | Company name (max 200 chars)                                                                     |\r
| `location`       | string | No       | Job location (max 200 chars)                                                                     |\r
| `jobUrl`         | string | No       | URL of the job posting (max 2000 chars, must be a valid URL). Used for duplicate detection       |\r
| `jobDescription` | string | No       | Full job description text (max 50,000 chars). Required (non-empty) for `autoPrepare`.            |\r
| `jobListingId`   | string | No       | If saving from a Mokaru search result, pass the job's `id` to automatically pull salary/details  |\r
| `source`         | string | No       | One of: `LinkedIn`, `CompanyWebsite`, `JobWebsite`, `Referral`, `Agency`, `Other`. Defaults to `Other` |\r
| `autoPrepare`    | boolean | No      | When `true`, Mokaru duplicates the user's default resume and tailors it to the job description using AI. Requires Plus plan, a default resume, and a non-empty job description. |\r
\r
**Curl example:**\r
\r
```bash\r
curl -s -X POST https://api.mokaru.ai/v1/tracker/applications \\r
  -H "Authorization: Bearer $MOKARU_API_KEY" \\r
  -H "Content-Type: application/json" \\r
  -d '{\r
    "jobTitle": "Frontend Engineer",\r
    "company": "Acme Corp",\r
    "location": "New York, NY",\r
    "jobUrl": "https://acme.com/careers/frontend",\r
    "jobListingId": "clx...",\r
    "source": "JobWebsite",\r
    "autoPrepare": true\r
  }' | jq .\r
```\r
\r
**Response shape:**\r
\r
```json\r
{\r
  "success": true,\r
  "applicationId": "clx...",\r
  "existing": false,\r
  "autoPrepare": true\r
}\r
```\r
\r
If `existing` is `true`, the application was already tracked (matched by `jobUrl`) and the existing ID is returned. No duplicate is created.\r
\r
If `autoPrepare` is `true` in the response, Mokaru is tailoring the user's resume in the background (~30 seconds). The application status will be `preparing` until done.\r
\r
**Auto-prep errors:** If auto-prep fails, the API returns a clear error code:\r
- `PLAN_REQUIRED` (403) - user needs a Plus plan\r
- `NO_DEFAULT_RESUME` (400) - user must set a default resume in Mokaru first\r
- `JOB_DESCRIPTION_TOO_SHORT` (400) - job description is missing or empty\r
\r
**Workflow tip:** When saving a job from search results, pass the `id` from the search result as `jobListingId`. This auto-fills salary and description data. Add `"autoPrepare": true` to also tailor the resume automatically.\r
\r
---\r
\r
### 3. List Applications\r
\r
**When to use:** The user wants to see their tracked applications. They might ask "show my applications" or "what jobs have I applied to?"\r
\r
**Method:** `GET /v1/tracker/applications`\r
\r
**Required scope:** `tracker:read`\r
\r
**Rate limit:** 60 requests per minute\r
\r
**Query parameters:**\r
\r
| Param    | Type   | Required | Description                                                   |\r
|----------|--------|----------|---------------------------------------------------------------|\r
| `status` | string | No       | Filter by status (see status values below)                    |\r
| `limit`  | number | No       | Results per page, default 25, max 100                         |\r
| `offset` | number | No       | Number of results to skip for pagination                      |\r
\r
**Valid status values:** `watchlist`, `preparing`, `applied`, `response`, `screening`, `interview_scheduled`, `interviewed`, `offer`, `negotiating`, `accepted`, `rejected`, `withdrawn`, `no_response`\r
\r
**Curl example:**\r
\r
```bash\r
curl -s -G https://api.mokaru.ai/v1/tracker/applications \\r
  -H "Authorization: Bearer $MOKARU_API_KEY" \\r
  --data-urlencode "status=applied" \\r
  --data-urlencode "limit=10" | jq .\r
```\r
\r
**Response shape:**\r
\r
```json\r
{\r
  "data": [\r
    {\r
      "id": "clx...",\r
      "jobTitle": "Frontend Engineer",\r
      "company": "Acme Corp",\r
      "location": "New York, NY",\r
      "jobUrl": "https://acme.com/careers/frontend",\r
      "status": "applied",\r
      "source": "JobWebsite",\r
      "priority": 3,\r
      "salaryMin": 120000,\r
      "salaryMax": 160000,\r
      "appliedDate": "2026-03-10T...",\r
      "createdAt": "2026-03-10T...",\r
      "updatedAt": "2026-03-12T..."\r
    }\r
  ],\r
  "total": 24,\r
  "hasMore": true,\r
  "limit": 10,\r
  "offset": 0\r
}\r
```\r
\r
**How to present:** Show the list as a table or concise summary. Include status, company, job title, and any salary info. If `hasMore` is true, let the user know there are more results.\r
\r
---\r
\r
### 4. Get Application Detail\r
\r
**When to use:** The user wants to see the full detail of a specific application, including its timeline, interviews, and notes. They might say "show me the details of my Acme application" or "what's the status of that job?"\r
\r
**Method:** `GET /v1/tracker/applications/{id}`\r
\r
**Required scope:** `tracker:read`\r
\r
**Rate limit:** 60 requests per minute\r
\r
**Curl example:**\r
\r
```bash\r
curl -s https://api.mokaru.ai/v1/tracker/applications/clx_abc123 \\r
  -H "Authorization: Bearer $MOKARU_API_KEY" | jq .\r
```\r
\r
**Response shape:**\r
\r
```json\r
{\r
  "data": {\r
    "id": "clx_abc123",\r
    "jobTitle": "Frontend Engineer",\r
    "company": "Acme Corp",\r
    "location": "New York, NY",\r
    "jobUrl": "https://acme.com/careers/frontend",\r
    "jobDescription": "We are looking for...",\r
    "status": "interviewed",\r
    "source": "JobWebsite",\r
    "priority": 5,\r
    "notes": "Great conversation with hiring manager",\r
    "salaryMin": 120000,\r
    "salaryMax": 160000,\r
    "salaryPeriod": "year",\r
    "cvId": "clx_cv456",\r
    "appliedDate": "2026-03-10T...",\r
    "createdAt": "2026-03-10T...",\r
    "updatedAt": "2026-03-15T...",\r
    "timeline": [\r
      {\r
        "id": "tl1",\r
        "status": "interviewed",\r
        "description": "status_changed",\r
        "createdAt": "2026-03-15T..."\r
      }\r
    ],\r
    "interviews": [\r
      {\r
        "id": "int1",\r
        "round": 1,\r
        "type": "video",\r
        "date": "2026-03-14T10:00:00.000Z",\r
        "notes": "Technical interview",\r
        "contact": {\r
          "id": "ct1",\r
          "firstName": "Sarah",\r
          "lastName": "Jones",\r
          "jobTitle": "Engineering Manager"\r
        }\r
      }\r
    ]\r
  }\r
}\r
```\r
\r
**How to use:** Present the application details clearly. Highlight the current status, upcoming interviews (with dates and contacts), and any notes. If the user has interviews coming up, suggest they prepare.\r
\r
---\r
\r
### 5. Update Application\r
\r
**When to use:** The user wants to change the status, priority, notes, or details of a tracked application. They might say "mark that application as interviewed" or "set priority to high."\r
\r
**Method:** `PATCH /v1/tracker/applications/{id}`\r
\r
**Required scope:** `tracker:write`\r
\r
**Rate limit:** 20 requests per minute\r
\r
**Request body (JSON) - all fields optional, at least one required:**\r
\r
| Field      | Type   | Description                                           |\r
|------------|--------|-------------------------------------------------------|\r
| `status`   | string | New status (see valid status values above)            |\r
| `priority` | number | 1 (lowest) to 5 (highest)                            |\r
| `notes`    | string | Free-text notes (max 5,000 chars)                     |\r
| `jobTitle` | string | Updated job title (max 200 chars)                     |\r
| `company`  | string | Updated company name (max 200 chars)                  |\r
| `location` | string | Updated location (max 200 chars)                      |\r
\r
**Curl example:**\r
\r
```bash\r
curl -s -X PATCH https://api.mokaru.ai/v1/tracker/applications/clx_abc123 \\r
  -H "Authorization: Bearer $MOKARU_API_KEY" \\r
  -H "Content-Type: application/json" \\r
  -d '{\r
    "status": "interviewed",\r
    "priority": 5,\r
    "notes": "Great conversation with the hiring manager"\r
  }' | jq .\r
```\r
\r
**Response shape:**\r
\r
```json\r
{\r
  "success": true,\r
  "application": {\r
    "id": "clx_abc123",\r
    "jobTitle": "Frontend Engineer",\r
    "company": "Acme Corp",\r
    "location": "New York, NY",\r
    "status": "interviewed",\r
    "priority": 5,\r
    "notes": "Great conversation with the hiring manager",\r
    "updatedAt": "2026-03-15T..."\r
  }\r
}\r
```\r
\r
Status changes are automatically recorded in the application's timeline.\r
\r
---\r
\r
### 6. List Contacts\r
\r
**When to use:** The user wants to see their networking contacts. They might say "show my contacts" or "who do I know at Acme Corp?"\r
\r
**Method:** `GET /v1/contacts`\r
\r
**Required scope:** `contacts:read`\r
\r
**Rate limit:** 60 requests per minute\r
\r
**Query parameters:**\r
\r
| Param          | Type   | Required | Description                                              |\r
|----------------|--------|----------|----------------------------------------------------------|\r
| `limit`        | number | No       | Results per page, default 25, max 100                    |\r
| `offset`       | number | No       | Number of results to skip                                |\r
| `relationship` | string | No       | Filter by type (see relationship values below)           |\r
| `search`       | string | No       | Search by name, company, or email (case-insensitive)     |\r
\r
**Valid relationship values:** `RECRUITER`, `HIRING_MANAGER`, `HR_MANAGER`, `TEAM_LEAD`, `DEPARTMENT_HEAD`, `CEO_FOUNDER`, `COLLEAGUE`, `FRIEND`, `REFERRAL`, `OTHER`\r
\r
**Curl example:**\r
\r
```bash\r
curl -s -G https://api.mokaru.ai/v1/contacts \\r
  -H "Authorization: Bearer $MOKARU_API_KEY" \\r
  --data-urlencode "search=Acme" \\r
  --data-urlencode "limit=10" | jq .\r
```\r
\r
**Response shape:**\r
\r
```json\r
{\r
  "data": [\r
    {\r
      "id": "clx...",\r
      "firstName": "Sarah",\r
      "lastName": "Jones",\r
      "jobTitle": "Engineering Manager",\r
      "company": "Acme Corp",\r
      "relationship": "HIRING_MANAGER",\r
      "email": "[email protected]",\r
      "phone": "+1 555-0200",\r
      "linkedIn": "https://linkedin.com/in/sarahjones",\r
      "createdAt": "2026-03-10T...",\r
      "updatedAt": "2026-03-15T..."\r
    }\r
  ],\r
  "total": 12,\r
  "hasMore": true,\r
  "limit": 10,\r
  "offset": 0\r
}\r
```\r
\r
---\r
\r
### 7. Get Contact Detail\r
\r
**When to use:** The user wants to see full details of a specific contact. They might say "show me Sarah's info" or "what's the recruiter's email?"\r
\r
**Method:** `GET /v1/contacts/{id}`\r
\r
**Required scope:** `contacts:read`\r
\r
**Rate limit:** 30 requests per minute\r
\r
**Curl example:**\r
\r
```bash\r
curl -s https://api.mokaru.ai/v1/contacts/clx_abc123 \\r
  -H "Authorization: Bearer $MOKARU_API_KEY" | jq .\r
```\r
\r
**Response shape:**\r
\r
```json\r
{\r
  "data": {\r
    "id": "clx_abc123",\r
    "firstName": "Sarah",\r
    "lastName": "Jones",\r
    "jobTitle": "Engineering Manager",\r
    "company": "Acme Corp",\r
    "relationship": "HIRING_MANAGER",\r
    "email": "[email protected]",\r
    "phone": "+1 555-0200",\r
    "linkedIn": "https://linkedin.com/in/sarahjones",\r
    "createdAt": "2026-03-10T...",\r
    "updatedAt": "2026-03-15T..."\r
  }\r
}\r
```\r
\r
---\r
\r
### 8. Create Contact\r
\r
**When to use:** The user wants to save a new networking contact. They might say "add Sarah Jones as a contact" or "save the recruiter's info."\r
\r
**Method:** `POST /v1/contacts`\r
\r
**Required scope:** `contacts:write`\r
\r
**Rate limit:** 20 requests per minute\r
\r
**Request body (JSON):**\r
\r
| Field          | Type   | Required | Description                              |\r
|----------------|--------|----------|------------------------------------------|\r
| `firstName`    | string | Yes      | First name (max 100 chars)               |\r
| `lastName`     | string | Yes      | Last name (max 100 chars)                |\r
| `jobTitle`     | string | No       | Contact's job title (max 200 chars)      |\r
| `company`      | string | No       | Company name (max 200 chars)             |\r
| `relationship` | string | No       | Relationship type (see values above)     |\r
| `email`        | string | No       | Email address (max 200 chars)            |\r
| `phone`        | string | No       | Phone number (max 50 chars)              |\r
| `linkedIn`     | string | No       | LinkedIn profile URL (max 500 chars)     |\r
\r
**Curl example:**\r
\r
```bash\r
curl -s -X POST https://api.mokaru.ai/v1/contacts \\r
  -H "Authorization: Bearer $MOKARU_API_KEY" \\r
  -H "Content-Type: application/json" \\r
  -d '{\r
    "firstName": "Sarah",\r
    "lastName": "Jones",\r
    "jobTitle": "Engineering Manager",\r
    "company": "Acme Corp",\r
    "relationship": "HIRING_MANAGER",\r
    "email": "[email protected]"\r
  }' | jq .\r
```\r
\r
**Response shape:**\r
\r
```json\r
{\r
  "success": true,\r
  "id": "clx..."\r
}\r
```\r
\r
---\r
\r
### 9. Update Contact\r
\r
**When to use:** The user wants to update a contact's details. They might say "update Sarah's phone number" or "change the recruiter's company."\r
\r
**Method:** `PATCH /v1/contacts/{id}`\r
\r
**Required scope:** `contacts:write`\r
\r
**Rate limit:** 20 requests per minute\r
\r
**Request body (JSON) - all fields optional, at least one required:**\r
\r
| Field          | Type        | Description                              |\r
|----------------|-------------|------------------------------------------|\r
| `firstName`    | string      | First name (max 100 chars)               |\r
| `lastName`     | string      | Last name (max 100 chars)                |\r
| `jobTitle`     | string/null | Job title (max 200 chars, null to clear) |\r
| `company`      | string/null | Company name (max 200 chars)             |\r
| `relationship` | string/null | Relationship type (see values above)     |\r
| `email`        | string/null | Email address (max 200 chars)            |\r
| `phone`        | string/null | Phone number (max 50 chars)              |\r
| `linkedIn`     | string/null | LinkedIn URL (max 500 chars)             |\r
\r
**Curl example:**\r
\r
```bash\r
curl -s -X PATCH https://api.mokaru.ai/v1/contacts/clx_abc123 \\r
  -H "Authorization: Bearer $MOKARU_API_KEY" \\r
  -H "Content-Type: application/json" \\r
  -d '{\r
    "phone": "+1 555-0201",\r
    "relationship": "TEAM_LEAD"\r
  }' | jq .\r
```\r
\r
**Response shape:**\r
\r
```json\r
{\r
  "success": true,\r
  "id": "clx_abc123"\r
}\r
```\r
\r
Pass `null` for optional fields to clear them (e.g. `"phone": null`).\r
\r
---\r
\r
### 10. Delete Contact\r
\r
**When to use:** The user wants to remove a contact. They might say "delete that contact" or "remove Sarah from my contacts."\r
\r
**Method:** `DELETE /v1/contacts/{id}`\r
\r
**Required scope:** `contacts:write`\r
\r
**Rate limit:** 10 requests per minute\r
\r
**Curl example:**\r
\r
```bash\r
curl -s -X DELETE https://api.mokaru.ai/v1/contacts/clx_abc123 \\r
  -H "Authorization: Bearer $MOKARU_API_KEY" | jq .\r
```\r
\r
**Response shape:**\r
\r
```json\r
{\r
  "success": true\r
}\r
```\r
\r
---\r
\r
### 11. Get Profile\r
\r
**When to use:** The user wants to see their career profile, or you need context about their background to tailor a job search. For example, "what skills do I have on file?" or before searching, to understand their experience level.\r
\r
**Method:** `GET /v1/profile`\r
\r
**Required scope:** `profile:read`\r
\r
**Rate limit:** 30 requests per minute\r
\r
**Curl example:**\r
\r
```bash\r
curl -s https://api.mokaru.ai/v1/profile \\r
  -H "Authorization: Bearer $MOKARU_API_KEY" | jq .\r
```\r
\r
**Response shape:**\r
\r
```json\r
{\r
  "data": {\r
    "firstName": "Jane",\r
    "lastName": "Doe",\r
    "email": "[email protected]",\r
    "phone": "+1 555-0100",\r
    "address": "New York, NY",\r
    "country": "US",\r
    "province": "NY",\r
    "jobTitle": "Frontend Engineer",\r
    "summary": "5 years of experience in...",\r
    "sector": "Technology",\r
    "linkedIn": "https://linkedin.com/in/janedoe",\r
    "website": "https://janedoe.dev",\r
    "portfolio": null,\r
    "jobTitles": [\r
      { "title": "Frontend Engineer", "displayOrder": 0 },\r
      { "title": "React Developer", "displayOrder": 1 }\r
    ],\r
    "skills": [\r
      { "name": "React", "category": "TECHNICAL", "level": "expert" },\r
      { "name": "TypeScript", "category": "TECHNICAL", "level": "advanced" }\r
    ],\r
    "workExperiences": [\r
      {\r
        "jobTitle": "Frontend Engineer",\r
        "company": "TechCo",\r
        "location": "New York, NY",\r
        "startDate": "2022-01-15T00:00:00.000Z",\r
        "endDate": null,\r
        "isCurrent": true,\r
        "description": "Building the design system...",\r
        "responsibilities": ["Led frontend architecture"],\r
        "achievements": ["Reduced bundle size by 40%"]\r
      }\r
    ],\r
    "educations": [\r
      {\r
        "school": "MIT",\r
        "degree": "Bachelor of Science",\r
        "field": "Computer Science",\r
        "startDate": "2016-09-01T00:00:00.000Z",\r
        "endDate": "2020-06-15T00:00:00.000Z",\r
        "isCurrent": false\r
      }\r
    ]\r
  }\r
}\r
```\r
\r
**Note:** The profile response uses friendly aliases `school` / `field` for education (derived from the DB fields `institution` / `fieldOfStudy`). When calling the dedicated `/v1/education` endpoints, use `institution` and `fieldOfStudy` instead (see section 24-28). Skill `category` values are the enum `TECHNICAL`, `SOFT`, or `LANGUAGE`.\r
\r
**How to use:** Pull the user's job titles, skills, and current role to craft better search queries. Mention their background when recommending jobs.\r
\r
---\r
\r
### 12. Update Profile\r
\r
**When to use:** The user wants to update their career profile. They might say "change my job title" or "update my LinkedIn" or "add my new employer."\r
\r
**Method:** `PATCH /v1/profile`\r
\r
**Required scope:** `profile:write`\r
\r
**Rate limit:** 20 requests per minute\r
\r
**Request body (JSON) - all fields optional, at least one required:**\r
\r
| Field          | Type        | Description                              |\r
|----------------|-------------|------------------------------------------|\r
| `firstName`    | string      | First name (max 100 chars)               |\r
| `lastName`     | string      | Last name (max 100 chars)                |\r
| `email`        | string      | Email address (max 254 chars)            |\r
| `phone`        | string/null | Phone number (max 50 chars)              |\r
| `address`      | string/null | Address (max 200 chars)                  |\r
| `country`      | string/null | Country (max 100 chars)                  |\r
| `province`     | string/null | Province or state (max 100 chars)        |\r
| `birthDate`    | string/null | ISO date string (e.g. "1990-01-15")      |\r
| `driverLicense`| string/null | Driver license type (max 50 chars)       |\r
| `gender`       | string/null | Gender (max 50 chars)                    |\r
| `jobTitle`     | string/null | Current job title (max 200 chars)        |\r
| `summary`      | string/null | Professional summary (max 2000 chars)    |\r
| `sector`       | string/null | Industry sector (max 100 chars)          |\r
| `employer`     | string/null | Current employer (max 200 chars)         |\r
| `linkedIn`     | string/null | LinkedIn username or URL (auto-normalized)|\r
| `website`      | string/null | Website URL (https:// added if missing)  |\r
| `portfolio`    | string/null | Portfolio URL (https:// added if missing)|\r
\r
Pass `null` for optional fields to clear them.\r
\r
**Curl example:**\r
\r
```bash\r
curl -s -X PATCH https://api.mokaru.ai/v1/profile \\r
  -H "Authorization: Bearer $MOKARU_API_KEY" \\r
  -H "Content-Type: application/json" \\r
  -d '{\r
    "jobTitle": "Senior Software Engineer",\r
    "employer": "Acme Corp",\r
    "linkedIn": "jane-smith"\r
  }' | jq .\r
```\r
\r
**Response shape:**\r
\r
```json\r
{\r
  "success": true\r
}\r
```\r
\r
LinkedIn usernames are automatically converted to full URLs. For example, `"jane-smith"` becomes `"https://linkedin.com/in/jane-smith"`. Website and portfolio URLs have `https://` prepended if missing.\r
\r
**Important:** Profile changes propagate to all resumes that use profile data. This is different from updating a resume's `cvData` which only affects that specific resume.\r
\r
---\r
\r
### 13. List Resumes\r
\r
**When to use:** The user wants to see their resumes, or you need to know which resume to export or update. They might say "show my resumes" or "which CVs do I have?"\r
\r
**Method:** `GET /v1/resume`\r
\r
**Required scope:** `resume:read`\r
\r
**Rate limit:** 60 requests per minute\r
\r
**Query parameters:**\r
\r
| Param    | Type   | Required | Description                           |\r
|----------|--------|----------|---------------------------------------|\r
| `limit`  | number | No       | Results per page, default 25, max 100 |\r
| `offset` | number | No       | Number of results to skip             |\r
\r
**Curl example:**\r
\r
```bash\r
curl -s https://api.mokaru.ai/v1/resume \\r
  -H "Authorization: Bearer $MOKARU_API_KEY" | jq .\r
```\r
\r
**Response shape:**\r
\r
```json\r
{\r
  "data": [\r
    {\r
      "id": "clx...",\r
      "name": "Software Engineer Resume",\r
      "template": "classic",\r
      "isDefault": true,\r
      "createdAt": "2026-01-15T...",\r
      "updatedAt": "2026-03-20T..."\r
    }\r
  ],\r
  "total": 3,\r
  "hasMore": false,\r
  "limit": 25,\r
  "offset": 0\r
}\r
```\r
\r
---\r
\r
### 14. Get Resume Detail\r
\r
**When to use:** The user wants to see the full content of a specific resume, or you need the data to provide career advice. They might say "show me my default resume" or "what's on my Software Engineer CV?"\r
\r
**Method:** `GET /v1/resume/{id}`\r
\r
**Required scope:** `resume:read`\r
\r
**Rate limit:** 30 requests per minute\r
\r
**Curl example:**\r
\r
```bash\r
curl -s https://api.mokaru.ai/v1/resume/clx_abc123 \\r
  -H "Authorization: Bearer $MOKARU_API_KEY" | jq .\r
```\r
\r
**Response shape:**\r
\r
```json\r
{\r
  "data": {\r
    "id": "clx...",\r
    "name": "Software Engineer Resume",\r
    "template": "classic",\r
    "isDefault": true,\r
    "cvData": {\r
      "firstName": "Jane",\r
      "lastName": "Doe",\r
      "email": "[email protected]",\r
      "jobTitle": "Software Engineer",\r
      "experiences": [...],\r
      "education": [...],\r
      "skills": [...]\r
    },\r
    "designSettings": { ... },\r
    "optionalFields": { ... },\r
    "sectionOrder": ["personal", "experience", "education", "skills"],\r
    "hiddenItems": { ... },\r
    "createdAt": "2026-01-15T...",\r
    "updatedAt": "2026-03-20T..."\r
  }\r
}\r
```\r
\r
The `cvData` field contains the full resume content: personal info, work experiences, education, skills, languages, certificates, projects, and more. The `hiddenItems` field tracks which individual entries (experiences, education, etc.) are hidden from the rendered resume.\r
\r
---\r
\r
### 15. Create Resume\r
\r
**When to use:** The user wants to create a new resume. They might say "create a new resume for backend roles" or "make a copy of my CV with a different name."\r
\r
**Method:** `POST /v1/resume`\r
\r
**Required scope:** `resume:write`\r
\r
**Rate limit:** 10 requests per minute\r
\r
**Request body (JSON):**\r
\r
| Field            | Type    | Required | Description                              |\r
|------------------|---------|----------|------------------------------------------|\r
| `name`           | string  | Yes      | Resume name (max 200 chars)              |\r
| `template`       | string  | No       | Template ID (default: "classic")         |\r
| `isDefault`      | boolean | No       | Set as default resume                    |\r
| `cvData`         | object  | No       | Resume content (experiences, skills, etc)|\r
| `designSettings` | object  | No       | Visual styling (colors, fonts, spacing)  |\r
| `optionalFields` | object  | No       | Show/hide optional fields                |\r
| `sectionOrder`   | array   | No       | Order of resume sections                 |\r
\r
**Curl example:**\r
\r
```bash\r
curl -s -X POST https://api.mokaru.ai/v1/resume \\r
  -H "Authorization: Bearer $MOKARU_API_KEY" \\r
  -H "Content-Type: application/json" \\r
  -d '{\r
    "name": "Backend Engineer Resume",\r
    "template": "classic",\r
    "isDefault": false\r
  }' | jq .\r
```\r
\r
**Response shape:**\r
\r
```json\r
{\r
  "success": true,\r
  "id": "clx..."\r
}\r
```\r
\r
---\r
\r
### 16. Update Resume\r
\r
**When to use:** The user wants to change their resume name, template, content, or settings. They might say "rename my resume" or "update my skills on the default CV."\r
\r
**Method:** `PATCH /v1/resume/{id}`\r
\r
**Required scope:** `resume:write`\r
\r
**Rate limit:** 20 requests per minute\r
\r
**Request body (JSON) - all fields optional, at least one required:**\r
\r
| Field            | Type    | Description                              |\r
|------------------|---------|------------------------------------------|\r
| `name`           | string  | Resume name (max 200 chars)              |\r
| `template`       | string  | Template ID                              |\r
| `isDefault`      | boolean | Set as default resume                    |\r
| `cvData`         | object  | Resume content                           |\r
| `designSettings` | object  | Visual styling                           |\r
| `optionalFields` | object  | Show/hide optional fields                |\r
| `sectionOrder`   | array   | Order of resume sections                 |\r
\r
**Curl example:**\r
\r
```bash\r
curl -s -X PATCH https://api.mokaru.ai/v1/resume/clx_abc123 \\r
  -H "Authorization: Bearer $MOKARU_API_KEY" \\r
  -H "Content-Type: application/json" \\r
  -d '{\r
    "name": "Updated Resume",\r
    "isDefault": true\r
  }' | jq .\r
```\r
\r
**Response shape:**\r
\r
```json\r
{\r
  "success": true,\r
  "id": "clx..."\r
}\r
```\r
\r
---\r
\r
### 17. Delete Resume\r
\r
**When to use:** The user wants to remove a resume. They might say "delete that old resume" or "remove my Backend CV."\r
\r
**Method:** `DELETE /v1/resume/{id}`\r
\r
**Required scope:** `resume:write`\r
\r
**Rate limit:** 10 requests per minute\r
\r
**Curl example:**\r
\r
```bash\r
curl -s -X DELETE https://api.mokaru.ai/v1/resume/clx_abc123 \\r
  -H "Authorization: Bearer $MOKARU_API_KEY" | jq .\r
```\r
\r
**Response shape:**\r
\r
```json\r
{\r
  "success": true\r
}\r
```\r
\r
If the deleted resume was the default, another resume is automatically promoted. Applications linked to this resume are unlinked (`cvId` set to null, the application itself is not deleted). Any Autopilot searches that reference this resume are also deleted.\r
\r
---\r
\r
### 18. Export Resume as PDF\r
\r
**When to use:** The user wants to download their resume as a PDF. They might say "export my resume" or "give me a PDF of my CV."\r
\r
**Method:** `POST /v1/resume/{id}/export/pdf`\r
\r
**Required scope:** `resume:export`\r
\r
**Rate limit:** 5 requests per minute\r
\r
**Request body (JSON, optional):**\r
\r
| Field    | Type   | Required | Description                   |\r
|----------|--------|----------|-------------------------------|\r
| `locale` | string | No       | Language for date formatting (default: "en") |\r
\r
**Curl example:**\r
\r
```bash\r
curl -s -X POST https://api.mokaru.ai/v1/resume/clx_abc123/export/pdf \\r
  -H "Authorization: Bearer $MOKARU_API_KEY" \\r
  -H "Content-Type: application/json" \\r
  -d '{}' \\r
  -o resume.pdf\r
```\r
\r
**Response:** Binary PDF file with `Content-Type: application/pdf`. Save it to disk or send it to the user.\r
\r
**Important:** This endpoint returns a binary file, not JSON. The PDF is rendered server-side with the user's chosen template and design settings.\r
\r
**Export errors:**\r
- `RESUME_PROCESSING` (409) - resume is being tailored by auto-prep. Wait 5-10 seconds and retry.\r
- `EMPTY_RESUME` (400) - the resume has no `cvData` yet. Ask the user to fill in their resume first.\r
\r
---\r
\r
### 19. List Experiences\r
\r
**When to use:** The user wants to see their work history. They might say "show my work experience" or "what jobs have I had?"\r
\r
**Method:** `GET /v1/experiences`\r
\r
**Required scope:** `experiences:read`\r
\r
**Rate limit:** 60 requests per minute\r
\r
**Query parameters:**\r
\r
| Param    | Type   | Required | Description                           |\r
|----------|--------|----------|---------------------------------------|\r
| `limit`  | number | No       | Results per page, default 25, max 100 |\r
| `offset` | number | No       | Number of results to skip             |\r
\r
**Curl example:**\r
\r
```bash\r
curl -s -G https://api.mokaru.ai/v1/experiences \\r
  -H "Authorization: Bearer $MOKARU_API_KEY" \\r
  --data-urlencode "limit=10" | jq .\r
```\r
\r
**Response shape:**\r
\r
```json\r
{\r
  "data": [\r
    {\r
      "id": "clx...",\r
      "jobTitle": "Senior Software Engineer",\r
      "company": "Acme Corp",\r
      "location": "San Francisco, CA",\r
      "startDate": "2022-07-01T00:00:00.000Z",\r
      "endDate": null,\r
      "isCurrent": true,\r
      "description": "Building and maintaining the core platform",\r
      "createdAt": "2026-01-10T...",\r
      "updatedAt": "2026-03-15T..."\r
    }\r
  ],\r
  "total": 4,\r
  "hasMore": false,\r
  "limit": 10,\r
  "offset": 0\r
}\r
```\r
\r
**Note:** The list response does not include `responsibilities` or `achievements` - use `GET /v1/experiences/{id}` to fetch those.\r
\r
---\r
\r
### 20. Create Experience\r
\r
**When to use:** The user wants to add a new work experience. They might say "add my new job at Acme" or "save this work experience."\r
\r
**Method:** `POST /v1/experiences`\r
\r
**Required scope:** `experiences:write`\r
\r
**Rate limit:** 20 requests per minute\r
\r
**Request body (JSON):**\r
\r
| Field              | Type    | Required | Description                                    |\r
|--------------------|---------|----------|------------------------------------------------|\r
| `jobTitle`         | string  | Yes      | Job title (max 200 chars)                      |\r
| `company`          | string  | Yes      | Company name (max 200 chars)                   |\r
| `location`         | string  | No       | Work location (max 200 chars)                  |\r
| `startDate`        | string  | No       | Full ISO-8601 datetime (e.g. "2022-07-01T00:00:00.000Z") |\r
| `endDate`          | string  | No       | Full ISO-8601 datetime (omit for current position)        |\r
| `isCurrent`        | boolean | No       | Whether this is the current position            |\r
| `description`      | string  | No       | Role description                                |\r
| `responsibilities` | array   | No       | List of responsibilities (array of strings)    |\r
| `achievements`     | array   | No       | List of achievements (array of strings)        |\r
\r
**Date format:** `startDate` and `endDate` must be full ISO-8601 datetimes (`YYYY-MM-DDTHH:mm:ss.sssZ`). A date-only string like `"2022-07-01"` will be rejected.\r
\r
**Curl example:**\r
\r
```bash\r
curl -s -X POST https://api.mokaru.ai/v1/experiences \\r
  -H "Authorization: Bearer $MOKARU_API_KEY" \\r
  -H "Content-Type: application/json" \\r
  -d '{\r
    "jobTitle": "Senior Software Engineer",\r
    "company": "Acme Corp",\r
    "location": "San Francisco, CA",\r
    "startDate": "2022-07-01T00:00:00.000Z",\r
    "isCurrent": true,\r
    "description": "Building the core platform",\r
    "responsibilities": ["Led frontend architecture"],\r
    "achievements": ["Reduced bundle size by 40%"]\r
  }' | jq .\r
```\r
\r
**Response shape:**\r
\r
```json\r
{\r
  "success": true,\r
  "id": "clx..."\r
}\r
```\r
\r
---\r
\r
### 21. Get Experience Detail\r
\r
**When to use:** The user wants to see full details of a specific work experience.\r
\r
**Method:** `GET /v1/experiences/{id}`\r
\r
**Required scope:** `experiences:read`\r
\r
**Rate limit:** 30 requests per minute\r
\r
**Curl example:**\r
\r
```bash\r
curl -s https://api.mokaru.ai/v1/experiences/clx_abc123 \\r
  -H "Authorization: Bearer $MOKARU_API_KEY" | jq .\r
```\r
\r
**Response shape:**\r
\r
```json\r
{\r
  "data": {\r
    "id": "clx_abc123",\r
    "jobTitle": "Senior Software Engineer",\r
    "company": "Acme Corp",\r
    "location": "San Francisco, CA",\r
    "startDate": "2022-07-01T00:00:00.000Z",\r
    "endDate": null,\r
    "isCurrent": true,\r
    "description": "Building and maintaining the core platform",\r
    "responsibilities": ["Led frontend architecture"],\r
    "achievements": ["Reduced bundle size by 40%"],\r
    "createdAt": "2026-01-10T...",\r
    "updatedAt": "2026-03-15T..."\r
  }\r
}\r
```\r
\r
---\r
\r
### 22. Update Experience\r
\r
**When to use:** The user wants to change details of a work experience. They might say "update my Acme job" or "I left that position, mark it as ended."\r
\r
**Method:** `PATCH /v1/experiences/{id}`\r
\r
**Required scope:** `experiences:write`\r
\r
**Rate limit:** 20 requests per minute\r
\r
**Request body (JSON) - all fields optional, at least one required:**\r
\r
| Field              | Type         | Description                                    |\r
|--------------------|--------------|------------------------------------------------|\r
| `jobTitle`         | string       | Job title (max 200 chars)                                      |\r
| `company`          | string       | Company name (max 200 chars)                                   |\r
| `location`         | string/null  | Work location (max 200 chars, null to clear)                   |\r
| `startDate`        | string/null  | Full ISO-8601 datetime (null to clear)                         |\r
| `endDate`          | string/null  | Full ISO-8601 datetime (null to clear)                         |\r
| `isCurrent`        | boolean/null | Whether this is the current position (null to clear)            |\r
| `description`      | string/null  | Role description (null to clear)                               |\r
| `responsibilities` | array/null   | List of responsibilities (null to clear)                       |\r
| `achievements`     | array/null   | List of achievements (null to clear)                           |\r
\r
**Date format:** `startDate` and `endDate` must be full ISO-8601 datetimes (`YYYY-MM-DDTHH:mm:ss.sssZ`). A date-only string will be rejected.\r
\r
**Curl example:**\r
\r
```bash\r
curl -s -X PATCH https://api.mokaru.ai/v1/experiences/clx_abc123 \\r
  -H "Authorization: Bearer $MOKARU_API_KEY" \\r
  -H "Content-Type: application/json" \\r
  -d '{\r
    "isCurrent": false,\r
    "endDate": "2026-03-15T00:00:00.000Z"\r
  }' | jq .\r
```\r
\r
**Response shape:**\r
\r
```json\r
{\r
  "success": true,\r
  "id": "clx_abc123"\r
}\r
```\r
\r
Pass `null` for optional fields to clear them.\r
\r
---\r
\r
### 23. Delete Experience\r
\r
**When to use:** The user wants to remove a work experience. They might say "delete that old job" or "remove the internship from my profile."\r
\r
**Method:** `DELETE /v1/experiences/{id}`\r
\r
**Required scope:** `experiences:write`\r
\r
**Rate limit:** 10 requests per minute\r
\r
**Curl example:**\r
\r
```bash\r
curl -s -X DELETE https://api.mokaru.ai/v1/experiences/clx_abc123 \\r
  -H "Authorization: Bearer $MOKARU_API_KEY" | jq .\r
```\r
\r
**Response shape:**\r
\r
```json\r
{\r
  "success": true\r
}\r
```\r
\r
---\r
\r
### 24. List Education\r
\r
**When to use:** The user wants to see their education history. They might say "show my education" or "what schools do I have listed?"\r
\r
**Method:** `GET /v1/education`\r
\r
**Required scope:** `education:read`\r
\r
**Rate limit:** 60 requests per minute\r
\r
**Query parameters:**\r
\r
| Param    | Type   | Required | Description                           |\r
|----------|--------|----------|---------------------------------------|\r
| `limit`  | number | No       | Results per page, default 25, max 100 |\r
| `offset` | number | No       | Number of results to skip             |\r
\r
**Curl example:**\r
\r
```bash\r
curl -s -G https://api.mokaru.ai/v1/education \\r
  -H "Authorization: Bearer $MOKARU_API_KEY" \\r
  --data-urlencode "limit=10" | jq .\r
```\r
\r
**Response shape:**\r
\r
```json\r
{\r
  "data": [\r
    {\r
      "id": "clx...",\r
      "institution": "Stanford University",\r
      "degree": "Bachelor of Science",\r
      "fieldOfStudy": "Computer Science",\r
      "location": "Stanford, CA",\r
      "startDate": "2018-09-01T00:00:00.000Z",\r
      "endDate": "2022-06-15T00:00:00.000Z",\r
      "isCurrent": false,\r
      "grade": "Magna Cum Laude",\r
      "createdAt": "2026-01-10T...",\r
      "updatedAt": "2026-03-15T..."\r
    }\r
  ],\r
  "total": 2,\r
  "hasMore": false,\r
  "limit": 10,\r
  "offset": 0\r
}\r
```\r
\r
**Note:** The list response does not include `description` or `gpa` - use `GET /v1/education/{id}` to fetch those.\r
\r
---\r
\r
### 25. Create Education\r
\r
**When to use:** The user wants to add education. They might say "add my Stanford degree" or "save this school to my profile."\r
\r
**Method:** `POST /v1/education`\r
\r
**Required scope:** `education:write`\r
\r
**Rate limit:** 20 requests per minute\r
\r
**Request body (JSON):**\r
\r
| Field         | Type    | Required | Description                                    |\r
|---------------|---------|----------|------------------------------------------------|\r
| `institution`  | string  | Yes      | School or institution name (max 200 chars)                    |\r
| `degree`       | string  | Yes      | Degree type (max 200 chars)                                   |\r
| `fieldOfStudy` | string  | No       | Field of study (max 200 chars)                                |\r
| `location`     | string  | No       | Location of the school (max 200 chars)                        |\r
| `startDate`    | string  | No       | Full ISO-8601 datetime (e.g. "2018-09-01T00:00:00.000Z")      |\r
| `endDate`      | string  | No       | Full ISO-8601 datetime (omit if currently enrolled)           |\r
| `isCurrent`    | boolean | No       | Whether currently enrolled                                     |\r
| `description`  | string  | No       | Additional details                                             |\r
| `grade`        | string  | No       | Grade or honors (max 50 chars, e.g. "Magna Cum Laude")        |\r
| `gpa`          | number  | No       | GPA value                                                      |\r
\r
**Date format:** `startDate` and `endDate` must be full ISO-8601 datetimes (`YYYY-MM-DDTHH:mm:ss.sssZ`). A date-only string will be rejected.\r
\r
**Curl example:**\r
\r
```bash\r
curl -s -X POST https://api.mokaru.ai/v1/education \\r
  -H "Authorization: Bearer $MOKARU_API_KEY" \\r
  -H "Content-Type: application/json" \\r
  -d '{\r
    "institution": "Stanford University",\r
    "degree": "Bachelor of Science",\r
    "fieldOfStudy": "Computer Science",\r
    "startDate": "2018-09-01T00:00:00.000Z",\r
    "endDate": "2022-06-15T00:00:00.000Z"\r
  }' | jq .\r
```\r
\r
**Response shape:**\r
\r
```json\r
{\r
  "success": true,\r
  "id": "clx..."\r
}\r
```\r
\r
---\r
\r
### 26. Get Education Detail\r
\r
**When to use:** The user wants to see full details of a specific education entry.\r
\r
**Method:** `GET /v1/education/{id}`\r
\r
**Required scope:** `education:read`\r
\r
**Rate limit:** 30 requests per minute\r
\r
**Curl example:**\r
\r
```bash\r
curl -s https://api.mokaru.ai/v1/education/clx_abc123 \\r
  -H "Authorization: Bearer $MOKARU_API_KEY" | jq .\r
```\r
\r
**Response shape:**\r
\r
```json\r
{\r
  "data": {\r
    "id": "clx_abc123",\r
    "institution": "Stanford University",\r
    "degree": "Bachelor of Science",\r
    "fieldOfStudy": "Computer Science",\r
    "location": "Stanford, CA",\r
    "startDate": "2018-09-01T00:00:00.000Z",\r
    "endDate": "2022-06-15T00:00:00.000Z",\r
    "isCurrent": false,\r
    "description": "Graduated with honors",\r
    "grade": "Magna Cum Laude",\r
    "gpa": 3.8,\r
    "createdAt": "2026-01-10T...",\r
    "updatedAt": "2026-03-15T..."\r
  }\r
}\r
```\r
\r
---\r
\r
### 27. Update Education\r
\r
**When to use:** The user wants to change education details. They might say "update my degree" or "change the field of study."\r
\r
**Method:** `PATCH /v1/education/{id}`\r
\r
**Required scope:** `education:write`\r
\r
**Rate limit:** 20 requests per minute\r
\r
**Request body (JSON) - all fields optional, at least one required:**\r
\r
| Field         | Type        | Description                                    |\r
|---------------|-------------|------------------------------------------------|\r
| `institution`  | string       | School name (max 200 chars)                                   |\r
| `degree`       | string       | Degree type (max 200 chars)                                   |\r
| `fieldOfStudy` | string/null  | Field of study (max 200 chars, null to clear)                 |\r
| `location`     | string/null  | Location of the school (max 200 chars, null to clear)         |\r
| `startDate`    | string/null  | Full ISO-8601 datetime (null to clear)                        |\r
| `endDate`      | string/null  | Full ISO-8601 datetime (null to clear)                        |\r
| `isCurrent`    | boolean/null | Whether currently enrolled (null to clear)                     |\r
| `description`  | string/null  | Additional details (null to clear)                            |\r
| `grade`        | string/null  | Grade or honors (max 50 chars, null to clear)                 |\r
| `gpa`          | number/null  | GPA value (null to clear)                                     |\r
\r
**Date format:** `startDate` and `endDate` must be full ISO-8601 datetimes (`YYYY-MM-DDTHH:mm:ss.sssZ`).\r
\r
**Curl example:**\r
\r
```bash\r
curl -s -X PATCH https://api.mokaru.ai/v1/education/clx_abc123 \\r
  -H "Authorization: Bearer $MOKARU_API_KEY" \\r
  -H "Content-Type: application/json" \\r
  -d '{\r
    "degree": "Master of Science",\r
    "fieldOfStudy": "Machine Learning"\r
  }' | jq .\r
```\r
\r
**Response shape:**\r
\r
```json\r
{\r
  "success": true,\r
  "id": "clx_abc123"\r
}\r
```\r
\r
---\r
\r
### 28. Delete Education\r
\r
**When to use:** The user wants to remove an education entry. They might say "delete that school" or "remove my old degree."\r
\r
**Method:** `DELETE /v1/education/{id}`\r
\r
**Required scope:** `education:write`\r
\r
**Rate limit:** 10 requests per minute\r
\r
**Curl example:**\r
\r
```bash\r
curl -s -X DELETE https://api.mokaru.ai/v1/education/clx_abc123 \\r
  -H "Authorization: Bearer $MOKARU_API_KEY" | jq .\r
```\r
\r
**Response shape:**\r
\r
```json\r
{\r
  "success": true\r
}\r
```\r
\r
---\r
\r
### 29. List Skills\r
\r
**When to use:** The user wants to see their skills. They might say "show my skills" or "what skills do I have?"\r
\r
**Method:** `GET /v1/skills`\r
\r
**Required scope:** `skills:read`\r
\r
**Rate limit:** 60 requests per minute\r
\r
**Query parameters:**\r
\r
| Param      | Type   | Required | Description                                            |\r
|------------|--------|----------|--------------------------------------------------------|\r
| `limit`    | number | No       | Results per page, default 25, max 100                  |\r
| `offset`   | number | No       | Number of results to skip                              |\r
| `category` | string | No       | Filter by category: `TECHNICAL`, `SOFT`, or `LANGUAGE` |\r
\r
**Curl example:**\r
\r
```bash\r
curl -s -G https://api.mokaru.ai/v1/skills \\r
  -H "Authorization: Bearer $MOKARU_API_KEY" \\r
  --data-urlencode "limit=50" \\r
  --data-urlencode "category=TECHNICAL" | jq .\r
```\r
\r
**Response shape:**\r
\r
```json\r
{\r
  "data": [\r
    {\r
      "id": "clx...",\r
      "name": "TypeScript",\r
      "category": "TECHNICAL",\r
      "level": "expert",\r
      "score": 5,\r
      "displayOrder": 0,\r
      "isVisible": true,\r
      "categoryRelation": { "name": "programming", "labelEn": "Programming Languages" },\r
      "createdAt": "2026-01-10T...",\r
      "updatedAt": "2026-03-15T..."\r
    }\r
  ],\r
  "total": 12,\r
  "hasMore": false,\r
  "limit": 50,\r
  "offset": 0\r
}\r
```\r
\r
The `category` field is the legacy enum (`TECHNICAL` / `SOFT` / `LANGUAGE`). The optional `categoryRelation` object holds an extended category definition (system-defined or user-defined) when the skill is linked to one.\r
\r
---\r
\r
### 30. Create Skill\r
\r
**When to use:** The user wants to add a skill. They might say "add TypeScript to my skills" or "save this skill."\r
\r
**Method:** `POST /v1/skills`\r
\r
**Required scope:** `skills:write`\r
\r
**Rate limit:** 20 requests per minute\r
\r
**Request body (JSON):**\r
\r
| Field      | Type   | Required | Description                                    |\r
|------------|--------|----------|------------------------------------------------|\r
| `name`     | string | Yes      | Skill name (max 200 chars)                                        |\r
| `category` | string | No       | One of: `TECHNICAL`, `SOFT`, `LANGUAGE`. Defaults to `TECHNICAL`. |\r
| `level`    | string | No       | Free-form proficiency label (max 50 chars, e.g. "expert")         |\r
| `score`    | number | No       | Integer 1-5 (higher means more proficient)                        |\r
\r
**Curl example:**\r
\r
```bash\r
curl -s -X POST https://api.mokaru.ai/v1/skills \\r
  -H "Authorization: Bearer $MOKARU_API_KEY" \\r
  -H "Content-Type: application/json" \\r
  -d '{\r
    "name": "TypeScript",\r
    "category": "TECHNICAL",\r
    "level": "expert",\r
    "score": 5\r
  }' | jq .\r
```\r
\r
**Response shape:**\r
\r
```json\r
{\r
  "success": true,\r
  "id": "clx..."\r
}\r
```\r
\r
---\r
\r
### 31. Get Skill Detail\r
\r
**When to use:** The user wants to see details of a specific skill.\r
\r
**Method:** `GET /v1/skills/{id}`\r
\r
**Required scope:** `skills:read`\r
\r
**Rate limit:** 30 requests per minute\r
\r
**Curl example:**\r
\r
```bash\r
curl -s https://api.mokaru.ai/v1/skills/clx_abc123 \\r
  -H "Authorization: Bearer $MOKARU_API_KEY" | jq .\r
```\r
\r
**Response shape:**\r
\r
```json\r
{\r
  "data": {\r
    "id": "clx_abc123",\r
    "name": "TypeScript",\r
    "categoryLegacy": "TECHNICAL",\r
    "categoryId": null,\r
    "level": "expert",\r
    "score": 5,\r
    "displayOrder": 0,\r
    "isVisible": true,\r
    "createdAt": "2026-01-10T...",\r
    "updatedAt": "2026-03-15T..."\r
  }\r
}\r
```\r
\r
**Note:** Unlike the list endpoint, the detail endpoint returns the raw database row. The enum category is on `categoryLegacy` (not remapped to `category`), and the optional extended category link is on `categoryId`.\r
\r
---\r
\r
### 32. Update Skill\r
\r
**When to use:** The user wants to change a skill's details. They might say "change my TypeScript level to expert" or "update that skill's category."\r
\r
**Method:** `PATCH /v1/skills/{id}`\r
\r
**Required scope:** `skills:write`\r
\r
**Rate limit:** 20 requests per minute\r
\r
**Request body (JSON) - all fields optional, at least one required:**\r
\r
| Field      | Type        | Description                                    |\r
|------------|-------------|------------------------------------------------|\r
| `name`         | string      | Skill name (max 200 chars)                                        |\r
| `category`     | string      | One of: `TECHNICAL`, `SOFT`, `LANGUAGE`                           |\r
| `level`        | string/null | Free-form proficiency label (max 50 chars, null to clear)         |\r
| `score`        | number/null | Integer 1-5 (null to clear)                                       |\r
| `isVisible`    | boolean     | Whether this skill shows on rendered resumes                       |\r
| `displayOrder` | number      | Integer position used for sorting skills                           |\r
\r
**Curl example:**\r
\r
```bash\r
curl -s -X PATCH https://api.mokaru.ai/v1/skills/clx_abc123 \\r
  -H "Authorization: Bearer $MOKARU_API_KEY" \\r
  -H "Content-Type: application/json" \\r
  -d '{\r
    "level": "expert",\r
    "score": 5\r
  }' | jq .\r
```\r
\r
**Response shape:**\r
\r
```json\r
{\r
  "success": true,\r
  "id": "clx_abc123"\r
}\r
```\r
\r
---\r
\r
### 33. Delete Skill\r
\r
**When to use:** The user wants to remove a skill. They might say "delete that skill" or "remove TypeScript from my profile."\r
\r
**Method:** `DELETE /v1/skills/{id}`\r
\r
**Required scope:** `skills:write`\r
\r
**Rate limit:** 10 requests per minute\r
\r
**Curl example:**\r
\r
```bash\r
curl -s -X DELETE https://api.mokaru.ai/v1/skills/clx_abc123 \\r
  -H "Authorization: Bearer $MOKARU_API_KEY" | jq .\r
```\r
\r
**Response shape:**\r
\r
```json\r
{\r
  "success": true\r
}\r
```\r
\r
---\r
\r
### 34. Delete Application\r
\r
**When to use:** The user wants to remove an application from their tracker. They might say "delete that application" or "remove the Acme job from my tracker."\r
\r
**Method:** `DELETE /v1/tracker/applications/{id}`\r
\r
**Required scope:** `tracker:write`\r
\r
**Rate limit:** 10 requests per minute\r
\r
**Curl example:**\r
\r
```bash\r
curl -s -X DELETE https://api.mokaru.ai/v1/tracker/applications/clx_abc123 \\r
  -H "Authorization: Bearer $MOKARU_API_KEY" | jq .\r
```\r
\r
**Response shape:**\r
\r
```json\r
{\r
  "success": true\r
}\r
```\r
\r
The application is soft-deleted (marked as deleted but retained in the database). Timeline entries are preserved. Any linked resume is not modified.\r
\r
---\r
\r
## Workflows\r
\r
### Finding, saving, and preparing for jobs\r
\r
1. Optionally call `GET /v1/profile` to understand the user's background.\r
2. Call `POST /v1/jobs/search` with a query based on what the user asked for (or derived from their profile).\r
3. Present the results with the `applyLink` for each job.\r
4. If the user wants to save one, call `POST /v1/tracker/applications` with the job details and pass the job `id` as `jobListingId`. Add `"autoPrepare": true` to tailor their resume automatically.\r
5. To actually apply, the user must visit the `applyLink` themselves. Provide it clearly.\r
\r
### Reviewing application pipeline\r
\r
1. Call `GET /v1/tracker/applications` to get all applications, or filter by status.\r
2. Summarize the pipeline: how many in each status, which are highest priority.\r
3. If the user wants to update one, call `PATCH /v1/tracker/applications/{id}`.\r
\r
### Managing contacts\r
\r
1. Call `GET /v1/contacts` to list all contacts, or use `search` to find by name/company.\r
2. Call `GET /v1/contacts/{id}` for full contact details.\r
3. To add a new contact, call `POST /v1/contacts` with at least `firstName` and `lastName`.\r
4. To update contact info, call `PATCH /v1/contacts/{id}` with the fields to change. Pass `null` to clear optional fields.\r
5. To delete, call `DELETE /v1/contacts/{id}`.\r
\r
### Managing work experiences\r
\r
1. Call `GET /v1/experiences` to list all work experiences.\r
2. Call `GET /v1/experiences/{id}` to see full details of a specific experience.\r
3. To add a new experience, call `POST /v1/experiences` with at least `jobTitle` and `company`.\r
4. To update, call `PATCH /v1/experiences/{id}` with the fields to change. Pass `null` to clear optional fields.\r
5. To delete, call `DELETE /v1/experiences/{id}`.\r
\r
### Managing education\r
\r
1. Call `GET /v1/education` to list all education entries.\r
2. Call `GET /v1/education/{id}` to see full details of a specific education entry.\r
3. To add, call `POST /v1/education` with at least `institution` and `degree`.\r
4. To update, call `PATCH /v1/education/{id}` with the fields to change. Pass `null` to clear optional fields.\r
5. To delete, call `DELETE /v1/education/{id}`.\r
\r
### Managing skills\r
\r
1. Call `GET /v1/skills` to list all skills.\r
2. Call `GET /v1/skills/{id}` to see details of a specific skill.\r
3. To add a skill, call `POST /v1/skills` with at least `name`.\r
4. To update, call `PATCH /v1/skills/{id}` with the fields to change. Pass `null` to clear optional fields.\r
5. To delete, call `DELETE /v1/skills/{id}`.\r
\r
### Managing resumes\r
\r
1. Call `GET /v1/resume` to see all resumes and find the right one.\r
2. Call `GET /v1/resume/{id}` to read the full content of a resume.\r
3. To create a new resume, call `POST /v1/resume` with a name and optional content.\r
4. To update resume content (add skills, experiences, etc.), call `PATCH /v1/resume/{id}` with the fields to change.\r
5. To export as PDF, call `POST /v1/resume/{id}/export/pdf` and save the binary response to a file.\r
6. To delete, call `DELETE /v1/resume/{id}`. Linked applications are unlinked, not deleted.\r
\r
---\r
\r
## Error Handling\r
\r
| Status | Meaning                  | What to do                                                        |\r
|--------|--------------------------|-------------------------------------------------------------------|\r
| 400    | Bad request / validation | Check the `details` field for which fields failed. Fix and retry. |\r
| 401    | Invalid or missing token | Tell the user their API key is invalid or expired.                |\r
| 403    | Insufficient permissions | The API key does not have the required scope for this endpoint.   |\r
| 404    | Not found                | The application or profile does not exist.                        |\r
| 409    | Processing               | Resume is being tailored by auto-prep. Wait and retry.            |\r
| 429    | Rate limited             | Wait before retrying. Do not hammer the endpoint.                 |\r
| 500    | Server error             | Retry once. If it persists, tell the user something went wrong.   |\r
| 503    | Service unavailable      | Rate limiter or export service is temporarily down. Retry after a short wait. |\r
\r
Always check the HTTP status before parsing the response body. On errors, the body contains an `error` field with a human-readable message.\r
\r
---\r
\r
## Documentation\r
\r
Full API documentation is available at [docs.mokaru.ai](https://docs.mokaru.ai).\r
Usage Guidance
This skill appears coherent and only needs your Mokaru API key (MOKARU_API_KEY) and common CLI tools. Before installing: (1) Only provide a Mokaru API key you trust — it grants the skill access to your Mokaru account (search, tracker, profile, resume endpoints). Create a least-privilege or revocable key in Mokaru if possible. (2) Confirm the API scopes the key permits (e.g., tracker:write) and monitor your Mokaru account activity; revoke the key if you see unexpected calls. (3) Note the skill explicitly says it does NOT submit applications for you — it will save and prepare applications and provide the apply link. (4) There is no installable code here (instruction-only), but provenance is limited: registry metadata and SKILL.md versions differ and no homepage/source URL is provided; if you need stronger assurance, request the publisher/source or check docs.mokaru.ai and create a scoped API key before granting access.
Capability Analysis
Type: OpenClaw Skill Name: auto-apply Version: 1.0.7 The auto-apply skill bundle is a legitimate integration for the Mokaru career management platform (api.mokaru.ai). It provides comprehensive instructions for an AI agent to manage job searches, resumes, applications, and professional profiles using standard REST API calls via curl and jq. The skill includes explicit safety instructions ensuring the agent does not submit applications without user intervention, and no evidence of malicious behavior, unauthorized data exfiltration, or prompt injection was found in SKILL.md or README.md.
Capability Tags
requires-oauth-tokenrequires-sensitive-credentials
Capability Assessment
Purpose & Capability
Name/description (job search, resume tailoring, application tracking) align with the declared requirements: a single MOKARU_API_KEY and curl/jq for making API calls. The endpoints and scopes described (jobs:search, tracker:write, profile, resumes, contacts, etc.) match the stated purpose. Minor note: SKILL.md header lists version 2.0.0 while registry metadata lists 1.0.7, and the skill's source/homepage are not provided — a provenance gap but not a technical incoherence.
Instruction Scope
SKILL.md gives concrete curl-based instructions to call https://api.mokaru.ai/v1/... using a Bearer token from MOKARU_API_KEY. Instructions stay within the stated scope (search, create/list/update tracker, profile/resume endpoints) and explicitly note the skill does NOT submit applications on the user's behalf. There are no instructions to read unrelated files, other env vars, or to transmit data to endpoints outside mokaru.ai.
Install Mechanism
This is an instruction-only skill with no install spec and no code files, so nothing is written to disk and no additional packages are pulled in.
Credentials
Only a single credential (MOKARU_API_KEY) is required, which is proportional to the described API usage. Required binaries (curl, jq) are reasonable for executing the provided examples. No unrelated secrets or system config paths are requested.
Persistence & Privilege
always is false and the skill is user-invocable with normal model invocation allowed (default). The skill does not request persistent system-wide privileges or modify other skills; no concerning persistence behavior is present.
How to Use
  1. Make sure OpenClaw is installed (local or Docker)
  2. Run the install command in chat: /install auto-apply
  3. After installation, invoke the skill by name or use /auto-apply
  4. Provide required inputs per the skill's parameter spec and get structured output
Version History
v1.0.7
No user-visible changes in this release.
v1.0.6
No code or SKILL.md changes detected in this version. - No updates or functional changes from the previous release. - All features and documentation remain the same.
v1.0.5
Version 2.0.0 is a major release for the auto-apply skill. - Introduced explicit versioning in the SKILL.md for better clarity and tracking. - No functional or behavioral changes; documentation structure remains the same. - All endpoints, usage guidance, and workflows are unchanged from previous release.
v1.0.4
- Expanded skill description for broader user intent coverage, including resume optimization and career coaching. - Clarified support for both remote and on-site roles, and application to all industries. - Added explicit use cases: job hunting, career search, applying for jobs, interview prep, resume optimization, and tracking. - Core functionality and endpoints remain unchanged.
v1.0.3
Summary: Adds auto-prep resume tailoring support for tracked jobs. - Introduced the autoPrepare option when creating applications, allowing Mokaru to duplicate and tailor the user's resume to the job using AI. - Detailed API requirements and constraints for autoPrepare, including plan, resume, and job description length. - Updated documentation to reflect new workflow and error codes for auto-prep scenarios. - No changes to endpoints for searching or listing jobs and applications.
v1.0.2
- Clarified that the skill does not submit job applications directly; it only helps you find jobs, save and track them, and prepare to apply. - Updated description and documentation to explicitly state that actual application submission is handled by the user or their agent, not by the skill. - Added workflow instructions: when the user wants to apply, save the job to their tracker and provide the apply link for manual completion. - No changes to endpoints or technical requirements; the skill's API usage remains the same.
v1.0.1
- No functional or behavioral changes; documentation and references updated to reflect the new skill name
v1.0.0
Initial release of the Mokaru Job Search & Application Tracker skill. - Search for jobs with detailed filters such as location, remote options, employment type, and date posted. - Save and track job applications, including support for duplicate detection and auto-filling from search results. - View and filter your tracked applications by status with pagination options. - Update tracked applications to change their status, priority, or other details. - Uses secure API authentication with a required bearer token.
Metadata
Slug auto-apply
Version 1.0.7
License MIT-0
All-time Installs 0
Active Installs 0
Total Versions 8
Frequently Asked Questions

What is Automate your Job Search?

Automate your job search and application process with Mokaru. Search thousands of jobs, tailor your resume to each role, track applications through your pipe... It is an AI Agent Skill for Claude Code / OpenClaw, with 345 downloads so far.

How do I install Automate your Job Search?

Run "/install auto-apply" in the OpenClaw or Claude Code chat to install it in one step — no extra setup required.

Is Automate your Job Search free?

Yes, Automate your Job Search is completely free, licensed under MIT-0. You can download, install and use it at no cost.

Which platforms does Automate your Job Search support?

Automate your Job Search is cross-platform and runs anywhere OpenClaw / Claude Code is available (cross-platform).

Who created Automate your Job Search?

It is built and maintained by VNDCK (@vndck); the current version is v1.0.7.

💬 Comments