> For the complete documentation index, see [llms.txt](https://docs.appmixer.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.appmixer.com/build-connectors-with-a-coding-agent/first-component.md).

# Your First Component

There is another first-connector walkthrough in these docs — [Build a Custom Connector](/getting-started/custom-connectors.md), which has you scaffold the files by hand with `appmixer init example` to learn the anatomy. This chapter does the opposite: an agent writes the files against a real API while you read what it produces.

By the end you will have one component that talks to a live service from your machine, through the same authentication your users will use. Nothing is published yet — that needs a decision that belongs in chapter 4.

## Decide the auth type before you prompt

Read the service's API documentation for one thing first: how a third-party app is meant to authenticate. Decide that once, before the first prompt — changing it on a connector people already use breaks every existing account ([Day-to-Day Work](/build-connectors-with-a-coding-agent/daily.md#changing-the-auth-type-of-a-published-connector)).

Eventbrite offers a private token and OAuth 2.0. A private-token connector works — each user pastes their own token — but on Eventbrite a user can only get one by registering an application first. With OAuth you register one application and your users click *Connect*. This guide uses OAuth 2.0.

## Register the app first

Create an application in the service's developer portal. Most portals ask for metadata that is not checked — Eventbrite wants an *Application URL* and a *Description*, and neither has to be real. **Leave the OAuth redirect field empty for now**; its value does not exist until the connector does.

Eventbrite then issues four values on one screen, with no explanation:

| Value             | What it is for                                |
| ----------------- | --------------------------------------------- |
| **API Key**       | The OAuth **client id** — what `-c` wants     |
| **Client Secret** | The OAuth **client secret** — what `-s` wants |
| Private Token     | Not used by an OAuth connector                |
| Public Token      | Not used at all                               |

Nothing on that screen says "client id". Write the mapping down before you start.

## Choose a component that cannot come back empty

Do not start with a list. On a new account a list returns nothing, and **an empty result is indistinguishable from a broken component** — agents and people misread it alike.

Start with an endpoint that always returns exactly one object: `/users/me`, `/me`, `/account`, `/whoami`. It proves authentication, transport and output mapping in one run. It is also the endpoint your auth module will use to name and validate accounts, so the work is reused.

## The prompt

> I want to build an Appmixer connector for Eventbrite. Documentation is on eventbrite.com/platform/docs. Start with one component to get my user profile. Authentication is OAuth 2.0.

Four things carry weight: the **service**, the **docs URL**, **one** named component, and the **auth type**. Add **your vendor** if it is not `appmixer` — the agent will not ask, and names everything under the scaffolder's default otherwise. [Scope and Research](/build-connectors-with-a-coding-agent/research.md) explains why it matters.

The agent then works unattended for a few minutes: it reads the skill's design rules, researches the API, scaffolds the connector, writes the component, reviews its own work and runs `appmixer connector validate`. When a documentation site renders with JavaScript, as Eventbrite's does, the agent may fall back on other sources or its own knowledge; it should say so, and the live test below settles it.

## What it built

```
src/<vendor>/eventbrite/
├── service.json          the connector as the Designer sees it: label, category, icon
├── bundle.json           version and changelog
├── auth.js               the authentication module
├── quota.js              rate limits, expressed as rules
├── core/
│   └── GetMyProfile/
│       ├── component.json    the manifest: ports, inputs, output schema
│       └── GetMyProfile.js   the behaviour: what runs when a message arrives
└── artifacts/            the agent's working notes; never published
```

[Basic Structure](/building-connectors/basic-structure.md) explains the hierarchy and the [Manifest](/building-connectors/manifest.md) reference documents every key. Check three things:

* **`auth.js`** declares `type: 'oauth2'` and the authorize and token endpoints, and holds no client id or secret.
* **`quota.js`** holds limits the service documents — for Eventbrite, 2,000 calls an hour and 48,000 a day. A limit tighter than the service's own fails in ways that look like the service's fault.
* **The icon** is a placeholder. The real one is yours to supply — see [Scope and Research](/build-connectors-with-a-coding-agent/research.md#give-it-the-real-icon).

`connector validate` reports one failing rule, `connector-has-makeapicall`: every connector is expected to carry a generic "call any endpoint" component. Chapter 3 adds it.

## The first human gate

The agent stops with a question like:

> Ready to plan and run CLI tests for `eventbrite`. Shall I go ahead?

Everything so far touched only your disk; the next step makes real API calls, and the skills draw the line there. Before you say yes, the test needs a token — and getting one is yours to do.

## Authorize locally

`appmixer test auth login` starts a local server on port 2300, opens the consent screen in your browser, and stores the token it gets back for the component tests:

```bash
appmixer test auth login src/<vendor>/<connector>/auth.js -c <apiKey> -s <clientSecret>
```

**Run it in a terminal of your own.** The command line carries your client secret and the CLI prints the access token in full. An agent may suggest running it with Claude Code's `!` prefix — that puts both into the conversation.

### The redirect URI: read it, do not build it

The service only redirects to a URI you registered, matching byte for byte. The CLI builds it as:

```
http://<host>:2300/auth/<service>/callback
```

where `<service>` is the service part of the name, with no vendor and no colon: `acme:eventbrite` gives `/auth/eventbrite/callback`, `appmixer:google:gmail` gives `/auth/google/callback`.

Do not assemble it yourself, and do not take an agent's word for it — agents get it wrong. The CLI prints the exact value on the line after `Opening authentication URL in browser:`, as the `redirect_uri` parameter. Register that, then run the login again. (Running the login with made-up credentials just to see the URL stores them as your client id and secret; run the real login afterwards.)

### If the service rejects the redirect URI

**A bare `403` page, often from CloudFront.** Some providers refuse loopback redirect URIs, Eventbrite among them. Use a hostname that resolves to your machine but is not loopback:

```bash
appmixer test auth login src/<vendor>/<connector>/auth.js \
  -u http://lvh.me:2300 -c <apiKey> -s <clientSecret>
```

`-u` (or `TEST_SERVER_URL`) changes the host in the redirect URI; the local server still listens on that port. `lvh.me` and `127-0-0-1.nip.io` both resolve to `127.0.0.1`. Register the rewritten URI.

<details>

<summary>What Eventbrite accepts</summary>

Eventbrite's firewall string-matches the host of `redirect_uri`:

| `redirect_uri` host        | Response  |
| -------------------------- | --------- |
| `http://localhost:2300/…`  | `403`     |
| `http://127.0.0.1:2300/…`  | `403`     |
| `https://localhost:2300/…` | `403`     |
| `127.0.0.1.nip.io`         | `403`     |
| **`127-0-0-1.nip.io`**     | **`302`** |
| **`lvh.me`**               | **`302`** |
| `http://example.com/…`     | `302`     |

</details>

**`Redirect URI hostnames must match`.** Eventbrite shows this when the registered value differs from the one sent in *any* part, the path included. Compare the two strings character by character.

{% hint style="info" %}
**Not every OAuth 2.0 service issues a refresh token.** Eventbrite does not, and its tokens do not expire, so the CLI prints `Missing refresh token, this can be ok, but most Oauth2 services return refresh token.` in red. That is correct, not an error.
{% endhint %}

Once the login succeeds, tell the agent, and answer yes to its question.

## Verify

```bash
appmixer test component src/<vendor>/eventbrite/core/GetMyProfile -i '{"in":{}}'
```

One message on the `out` port, carrying your own profile with every field the manifest declares, and exit code `0`. The agent picks the component name from your prompt; use the directory it created.

{% hint style="warning" %}
`appmixer test component` takes a **directory path**, not a component type. `appmixer test component acme.eventbrite.core.GetMyProfile` is an error, and the message does not say why.
{% endhint %}

That one green run proves the credential, the redirect URI, the stored token, the request and the declared output all at once.

## Do not publish this yet

Publishing fixes your **vendor** — the namespace in every component name — and changing it later renames everything and strands the old copies on the instance. That decision, and the rights to publish, are in chapter 4.

Next: [Scope and Research](/build-connectors-with-a-coding-agent/research.md).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.appmixer.com/build-connectors-with-a-coding-agent/first-component.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
