# Quickstart (no repo, no store listing) (/docs/api/getting-started/quickstart-manual)



The [GitHub quickstart](/docs/api/getting-started/quickstart) needs a repo. The [mobile / App Store quickstart](/docs/api/getting-started/quickstart-mobile) needs a store listing. If you have neither — a local prototype, a weekend build, a Godot side project, an internal tool, anything where you're not shipping to a store yet and don't want to point Layers at a codebase — skip both and wire the SDK in by hand.

You lose the auto-derived brand context (you'll fill that in yourself on the project). You keep everything else: events flow into the Layers pipeline, your `app_id` is valid against every downstream endpoint, and you can upgrade to the ingest paths later without rotating anything.

This page uses steps 1, 2, 3, and 6 from the [main quickstart](/docs/api/getting-started/quickstart) verbatim — start there for `whoami`, project creation, and job polling. Come back here for the ingest-less SDK wiring.

## Prerequisites [#prerequisites]

* Steps 1–3 of the [main quickstart](/docs/api/getting-started/quickstart) complete. You have `$LAYERS_API_KEY` and `$PROJECT_ID`.
* You are OK setting the brand context by hand later via `PATCH /v1/projects/:id` (we can't derive it without code or a listing).

## 1. Register the SDK app — no bundleId, no ingest [#1-register-the-sdk-app--no-bundleid-no-ingest]

`POST /v1/projects/:projectId/sdk-apps` without `bundleId` registers a bare SDK app tied to your project. No scrape, no clone, no workflow — just a row that gives you an `app_id` you can drop into the SDK.

<Tabs items="['curl', 'TypeScript', 'Python']">
  <Tab value="curl">
    ```bash
    curl -X POST "https://api.layers.com/v1/projects/$PROJECT_ID/sdk-apps" \
      -H "X-Api-Key: $LAYERS_API_KEY" \
      -H "Content-Type: application/json" \
      -H "Idempotency-Key: $(uuidgen)" \
      -d '{
        "platform": "web",
        "displayName": "Acme Prototype"
      }'
    ```
  </Tab>

  <Tab value="TypeScript">
    ```ts
    import { randomUUID } from "node:crypto";

    const res = await fetch(
      `https://api.layers.com/v1/projects/${projectId}/sdk-apps`,
      {
        method: "POST",
        headers: {
          "X-Api-Key": process.env.LAYERS_API_KEY!,
          "Content-Type": "application/json",
          "Idempotency-Key": randomUUID(),
        },
        body: JSON.stringify({
          platform: "web",
          displayName: "Acme Prototype",
        }),
      },
    );
    const { app_id } = await res.json();
    ```
  </Tab>

  <Tab value="Python">
    ```python
    import os, uuid, requests

    res = requests.post(
        f"https://api.layers.com/v1/projects/{project_id}/sdk-apps",
        headers={
            "X-Api-Key": os.environ["LAYERS_API_KEY"],
            "Content-Type": "application/json",
            "Idempotency-Key": str(uuid.uuid4()),
        },
        json={
            "platform": "web",
            "displayName": "Acme Prototype",
        },
    )
    app = res.json()
    app_id = app["app_id"]
    ```
  </Tab>
</Tabs>

Response (201 Created):

```json
{
  "app_id": "app_7ffb9410eb0eb848264f8a",
  "platform": "web",
  "displayName": "Acme Prototype",
  "projectId": "254a4ce1-f4ca-42b1-9e36-17ca45ef3d39",
  "createdAt": "2026-04-20T12:00:00.000Z"
}
```

Save `app_id` — every SDK event carries it.

## 2. Fire a test event [#2-fire-a-test-event]

Confirm the pipeline works. `POST /v1/sdk-events` accepts one or many events; we use one here.

<Tabs items="['curl', 'TypeScript', 'Python']">
  <Tab value="curl">
    ```bash
    curl -X POST https://in.layers.com/l/events \
      -H "Content-Type: application/json" \
      -d '{
        "app_id": "'"$APP_ID"'",
        "events": [{
          "event": "layers_test_event",
          "user_id": "demo-user-1",
          "timestamp": "'"$(date -u +%Y-%m-%dT%H:%M:%SZ)"'"
        }]
      }'
    ```
  </Tab>

  <Tab value="TypeScript">
    ```ts
    await fetch("https://in.layers.com/l/events", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        app_id,
        events: [
          {
            event: "layers_test_event",
            user_id: "demo-user-1",
            timestamp: new Date().toISOString(),
          },
        ],
      }),
    });
    ```
  </Tab>

  <Tab value="Python">
    ```python
    import datetime, requests

    requests.post(
        "https://in.layers.com/l/events",
        json={
            "app_id": app_id,
            "events": [
                {
                    "event": "layers_test_event",
                    "user_id": "demo-user-1",
                    "timestamp": datetime.datetime.utcnow().isoformat() + "Z",
                }
            ],
        },
    )
    ```
  </Tab>
</Tabs>

The ingest endpoint returns `202` before the event hits storage — events are batched asynchronously. Confirm arrival via `GET /v1/projects/:projectId/events/users/demo-user-1` a minute later.

## 3. Fill in brand context by hand [#3-fill-in-brand-context-by-hand]

Without an ingest to derive it, set the brand block on the project yourself. Downstream generation (content, influencer narratives, ad creative) reads from this block exactly like the ingest paths populate it.

```bash
curl -X PATCH "https://api.layers.com/v1/projects/$PROJECT_ID" \
  -H "X-Api-Key: $LAYERS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "brand": {
      "appName": "Acme Prototype",
      "tagline": "A weekend experiment.",
      "audience": "hobby developers, curious tinkerers",
      "brandVoice": "casual, self-aware, concise",
      "keywords": ["prototype", "weekend build"]
    }
  }'
```

That's it. You have a project, an SDK app, a live event, and a brand block. You can upgrade to the GitHub or App Store ingest later without rotating the `app_id` — the ingest merges into the existing project.

## See also [#see-also]

* [Quickstart (GitHub path)](/docs/api/getting-started/quickstart) — shared steps 1, 2, 3, 6
* [Quickstart (App Store path)](/docs/api/getting-started/quickstart-mobile) — when you have a listing but no repo
* [`POST /v1/projects/:projectId/sdk-apps`](/docs/api/reference/sdk-apps/create-sdk-app) — full endpoint reference
* [SDK events](/docs/api/reference/telemetry/events) — the event envelope
