openapi: 3.0.3
info:
  title: Netnaunse API
  version: 0.2.0
  description: |
    Official Netnaunse public API (SMS-first). Authenticate with a JWT or API key,
    send SMS, inspect delivery status, manage a prepaid wallet, and receive signed webhooks.

    Customer responses never include provider credentials, provider costs, or raw upstream errors.
  contact:
    name: Netnaunse Support
    email: support@netnaunse.com
    url: https://docs.netnaunse.com
servers:
  - url: https://api.netnaunse.com
    description: Production
  - url: http://localhost:3000
    description: Local gateway
tags:
  - name: Auth
  - name: SMS
  - name: Wallet
  - name: Webhooks
  - name: Product
paths:
  /health:
    get:
      summary: Gateway health
      responses:
        "200":
          description: OK
  /v1/auth/register:
    post:
      tags: [Auth]
      summary: Register user, organisation, and wallet
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [email, password]
              properties:
                email: { type: string, format: email }
                password: { type: string, minLength: 8 }
                firstName: { type: string }
                lastName: { type: string }
                organizationName: { type: string }
      responses:
        "201":
          description: Created
  /v1/auth/login:
    post:
      tags: [Auth]
      summary: Login and receive JWT
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [email, password]
              properties:
                email: { type: string }
                password: { type: string }
      responses:
        "200":
          description: JWT + user
  /v1/auth/me:
    get:
      tags: [Auth]
      summary: Current user and organisation context
      security: [{ bearerAuth: [] }]
      responses:
        "200":
          description: User profile
  /v1/auth/api-keys:
    get:
      tags: [Auth]
      summary: List API keys
      security: [{ bearerAuth: [] }]
      responses:
        "200":
          description: Key metadata (secrets not included)
    post:
      tags: [Auth]
      summary: Create API key
      description: Returns the full `nn_…` secret once.
      security: [{ bearerAuth: [] }]
      responses:
        "201":
          description: Created (includes secret once)
  /v1/auth/api-keys/{id}/disable:
    post:
      tags: [Auth]
      summary: Disable an API key
      security: [{ bearerAuth: [] }]
      parameters:
        - in: path
          name: id
          required: true
          schema: { type: string }
      responses:
        "200":
          description: Disabled
  /v1/sms/send:
    post:
      tags: [SMS]
      summary: Queue an SMS
      security: [{ bearerAuth: [] }]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [to, message]
              properties:
                to:
                  type: string
                  description: Destination MSISDN (e.g. 2557XXXXXXXX)
                  example: "255712345678"
                message:
                  type: string
                  maxLength: 1600
                  example: Your OTP is 847201. Valid for 5 minutes.
                senderId:
                  type: string
                  maxLength: 11
                  pattern: "^[A-Za-z0-9]+$"
                  example: MyBrand
                language:
                  type: string
                  enum: [English, Unicode]
                  default: English
                scheduledAt:
                  type: string
                  format: date-time
                messageType:
                  type: string
                  enum: [otp, transactional, marketing]
            example:
              to: "255712345678"
              message: Your OTP is 847201. Valid for 5 minutes.
              senderId: MyBrand
              language: English
      responses:
        "202":
          description: Queued
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      id: { type: string }
                      status: { type: string, example: queued }
                      to: { type: string }
                      queuedAt: { type: string, format: date-time }
                      pricing:
                        type: object
                        properties:
                          segments: { type: integer }
                          unitPrice: { type: number }
                          total: { type: number }
                          currency: { type: string }
        "400":
          description: Validation error or MISSING_SENDER_ID / WALLET_MISSING
        "402":
          description: INSUFFICIENT_BALANCE
  /v1/sms:
    get:
      tags: [SMS]
      summary: List messages
      security: [{ bearerAuth: [] }]
      parameters:
        - in: query
          name: page
          schema: { type: integer, default: 1 }
        - in: query
          name: limit
          schema: { type: integer, default: 20 }
      responses:
        "200":
          description: Paginated message list
  /v1/sms/{id}:
    get:
      tags: [SMS]
      summary: Get message by id
      security: [{ bearerAuth: [] }]
      parameters:
        - in: path
          name: id
          required: true
          schema: { type: string }
      responses:
        "200":
          description: Message
        "404":
          description: Not found
  /v1/dashboard/stats:
    get:
      tags: [Product]
      summary: Dashboard stats
      security: [{ bearerAuth: [] }]
      responses:
        "200":
          description: Stats
  /v1/wallet:
    get:
      tags: [Wallet]
      summary: Wallet balance
      security: [{ bearerAuth: [] }]
      responses:
        "200":
          description: Wallet
  /v1/wallet/transactions:
    get:
      tags: [Wallet]
      summary: Wallet ledger transactions
      security: [{ bearerAuth: [] }]
      responses:
        "200":
          description: Transactions
  /v1/wallet/top-up:
    post:
      tags: [Wallet]
      summary: Credit wallet (controlled/dev)
      description: Not for end-user production top-ups. Prefer the dashboard Buy SMS flow.
      security: [{ bearerAuth: [] }]
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                amount: { type: number }
      responses:
        "200":
          description: Updated wallet
  /v1/webhooks:
    get:
      tags: [Webhooks]
      summary: List webhook endpoints
      security: [{ bearerAuth: [] }]
      responses:
        "200":
          description: Endpoints
    post:
      tags: [Webhooks]
      summary: Register webhook endpoint
      description: Returns signing secret once. Events default to message.sent and message.failed.
      security: [{ bearerAuth: [] }]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [url]
              properties:
                url: { type: string, format: uri }
                events:
                  type: array
                  items: { type: string }
                  default: [message.sent, message.failed]
      responses:
        "201":
          description: Created (includes secret once)
  /v1/webhooks/{id}:
    delete:
      tags: [Webhooks]
      summary: Delete webhook endpoint
      security: [{ bearerAuth: [] }]
      parameters:
        - in: path
          name: id
          required: true
          schema: { type: string }
      responses:
        "200":
          description: Deleted
  /v1/kyc:
    get:
      tags: [Product]
      summary: Get KYC submission
      security: [{ bearerAuth: [] }]
      responses:
        "200":
          description: KYC or null
    post:
      tags: [Product]
      summary: Submit KYC
      security: [{ bearerAuth: [] }]
      responses:
        "201":
          description: Submitted
  /v1/sender-ids:
    get:
      tags: [Product]
      summary: List sender ID requests
      security: [{ bearerAuth: [] }]
      responses:
        "200":
          description: List
    post:
      tags: [Product]
      summary: Request sender ID
      security: [{ bearerAuth: [] }]
      responses:
        "201":
          description: Created
  /v1/contacts:
    get:
      tags: [Product]
      summary: List contacts
      security: [{ bearerAuth: [] }]
      responses:
        "200":
          description: Contacts
    post:
      tags: [Product]
      summary: Create contact
      security: [{ bearerAuth: [] }]
      responses:
        "201":
          description: Created
  /v1/templates:
    get:
      tags: [Product]
      summary: List templates
      security: [{ bearerAuth: [] }]
      responses:
        "200":
          description: Templates
    post:
      tags: [Product]
      summary: Create template
      security: [{ bearerAuth: [] }]
      responses:
        "201":
          description: Created
  /v1/campaigns:
    get:
      tags: [Product]
      summary: List campaigns
      security: [{ bearerAuth: [] }]
      responses:
        "200":
          description: Campaigns
    post:
      tags: [Product]
      summary: Create campaign (draft/scheduled)
      security: [{ bearerAuth: [] }]
      responses:
        "201":
          description: Created
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT or API key
      description: JWT from /v1/auth/login or API key beginning with nn_
