# Getting started

> Register a Hekana app, send a store through the consent screen, exchange the code for a token and call the Apps API. Which SDK packages exist.

Source: https://hekana.dev/apps/quickstart

This page takes an app from registration to a first Apps API call. Every request below is to the Hekana API at `https://api.hekana.com/api/v1`. Replies are wrapped as `{ "success": true, "data": ..., "requestId": "..." }`, including the OAuth token reply; read `data`.

> **Read this first.** The OAuth flow only runs for **approved** apps, and approval is a manual review. You can register and submit today, but you cannot obtain a token for a draft app. Plan to build against the response shapes in the [API reference](https://hekana.dev/apps/api-reference) until the review passes.

## Packages: what exists

| Package | State |
| - | - |
| `@hekana/apps-sdk` | Typed Apps API client (`HekanaApps`), `verifyWebhook()` and a `hekana-apps` CLI. TypeScript source in the Hekana repository. **Not published to npm.** |
| `hekana-sdk` | A read-only client for the separate agent API (products, orders, customers). **Not on npm.** It does not call the Apps API. |
| `create-hekana-app` | Scaffolds a project that uses `hekana-sdk`. **Not on npm**, so `npx create-hekana-app` does not work yet. |

Until `@hekana/apps-sdk` is released, call the API over HTTP as shown below. Its method names (`orders.list`, `data.put`, `checkoutExtensions.put`) mirror the endpoints, so moving to it later is a small change.

## 1. Register the app

Registering is a call made with the session of a store owner or admin (the developer is a store, and the app belongs to it).

```json title="POST /oauth/apps (request body)"
{
  "name": "Reorder reminders",
  "redirect_uris": ["https://example.com/hekana/callback"],
  "scopes": ["read_orders", "read_customers", "send_messages"],
  "type": "confidential"
}
```

- `redirect_uris`: 1 to 10 addresses. They must be `https` (plain `http` only for `localhost` and `127.0.0.1`) with no fragment, and are matched exactly.
- `scopes`: up to 20, from the list in [Authentication and scopes](https://hekana.dev/apps/authentication).
- `type`: `confidential` (default) gets a client secret; `public` has none and relies on PKCE alone.

The reply holds the app, its `clientId` (starts with `hkna_`) and, for a confidential app, `clientSecret`. **The secret is shown once.** Keep it on your server. `POST /oauth/apps/:id/rotate-secret` replaces it and shows the new one once.

The app starts as a `draft`. Before you can submit it, add its listing (see [Testing and going live](https://hekana.dev/apps/going-live)), then call `POST /oauth/apps/:id/submit`.

## 2. Send a store owner to the consent screen

After approval, send the store owner to the Hekana dashboard page `/oauth/authorize` with these query parameters:

```text
client_id=<your client id>
redirect_uri=<one of your registered redirect URIs>
scope=read_orders read_customers
state=<random value you check on return>
code_challenge=<base64url SHA-256 of your code verifier>
code_challenge_method=S256
```

PKCE with `S256` is required; `plain` is refused. `scope` must be a subset of what the app registered. The owner sees the app name and the scopes, and approves or denies. On approval the browser returns to your `redirect_uri` with `code` and your `state`. A code lives 60 seconds and works once.

## 3. Exchange the code for tokens

```ts title="exchange.ts"
const res = await fetch("https://api.hekana.com/api/v1/oauth/token", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    grant_type: "authorization_code",
    code,                       // from the redirect
    redirect_uri,               // the same one
    client_id: process.env.HEKANA_CLIENT_ID,
    client_secret: process.env.HEKANA_CLIENT_SECRET, // confidential apps
    code_verifier,              // the verifier behind your code_challenge
  }),
});
const { data } = await res.json();
// data: { access_token, token_type: "Bearer", expires_in: 3600, refresh_token, scope }
```

Store both tokens per store. The access token lasts one hour; see [Authentication](https://hekana.dev/apps/authentication) for refresh.

## 4. Call the API

```ts title="first-call.ts"
const res = await fetch("https://api.hekana.com/api/v1/apps-api/orders?limit=5", {
  headers: {
    Authorization: `Bearer ${accessToken}`,
    "Hekana-Api-Version": "2026-10-01",
  },
});
const { data } = await res.json();
// data: { data: [...orders], total, page, limit, nextCursor }
```

The token decides the store. There is no store id in any request.

## 5. Listen for events

Subscribe with `POST /apps-api/webhooks` and verify every delivery. See [Webhooks](https://hekana.dev/apps/webhooks).

## The `hekana-apps` CLI

The command in the SDK source is a thin command line over the same client, for poking at an installation: `orders list`, `products list|get`, `customers list|get`, `data list|get|put|delete` and `verify-webhook`. It reads the token from the `HEKANA_TOKEN` environment variable (never an argument) and prints JSON. It ships as TypeScript source with the SDK and has the same publishing status.
