Files
Nip-05-api/internal/http/docs/openapi.yaml
2026-04-29 02:35:00 +00:00

298 lines
9.1 KiB
YAML

openapi: 3.1.0
info:
title: NIP-05 API
description: Single-domain NIP-05 identity service with Lightning-paid registration.
version: 1.0.0
servers:
- url: /
tags:
- name: Public
description: Anonymous, infrastructure-level endpoints. Cacheable, no auth.
- name: User
description: Anonymous flows for end users — lookup, availability, payment.
- name: Admin
description: Privileged operations. Require an `X-API-Key` header.
components:
securitySchemes:
AdminAPIKey:
type: apiKey
in: header
name: X-API-Key
schemas:
Error:
type: object
properties:
error: { type: string }
detail: { type: string }
Pricing:
type: object
properties:
yearly_sats: { type: integer }
lifetime_sats: { type: integer }
lightning_enabled: { type: boolean }
Invoice:
type: object
properties:
payment_hash: { type: string }
payment_request: { type: string }
amount_sats: { type: integer }
expires_at: { type: string, format: date-time }
username: { type: string }
is_renewal: { type: boolean }
InvoiceStatus:
type: object
properties:
payment_hash: { type: string }
status: { type: string, enum: [pending, paid, expired] }
username: { type: string }
User:
type: object
properties:
pubkey: { type: string }
npub: { type: string }
username: { type: string }
subscription_type: { type: string, enum: [yearly, lifetime] }
is_active: { type: boolean }
expires_at: { type: string, format: date-time, nullable: true }
deactivated_at: { type: string, format: date-time, nullable: true }
UserLookup:
type: object
properties:
pubkey: { type: string }
npub: { type: string }
is_whitelisted: { type: boolean }
username: { type: string }
expires_at: { type: string, format: date-time, nullable: true }
in_grace: { type: boolean }
reserved_username: { type: string }
expired_at: { type: string, format: date-time }
paths:
/.well-known/nostr.json:
get:
tags: [Public]
summary: NIP-05 lookup
parameters:
- in: query
name: name
schema: { type: string }
responses:
'200':
description: NIP-05 names map
content:
application/json:
schema:
type: object
properties:
names:
type: object
additionalProperties: { type: string }
relays:
type: object
additionalProperties:
type: array
items: { type: string }
/healthz:
get:
tags: [Public]
summary: Health check
responses:
'200': { description: OK }
'503': { description: Down }
/v1/pricing:
get:
tags: [Public]
summary: Pricing info
responses:
'200':
description: Pricing
content:
application/json:
schema: { $ref: '#/components/schemas/Pricing' }
/v1/invoices:
post:
tags: [User]
summary: Create payment invoice
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [pubkey]
properties:
pubkey: { type: string, description: "Hex pubkey or npub" }
username:
type: string
description: "Optional. Auto-generated from the pubkey if omitted."
subscription_type:
type: string
enum: [yearly, lifetime]
description: "Optional. Defaults to lifetime."
years:
type: integer
minimum: 1
description: "Optional. Defaults to 1 when subscription_type is yearly; ignored for lifetime."
responses:
'200':
description: Invoice
content:
application/json:
schema: { $ref: '#/components/schemas/Invoice' }
'400': { description: Validation error, content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } }
'403': { description: Forbidden — user already has lifetime access, content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } }
'409': { description: Conflict — username unavailable or pending invoice already exists, content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } }
'503': { description: Lightning unavailable, content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } }
/v1/invoices/{payment_hash}:
get:
tags: [User]
summary: Invoice status
parameters:
- in: path
name: payment_hash
required: true
schema: { type: string }
responses:
'200':
description: Status
content:
application/json:
schema: { $ref: '#/components/schemas/InvoiceStatus' }
'404': { description: Not found }
/v1/users/{pubkey}:
get:
tags: [User]
summary: Lookup user by pubkey (npub or hex)
parameters:
- in: path
name: pubkey
required: true
schema: { type: string }
responses:
'200':
description: User lookup
content:
application/json:
schema: { $ref: '#/components/schemas/UserLookup' }
'404': { description: Never registered }
/v1/usernames/{name}/available:
get:
tags: [User]
summary: Username availability
parameters:
- in: path
name: name
required: true
schema: { type: string }
responses:
'200':
description: Availability
content:
application/json:
schema:
type: object
properties:
username: { type: string }
available: { type: boolean }
/v1/admin/users:
post:
tags: [Admin]
summary: Add user (admin)
security: [{ AdminAPIKey: [] }]
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [pubkey, username, subscription_type]
properties:
pubkey: { type: string }
username: { type: string }
subscription_type: { type: string, enum: [yearly, lifetime] }
years: { type: integer }
responses:
'201':
description: Created
content: { application/json: { schema: { $ref: '#/components/schemas/User' } } }
'401': { description: Unauthorized }
get:
tags: [Admin]
summary: List users (admin)
security: [{ AdminAPIKey: [] }]
parameters:
- in: query
name: active
schema: { type: boolean }
- in: query
name: q
schema: { type: string }
responses:
'200':
description: User list
content:
application/json:
schema:
type: array
items: { $ref: '#/components/schemas/User' }
'401': { description: Unauthorized }
/v1/admin/users/{pubkey}:
put:
tags: [Admin]
summary: Update username (admin)
security: [{ AdminAPIKey: [] }]
parameters:
- in: path
name: pubkey
required: true
schema: { type: string }
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [username]
properties:
username: { type: string }
responses:
'200': { description: Updated }
'401': { description: Unauthorized }
'404': { description: Not found }
'409': { description: Conflict }
delete:
tags: [Admin]
summary: Delete user (admin)
security: [{ AdminAPIKey: [] }]
parameters:
- in: path
name: pubkey
required: true
schema: { type: string }
responses:
'200': { description: Deleted }
'401': { description: Unauthorized }
'404': { description: Not found }
/v1/admin/users/{pubkey}/extend:
post:
tags: [Admin]
summary: Extend subscription (admin)
security: [{ AdminAPIKey: [] }]
parameters:
- in: path
name: pubkey
required: true
schema: { type: string }
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
years: { type: integer }
subscription_type: { type: string, enum: [yearly, lifetime] }
responses:
'200': { description: Extended }
'401': { description: Unauthorized }
'404': { description: Not found }