> ## Documentation Index
> Fetch the complete documentation index at: https://developers.semji.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Quickstart

> Create your API key, retrieve your workspace, import a page, and optimize it with Atomic Content — all from the command line.

This guide walks you through the four steps to go from zero to an AI-optimized content draft using the Semji API.

<Note>
  You need a Semji account to follow this guide. Sign up or log in at [app.semji.com](https://app.semji.com).
</Note>

## 1. Create your API key

<Steps>
  <Step title="Open API key settings">
    Log in to [app.semji.com](https://app.semji.com), then go to **Settings > Organization > API Keys**.
  </Step>

  <Step title="Generate a key">
    Click **New API key**, give it a name (e.g. `quickstart`), and click **Create**.
  </Step>

  <Step title="Copy the key">
    Your key is shown once. Copy it now — you won't be able to see it again. All keys start with `sk_`.
  </Step>
</Steps>

<Warning>
  Treat your API key like a password. Don't commit it to source control or include it in client-side code.
</Warning>

Export it in your terminal to use it in the commands below:

```bash theme={null}
export SEMJI_API_KEY="sk_your_api_key_here"
```

TypeScript examples read exported values with `process.env`. Python examples read them with `os.environ[...]`.

## 2. Test your key

Call `GET /v1/me` to verify your key works and see your organization:

<CodeGroup>
  ```typescript TypeScript theme={null}
  const response = await fetch("https://api.semji.com/v1/me", {
    headers: { Authorization: `Bearer ${process.env.SEMJI_API_KEY}` },
  });
  console.log(await response.json());
  ```

  ```python Python theme={null}
  import os
  import requests

  response = requests.get(
      "https://api.semji.com/v1/me",
      headers={"Authorization": f"Bearer {os.environ['SEMJI_API_KEY']}"},
  )
  print(response.json())
  ```

  ```bash cURL theme={null}
  curl https://api.semji.com/v1/me \
    -H "Authorization: Bearer $SEMJI_API_KEY"
  ```
</CodeGroup>

You should get back your user profile and organization:

```json theme={null}
{
  "id": "df286a001943",
  "firstName": "Jane",
  "lastName": "Smith",
  "email": "jane@example.com",
  "createdAt": "2024-03-15T10:30:00+00:00",
  "jobTitle": "Marketing Manager",
  "languageCode": "en",
  "profileImageUrl": null,
  "organization": {
    "id": "89b0f07aade2",
    "name": "Example Corp",
    "createdAt": "2024-01-10T08:00:00+00:00",
    "brandName": null,
    "brandImageUrl": null,
    "credits": {
      "analysis": 47,
      "aiWriting": 12,
      "contentIdeasSearches": 5
    },
    "usersCount": 3,
    "workspacesCount": 2
  }
}
```

## 3. Get your workspace

A workspace represents one website in Semji. List your workspaces to grab the `id` you'll use in the next steps:

<CodeGroup>
  ```typescript TypeScript theme={null}
  const response = await fetch("https://api.semji.com/v1/workspaces", {
    headers: { Authorization: `Bearer ${process.env.SEMJI_API_KEY}` },
  });
  const { data } = await response.json();
  console.log(data[0].id, data[0].name);
  ```

  ```python Python theme={null}
  import os
  import requests

  response = requests.get(
      "https://api.semji.com/v1/workspaces",
      headers={"Authorization": f"Bearer {os.environ['SEMJI_API_KEY']}"},
  )
  workspaces = response.json()["data"]
  print(workspaces[0]["id"], workspaces[0]["name"])
  ```

  ```bash cURL theme={null}
  curl https://api.semji.com/v1/workspaces \
    -H "Authorization: Bearer $SEMJI_API_KEY"
  ```
</CodeGroup>

Save your workspace ID:

```bash theme={null}
export WORKSPACE_ID="6c629e33a9a6"
```

## 4. Import a page and optimize it

### Import the page

Import a URL into your workspace. You can optionally attach a focus keyword right away:

<CodeGroup>
  ```typescript TypeScript theme={null}
  const response = await fetch(
    `https://api.semji.com/v1/workspaces/${process.env.WORKSPACE_ID}/pages`,
    {
      method: "POST",
      headers: {
        Authorization: `Bearer ${process.env.SEMJI_API_KEY}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        url: "https://example.com/blog/my-article",
        focusKeyword: "content marketing strategy",
      }),
    }
  );
  const page = await response.json();
  console.log(page.id);
  ```

  ```python Python theme={null}
  import os
  import requests

  response = requests.post(
      f"https://api.semji.com/v1/workspaces/{os.environ['WORKSPACE_ID']}/pages",
      headers={
          "Authorization": f"Bearer {os.environ['SEMJI_API_KEY']}",
          "Content-Type": "application/json",
      },
      json={
          "url": "https://example.com/blog/my-article",
          "focusKeyword": "content marketing strategy",
      },
  )
  page = response.json()
  print(page["id"])
  ```

  ```bash cURL theme={null}
  curl -X POST "https://api.semji.com/v1/workspaces/$WORKSPACE_ID/pages" \
    -H "Authorization: Bearer $SEMJI_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "url": "https://example.com/blog/my-article",
      "focusKeyword": "content marketing strategy"
    }'
  ```
</CodeGroup>

The response returns the page with its `id` and crawled metadata (title, word count, etc.). Save the page ID for the next step:

```bash theme={null}
export PAGE_ID="1b81be0eb082"
```

### Create a content draft

Create a content linked to the page you just imported:

<CodeGroup>
  ```typescript TypeScript theme={null}
  const contentRes = await fetch(
    `https://api.semji.com/v1/workspaces/${process.env.WORKSPACE_ID}/contents`,
    {
      method: "POST",
      headers: {
        Authorization: `Bearer ${process.env.SEMJI_API_KEY}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        title: "Content Marketing Strategy for 2025",
        pageId: process.env.PAGE_ID,
      }),
    }
  );
  const content = await contentRes.json();
  console.log(content.id);
  ```

  ```python Python theme={null}
  import os
  import requests

  response = requests.post(
      f"https://api.semji.com/v1/workspaces/{os.environ['WORKSPACE_ID']}/contents",
      headers={
          "Authorization": f"Bearer {os.environ['SEMJI_API_KEY']}",
          "Content-Type": "application/json",
      },
      json={
          "title": "Content Marketing Strategy for 2025",
          "pageId": os.environ["PAGE_ID"],
      },
  )
  content = response.json()
  print(content["id"])
  ```

  ```bash cURL theme={null}
  curl -X POST "https://api.semji.com/v1/workspaces/$WORKSPACE_ID/contents" \
    -H "Authorization: Bearer $SEMJI_API_KEY" \
    -H "Content-Type: application/json" \
    -d "{
      \"title\": \"Content Marketing Strategy for 2025\",
      \"pageId\": \"$PAGE_ID\"
    }"
  ```
</CodeGroup>

Save the content ID:

```bash theme={null}
export CONTENT_ID="3a89fc29d1f3"
```

### Analyze the focus keyword

Before generating content, the focus keyword needs a completed SEO analysis. Trigger it with `POST /v1/keywords/:id/analyze` using the keyword ID returned during page import:

```bash theme={null}
export KEYWORD_ID="b211968d8d46"
```

<CodeGroup>
  ```typescript TypeScript theme={null}
  await fetch(
    `https://api.semji.com/v1/keywords/${process.env.KEYWORD_ID}/analyze`,
    {
      method: "POST",
      headers: { Authorization: `Bearer ${process.env.SEMJI_API_KEY}` },
    }
  );
  ```

  ```python Python theme={null}
  import os
  import requests

  requests.post(
      f"https://api.semji.com/v1/keywords/{os.environ['KEYWORD_ID']}/analyze",
      headers={"Authorization": f"Bearer {os.environ['SEMJI_API_KEY']}"},
  )
  ```

  ```bash cURL theme={null}
  curl -X POST "https://api.semji.com/v1/keywords/$KEYWORD_ID/analyze" \
    -H "Authorization: Bearer $SEMJI_API_KEY"
  ```
</CodeGroup>

Poll `GET /v1/keywords/:id` until `analysisStatus` reaches `success`:

<CodeGroup>
  ```typescript TypeScript theme={null}
  while (true) {
    const res = await fetch(
      `https://api.semji.com/v1/keywords/${process.env.KEYWORD_ID}`,
      { headers: { Authorization: `Bearer ${process.env.SEMJI_API_KEY}` } }
    );
    const kw = await res.json();
    console.log(`Analysis: ${kw.analysisStatus}`);
    if (["success", "failed"].includes(kw.analysisStatus)) break;
    await new Promise((r) => setTimeout(r, 5000));
  }
  ```

  ```python Python theme={null}
  import os
  import time
  import requests

  while True:
      kw = requests.get(
          f"https://api.semji.com/v1/keywords/{os.environ['KEYWORD_ID']}",
          headers={"Authorization": f"Bearer {os.environ['SEMJI_API_KEY']}"},
      ).json()
      print(f"Analysis: {kw['analysisStatus']}")
      if kw["analysisStatus"] in ("success", "failed"):
          break
      time.sleep(5)
  ```

  ```bash cURL theme={null}
  curl "https://api.semji.com/v1/keywords/$KEYWORD_ID" \
    -H "Authorization: Bearer $SEMJI_API_KEY"
  ```
</CodeGroup>

<Note>
  The analysis typically completes within 30 to 90 seconds.
</Note>

### Launch Atomic Content

Trigger an AI content generation on the draft. Use `replace` to generate from scratch or `optimize` to rewrite existing content:

<CodeGroup>
  ```typescript TypeScript theme={null}
  await fetch(
    `https://api.semji.com/v1/contents/${process.env.CONTENT_ID}/atomic`,
    {
      method: "POST",
      headers: {
        Authorization: `Bearer ${process.env.SEMJI_API_KEY}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({ type: "replace" }),
    }
  );
  ```

  ```python Python theme={null}
  import os
  import requests

  requests.post(
      f"https://api.semji.com/v1/contents/{os.environ['CONTENT_ID']}/atomic",
      headers={
          "Authorization": f"Bearer {os.environ['SEMJI_API_KEY']}",
          "Content-Type": "application/json",
      },
      json={"type": "replace"},
  )
  ```

  ```bash cURL theme={null}
  curl -X POST "https://api.semji.com/v1/contents/$CONTENT_ID/atomic" \
    -H "Authorization: Bearer $SEMJI_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{ "type": "replace" }'
  ```
</CodeGroup>

### Poll for completion

The generation runs asynchronously. Poll `GET /v1/contents/:id/generation` until the status reaches `review`:

<CodeGroup>
  ```typescript TypeScript theme={null}
  while (true) {
    const res = await fetch(
      `https://api.semji.com/v1/contents/${process.env.CONTENT_ID}/generation`,
      { headers: { Authorization: `Bearer ${process.env.SEMJI_API_KEY}` } }
    );
    const { status } = await res.json();
    console.log(`Status: ${status}`);
    if (["review", "failed", "cancelled"].includes(status)) break;
    await new Promise((r) => setTimeout(r, 5000));
  }
  ```

  ```python Python theme={null}
  import os
  import time
  import requests

  while True:
      status = requests.get(
          f"https://api.semji.com/v1/contents/{os.environ['CONTENT_ID']}/generation",
          headers={"Authorization": f"Bearer {os.environ['SEMJI_API_KEY']}"},
      ).json()
      print(f"Status: {status['status']}")
      if status["status"] in ("review", "failed", "cancelled"):
          break
      time.sleep(5)
  ```

  ```bash cURL theme={null}
  curl "https://api.semji.com/v1/contents/$CONTENT_ID/generation" \
    -H "Authorization: Bearer $SEMJI_API_KEY"
  ```
</CodeGroup>

Possible statuses: `queued` → `pending` → `review` → `success` (after confirm) or `failed` / `cancelled`.

### Confirm the draft

Once the status is `review`, confirm the generation to apply it to your content:

<CodeGroup>
  ```typescript TypeScript theme={null}
  await fetch(
    `https://api.semji.com/v1/contents/${process.env.CONTENT_ID}/generation/confirm`,
    {
      method: "POST",
      headers: { Authorization: `Bearer ${process.env.SEMJI_API_KEY}` },
    }
  );
  ```

  ```python Python theme={null}
  import os
  import requests

  requests.post(
      f"https://api.semji.com/v1/contents/{os.environ['CONTENT_ID']}/generation/confirm",
      headers={"Authorization": f"Bearer {os.environ['SEMJI_API_KEY']}"},
  )
  ```

  ```bash cURL theme={null}
  curl -X POST "https://api.semji.com/v1/contents/$CONTENT_ID/generation/confirm" \
    -H "Authorization: Bearer $SEMJI_API_KEY"
  ```
</CodeGroup>

Your content is now optimized. Open it in the [Semji editor](https://app.semji.com) to review and publish.

## What's next?

<CardGroup cols={2}>
  <Card title="API Reference" icon="https://mintcdn.com/semji/LJ0P0Pdna2J2p9bi/images/icons/phosphor/code.svg?fit=max&auto=format&n=LJ0P0Pdna2J2p9bi&q=85&s=e5a9ddc47b59179bd1daa40c1bd3ce02" href="/api-reference/overview" width="256" height="256" data-path="images/icons/phosphor/code.svg">
    Explore all available endpoints.
  </Card>

  <Card title="Authentication" icon="https://mintcdn.com/semji/LJ0P0Pdna2J2p9bi/images/icons/phosphor/key.svg?fit=max&auto=format&n=LJ0P0Pdna2J2p9bi&q=85&s=afa19402783376306a7b406f342e5106" href="/api-reference/authentication" width="256" height="256" data-path="images/icons/phosphor/key.svg">
    Rate limits, error handling, and key management.
  </Card>
</CardGroup>
