# noscha.io - AI Agent Skill Guide

## Service Overview

noscha.io provides **disposable email notifications, subdomain DNS, and NIP-05 Nostr identity** - all paid instantly via Lightning Network. No KYC, no signup, no accounts. Just pick a username, pay sats, and your services are live.

**Base URL:** `https://noscha.io`

## Quick Start (3 Steps)

### Step 1: Check username availability

```
GET /api/check/{username}
```

**Response:**
```json
{"available": true, "username": "alice"}
```

### Step 2: Create order (webhook verification required)

```
POST /api/order
Content-Type: application/json

{
  "username": "alice",
  "plan": "30d",
  "webhook_url": "https://your-server.com/webhook",
  "services": {
    "email": {},
    "subdomain": {"type": "CNAME", "target": "mysite.example.com", "proxied": false},
    "nip05": {"pubkey": "abc123...hex"}
  }
}
```

**Response:**
```json
{
  "order_id": "ord_18f3a...",
  "amount_sats": 6500,
  "bolt11": "",
  "expires_at": "2026-02-11T12:15:00Z",
  "status": "webhook_pending",
  "message": "Check your webhook for the challenge URL. Visit it to confirm and get an invoice."
}
```

A challenge POST is sent to your `webhook_url`:
```json
{"event": "webhook_challenge", "challenge_url": "https://noscha.io/api/order/{order_id}/confirm/{challenge}", "order_id": "ord_18f3a..."}
```

After payment is confirmed, a completion notice is POSTed to your `webhook_url`:
```json
{"event": "payment_completed", "order_id": "...", "username": "...", "management_token": "...", "my_page_url": "https://noscha.io/my/mgmt_xxx", "expires_at": "...", "plan": "...", "amount_sats": ..., "is_extend": false, "services": {"email": true, "subdomain": true, "nip05": true}}
```

### Step 2b: Confirm webhook & get invoice

Visit the `challenge_url` from the webhook (GET request):
```
GET /api/order/{order_id}/confirm/{challenge}
```

**Response:**
```json
{
  "order_id": "ord_18f3a...",
  "amount_sats": 6500,
  "bolt11": "lnbc65000n1p...",
  "expires_at": "2026-02-11T12:15:00Z",
  "status": "pending"
}
```

You can include any combination of services (`email`, `subdomain`, `nip05`). `webhook_url` is **required** for all orders - email notifications are delivered via webhook.

### Step 3: Pay the invoice & poll for status

Pay the `bolt11` Lightning invoice, then poll:

```
GET /api/order/{order_id}/status
```

**Response (after payment):**
```json
{
  "order_id": "ord_18f3a...",
  "status": "provisioned",
  "management_token": "mgmt_18f3b..."
}
```

Alternatively, wait for the `payment_completed` webhook (no polling required). Save the `management_token` - it's needed for extensions and management. The `my_page_url` in the webhook is your management page.

## Endpoints Reference

### GET /api/check/{username}
Check if a username is available for registration.
- **username**: 1-20 chars, alphanumeric + hyphens, no leading/trailing hyphens
- Returns `{"available": bool, "username": string, "error"?: string}`

### POST /api/order
Create a new rental order. Returns a Lightning invoice.
- **Body**: `{"username": string, "plan": string, "services"?: {...}}`
- **plan**: `"1d"` | `"7d"` | `"30d"` | `"90d"` | `"365d"`
- **services.email**: `{}`
- **services.subdomain**: `{"type": "A"|"AAAA"|"CNAME", "target": string, "proxied"?: bool}`
- **services.nip05**: `{"pubkey": "hex_pubkey"}`
- Returns `{"order_id", "amount_sats", "bolt11", "expires_at", "management_token"?}`
- Invoice expires in 15 minutes

### GET /api/order/{order_id}/status
Poll order status after payment.
- Returns `{"order_id", "status": "pending"|"paid"|"provisioned"|"expired", "management_token"?}`
- `management_token` is returned only when `status` is `"provisioned"`

### POST /api/extend
Extend an existing rental with a new plan period.
- **management_token**: Your rental's management token (from payment_completed webhook)
- **plan**: `"1d"` | `"7d"` | `"30d"` | `"90d"` | `"365d"`
- **services** (optional): Services to include in extension. If omitted, uses current rental's services.
- **service_keys** (optional): Array of service keys to extend only those specific services. Values: `["email"]`, `["subdomain"]`, `["nip05"]`, or combinations like `["email", "subdomain"]`. If omitted, extends all active services.
- **Body (extend all services):**
```json
{
  "management_token": "mgmt_xxx",
  "plan": "30d"
}
```
- **Body (extend specific services):**
```json
{
  "management_token": "mgmt_xxx",
  "plan": "30d",
  "service_keys": ["email", "subdomain"]
}
```
- **Response (success):**
```json
{
  "order_id": "ord_25g7k...",
  "amount_sats": 6500,
  "bolt11": "lnbc65000n1p...",
  "expires_at": "2026-03-13T12:15:00Z"
}
```
- **Errors:**
  - `404`: Rental not found (invalid or expired management_token)
  - `400`: Invalid request body

### POST /api/add-service
Add new services to an existing active rental. New services get the specified plan duration.
- **management_token**: Your rental's management token
- **plan** (required): Duration for the new services: `"1d"` | `"7d"` | `"30d"` | `"90d"` | `"365d"`
- **services** (required): Services to add. Cannot re-add services already active on this rental.
- **Body:**
```json
{
  "management_token": "mgmt_xxx",
  "plan": "30d",
  "services": {
    "email": {}
  }
}
```
- **Response (success):**
```json
{
  "order_id": "ord_25g7l...",
  "amount_sats": 2000,
  "bolt11": "lnbc20000n1p...",
  "expires_at": "2026-03-13T12:40:00Z"
}
```
- **Errors:**
  - `404`: Rental not found
  - `409`: Service already active on this rental
  - `400`: No services to add, invalid request body, or missing plan parameter

### PUT /api/my/{token}/nip05
Update the NIP-05 pubkey for an active rental (requires NIP-05 service to be enabled).
- **token**: Your management token (from payment_completed webhook)
- **Body:**
```json
{
  "pubkey": "deadbeef...64char hex or npub1..."
}
```
- **Response (success):**
```json
{
  "success": true,
  "pubkey_hex": "deadbeef...64char hex"
}
```
- **Errors:**
  - `404`: Rental not found
  - `400`: NIP-05 service not enabled for this rental, or invalid pubkey format

### PUT /api/my/{token}/subdomain
Update the subdomain CNAME target (requires subdomain service to be enabled).
- **token**: Your management token (from payment_completed webhook)
- **Body:**
```json
{
  "target": "newsite.example.com"
}
```
- **Response (success):**
```json
{
  "success": true,
  "target": "newsite.example.com"
}
```
- **Errors:**
  - `404`: Rental not found
  - `400`: Subdomain service not enabled for this rental
  - `500`: Failed to update Cloudflare DNS record

### GET /api/pricing
Get current pricing for all plans and services.
- Returns pricing matrix: `{"1d": {"subdomain": 500, "email": 1500, "nip05": 200, "bundle": 1800}, ...}`

### GET /api/info
Service metadata.

### GET /health
Health check. Returns `{"status": "ok", "version": "..."}`.

### GET /.well-known/nostr.json?name={username}
NIP-05 verification endpoint (Nostr protocol).

### GET /api/mail/{username}?token=mgmt_xxx
List all emails in the inbox for the given username.
- **username**: Your registered username
- **token**: Your management token (query parameter)
- Returns a list of emails with metadata (from, to, subject, date, etc.)

### GET /api/mail/{username}/{mail_id}?token=mgmt_xxx
Retrieve a specific email by ID.
- **username**: Your registered username
- **mail_id**: The email ID (e.g. `m_xxxx`)
- **token**: Your management token (query parameter)
- Returns the full email data including from, to, subject, body_text, body_html, date, etc.
- Returns 404 if email not found

### POST /api/mail/{username}/send
Send an email via Resend API from your noscha.io email address.
- **username**: Your registered username
- **Body**: `{"to": "recipient@example.com", "subject": "Subject", "text": "Email content", "management_token": "mgmt_xxx"}`
- Rate limited to 5 emails per 24 hours per account
- From address will be `{username}@noscha.io`
- Returns `{"success": true, "message_id": "resend_message_id"}` on success

### PUT /api/settings/{management_token}
Update rental settings, currently supports setting webhook URL for email notifications.
- **management_token**: Your rental's management token for authentication
- **Body**: `{"webhook_url": "https://your-server.com/webhook"}` (or null to disable)
- When webhook_url is set, incoming emails will trigger a POST to this URL
- Webhook payload: `{"event": "email_received", "from": "sender@example.com", "to": "you@noscha.io", "subject": "...", "view_url": "https://noscha.io/api/mail/{username}/{mail_id}", "received_at": "2026-02-11T..."}`

## Pricing (sats, Lightning Network)

| Plan | Subdomain | Email | NIP-05 | Bundle (all 3) |
|------|-----------|-------|--------|------------------|
| 1 Hour | 300 | 800 | 100 | 1,000 |
| 1 Day | 500 | 1,500 | 110 | 1,600 |
| 7 Days | 1,000 | 2,500 | 200 | 3,300 |
| 30 Days | 2,000 | 5,000 | 1,000 | 6,500 |
| 90 Days | 5,000 | 12,000 | 2,000 | 16,000 |
| 365 Days | 10,000 | 35,000 | 4,000 | 40,000 |

Bundle discount applies automatically when all 3 services are selected. Prices may change - always check `/api/pricing` for current rates.

## Ecosystem: nostaro (Nostr CLI)

[nostaro](https://github.com/kojira/nostaro) is a Rust-based Nostr CLI that pairs perfectly with noscha.io.

**Install:** `cargo install nostaro`

**Set your noscha.io NIP-05 identity:**
```
nostaro profile set --nip05 yourname@noscha.io
```

**Usage examples:**
- `nostaro post "hello nostr"` - publish a note
- `nostaro zap <npub> 100` - send 100 sats zap
- `nostaro timeline` - view your timeline
- `nostaro profile get` - check your profile

Get a NIP-05 identity from noscha.io and use it instantly with nostaro for a complete Nostr experience.

## Typical Agent Workflow

### Initial Setup
1. **Decide** what services you need (email notifications? subdomain? NIP-05?)
2. **GET /api/check/{username}** - verify availability
3. **GET /api/pricing** - confirm current pricing
4. **POST /api/order** - create order with desired services
5. **Pay** the `bolt11` invoice via any Lightning wallet/API
6. **GET /api/order/{order_id}/status** - poll until `"provisioned"` (poll every 3s, max ~5 min)
7. **Store** the `management_token` for future management

### Managing Your Rental
- **Extend rental time:** `POST /api/extend` with a new plan period (doesn't add services, just extends)
- **Add services:** `POST /api/add-service` to add email/subdomain/NIP-05 without changing expiry
- **Update NIP-05 pubkey:** `PUT /api/my/{token}/nip05` to change your Nostr identity pubkey
- **Update subdomain target:** `PUT /api/my/{token}/subdomain` to redirect to a new target
- **View your account:** Visit the `my_page_url` from the payment_completed webhook or construct it as `https://noscha.io/my/{management_token}`

## Limitations

- Username: 1-20 characters, alphanumeric and hyphens only
- Invoice expires in 15 minutes after creation
- Lightning Network payments only (Bitcoin)
- No refunds (disposable service by design)
- DNS propagation may take up to 5 minutes after provisioning
- - All services under one username share the same expiry date

## Terms of Service (Summary)

- Service is provided as-is for legitimate use
- Abuse (spam, phishing, illegal content) will result in immediate termination
- Received emails are automatically deleted after 1 hour
- No personal data is collected beyond what's needed for the service
- Payments are final and non-refundable
- Service availability is best-effort
