# API

Base URL is environment-specific. Paid endpoints require an `Authorization: Bearer igsk_...` header.

## Auth

Customer keys are opaque `igsk_` bearer tokens and are visible only once at creation. The service stores SHA-256 hashes, not raw keys.

Header:

```text
Authorization: Bearer igsk_...
```

Owner/admin keys are configured by `OWNER_ADMIN_KEY_SHA256` and are unbilled. Admin routes require that owner key.

## `GET /health`

Returns service status without authentication.

Response:

```json
{
  "status": "ok",
  "service": "igskill.md",
  "version": "dev",
  "timestamp": "2026-06-28T00:00:00.000Z"
}
```

## MVP Scope

The M1 public API is URL-first. It accepts public Instagram post/reel URLs or shortcodes and returns normalized JSON for agent consumption. Profile/search/discovery endpoints are deferred until provider reliability, pricing, and policy risk are better understood.

All paid responses should include:

- `data`: normalized media or comments.
- `provider`: sanitized provider id, billed unit, and result count when available.
- `cache`: `hit`, `miss`, or `stale` plus cache key and TTL when available.
- `usage`: price card version plus reserved, settled, and refunded micro-credits.
- `limitations`: provider-visible gaps such as missing transcript, incomplete comments, short-lived media URLs, or unsupported private/login-only content.
- `parse`: optional hosted AI output when a parse mode is requested.

## M1 Endpoints

### `POST /v1/signup`

Creates an account and returns a one-time visible `igsk_` key. Store only the key hash.

Request:

```json
{
  "accountName": "Example agent team",
  "keyName": "local-dev"
}
```

Response:

```json
{
  "account": {
    "id": "acct_...",
    "name": "Example agent team",
    "createdAt": "2026-06-28T00:00:00.000Z"
  },
  "key": {
    "id": "key_...",
    "accountId": "acct_...",
    "name": "local-dev",
    "role": "customer",
    "unbilled": false,
    "prefix": "igsk_",
    "createdAt": "2026-06-28T00:00:00.000Z"
  },
  "apiKey": "igsk_...",
  "warning": "Store this API key now. It will not be shown again."
}
```

### `GET /v1/me`

Requires any valid `igsk_` bearer token. Returns key metadata for debugging auth without exposing key hashes or secrets.

### `GET /v1/post`

Query:

- `url`: Instagram post/carousel URL or shortcode.
- `parse`: omitted, `summary`, `tldr`, or `json`.
- `comments`: omitted, `none`, or `latest`.
- `commentLimit`: `20` or `100`. Use `GET /v1/comments` for `500` comment batches.

Returns normalized `InstagramMedia` for `image`, `video`, or `carousel` media:

- `shortcode`, `url`, `canonicalUrl`, and `type`.
- Caption, hashtags, mentions, owner summary, timestamp, and metrics when available.
- Media assets and carousel children when available. Provider media URLs can be short-lived and should be labelled as such.
- Optional latest comments when requested and provider-visible.
- Cache, provider, usage, and limitations metadata.
- Billing reserves before provider spend, settles successful reads, and refunds failed upstream/provider/parser attempts.

### `GET /v1/reel`

Query:

- `url`: Instagram reel URL or shortcode.
- `transcript`: omitted, `false`, `provider`, or `true`.
- `parse`: omitted, `summary`, `tldr`, or `json`.
- `comments`: omitted, `none`, or `latest`.
- `commentLimit`: `20` or `100`. Use `GET /v1/comments` for `500` comment batches.

Transcript behavior:

- `false` skips transcript spend.
- `provider` uses only a provider-supplied transcript.
- `true` uses provider transcript first. If the provider does not return one, igskill calls the hosted Achronon/ClaudeVPS transcription boundary when `ACHRONON_AI_ENDPOINT` and `ACHRONON_AI_SERVICE_TOKEN` are configured.
- If no transcript is available, return the reel without a transcript and include a limitation instead of failing the whole read.

Hosted transcription request routing:

- `ACHRONON_AI_ENDPOINT` should point at the ClaudeVPS sandbox base, for example `https://api.claudevps.com/sandboxes/<sandbox-id>`.
- `ACHRONON_AI_TRANSCRIBE_PATH` defaults to `/claudex/transcribe`.
- `ACHRONON_AI_TRANSCRIBE_MODEL` defaults to `auto`. ClaudeVPS accepts the legacy `gpt-4o-mini-transcribe` hint and maps it to `auto`.
- `ACHRONON_AI_TRANSCRIBE_MAX_DURATION_SEC` defaults to `180`.
- igskill passes a provider media URL, media identity, model, task, and duration cap. ClaudeVPS owns download, audio extraction, relay Codex auth, model execution, and transcript normalization.

Returns normalized `InstagramMedia` with `type: "reel"` plus reel-specific metrics, music/audio metadata, optional transcript, cache, provider, usage, and limitations metadata.

Reel `summary`, `tldr`, and `json` parse payloads combine the caption and transcript when available. If comments are requested, the summary payload may include the same deterministic ranked comment sample used by comment analysis, including notable replies and low-signal filtering metadata.
Billing reserves before provider spend, settles successful reads, and refunds failed upstream/provider/parser attempts. Parsed reel summaries that include comments reserve both media parse and comment parse line items.

### `GET /v1/comments`

Query:

- `url`: post or reel URL.
- `limit`: `20`, `100`, or `500`, default `100`.
- `includeReplies`: `true` or `false`, default `false`.
- `parse`: omitted, `themes`, `sentiment`, `json`, `questions`, `objections`, `consensus`, `notable_replies`, `spam_low_signal`, or `entities`.

Returns normalized comments and optional replies:

- Comment id, parent id, text, owner summary, timestamp, like count, reply count, and permalink when available.
- `truncated: true` and sampling/ranking notes when the provider returns fewer comments than requested or applies ordering the API cannot verify.
- Cache, provider, usage, and limitations metadata.
- Billing reserves by batch size before provider spend, settles successful reads, and refunds failed upstream/provider/parser attempts.

### Parse Modes

All endpoint responses are JSON. `parse` means hosted AI interpretation, not response serialization.

Media parse modes:

- `summary`: concise natural-language summary for the post/reel.
- `tldr`: shorter agent-facing takeaway.
- `json`: structured hosted interpretation for agent workflows.

OCR/vision over images, carousel frames, stickers, screenshots, or on-image text is not enabled in M1. Responses should expose this as a limitation when relevant rather than implying visual inspection was performed.

Comment parse modes:

- `themes`: recurring themes and representative comments.
- `sentiment`: coarse positive/neutral/negative distribution with caveats.
- `json`: structured hosted interpretation over the returned comment sample.
- `questions`: recurring questions and unclear points.
- `objections`: purchase, trust, pricing, feature, or credibility objections.
- `consensus`: areas of broad agreement or disagreement.
- `notable_replies`: important replies and reply-thread context.
- `spam_low_signal`: spam, bot-like, or low-signal comment patterns.
- `entities`: people, brands, products, places, and named entities mentioned in comments.

M1 parse outputs must use the hosted Achronon/ClaudeVPS boundary, be cacheable by content hash, parse mode, model, and prompt version, and include limitations for sampled comments, missing transcript, missing caption, or stale metrics.

## Deferred Endpoints

- `GET /v1/profile?username=<username>`.
- `GET /v1/search?type=hashtag|profile|place&query=<query>`.
- OCR/vision enrichment for image/carousel media.

These are M2/M3 only if provider pricing and reliability support them. Profile/search are deferred by decision `0010`; they are not required for the M1 URL-read API.

## Billing/Admin

### `POST /v1/topups/checkout`

Requires a customer `igsk_` bearer token. Creates a Stripe Checkout session for a prepaid top-up.

Request:

```json
{
  "microCredits": 1000000
}
```

Response:

```json
{
  "checkoutSession": {
    "id": "cs_...",
    "url": "https://checkout.stripe.com/..."
  },
  "microCredits": 1000000
}
```

### `POST /v1/stripe/webhook`

Receives Stripe checkout completion events and grants credits from checkout metadata after signature verification. The current lightweight boundary expects completed checkout metadata to include `accountId` and `microCredits`.

### `GET /v1/ops/metrics`

`GET /v1/ops/metrics` requires the owner/admin key. It currently returns scaffold metrics and whether providers are configured, without secret values.

## Error Shape

Sanitized error shape:

```json
{
  "error": {
    "code": "provider_unavailable",
    "message": "Instagram provider is temporarily unavailable.",
    "requestId": "req_..."
  }
}
```

Provider raw errors and secrets must not be exposed.

See `docs/error-taxonomy.md` for codes, HTTP statuses, and operator actions.
