# Protocol Specification

This document provides the technical specification for the Network-Agnostic Secure Payment Instruction Protocol (NASPIP) as implemented by Fluxis and [naspip-go](https://github.com/fluxisus/naspip-go).

## Overview

NASPIP defines a standardized format for payment instructions that can be securely transmitted and validated across any payment network. Tokens are **PASETO v4 public** (signed, not encrypted) — anyone with the issuer's public key can verify authenticity and payload integrity.

## Data Structure

### NASPIP Token Format

A NASPIP token is a semicolon-delimited string wrapping a PASETO v4 public token:

```
naspip;{key_issuer};{key_id};v4.public.{paseto_token}
```

| Component | Description | Example |
| --------- | ----------- | ------- |
| Prefix | Protocol identifier | `naspip` |
| Key issuer (`kis`) | Entity that issued the signing key | `fluxis.us` |
| Key ID (`kid`) | Identifier of the signing key | `fluxis.qr.dyn.1` |
| PASETO token | PASETO v4 public token containing the signed payload | `v4.public.IhYyMDI...` |

The inner PASETO payload uses standard claims (`iss`, `sub`, `exp`, `iat`, `kid`, `kis`, `kep`) plus a `data` field containing either payment instructions or a URL payload.

### Payload Schemas

NASPIP supports two payload types inside the PASETO token `data` field.

#### Instruction payload (direct payment)

```json
{
  "payment": {
    "id": "180ede28-2968-4ac7-8e81-ca446f201949",
    "address": "0x1234567890abcdef1234567890abcdef12345678",
    "unique_asset_id": "npolygon_t0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",
    "is_open": false,
    "amount": "49.99",
    "expires_at": 1759397652
  },
  "order": {
    "total": "49.99",
    "coin_code": "USD",
    "description": "Order description",
    "merchant": {
      "name": "Merchant #1",
      "description": "Merchant description"
    },
    "items": []
  }
}
```

#### URL payload (checkout / deferred instructions)

```json
{
  "url": "https://api.fluxis.us/v1/pos/{posID}/payment-request-checkout",
  "payment_options": ["npolygon_t0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359"],
  "order": {
    "total": "49.99",
    "coin_code": "USD",
    "merchant": { "name": "Merchant #1" }
  }
}
```

Static POS QR codes may omit `payment_options`; wallets call `POST /v1/naspip/read` and Fluxis resolves instructions by fetching the URL when `payment_options` is absent.

## Cryptographic Operations

NASPIP uses **PASETO v4 public tokens** with Ed25519 keys. Payloads are protobuf-encoded before signing. In Fluxis, use [naspip-go](https://github.com/fluxisus/naspip-go) or the REST API — do not implement raw Ed25519+SHA-256 over JSON.

### Signing (create)

1. Build `InstructionPayload` or `UrlPayload`
2. Encode payload as protobuf
3. Sign with PASETO v4 using the issuer's Ed25519 private key
4. Prefix with `naspip;{kis};{kid};`

Default token TTL: **1 hour** for payment instructions; **10 years** (`87600h`) for URL-only payloads.

### Verification (read)

1. Split token on `;` and validate prefix `naspip`
2. Resolve public key by `kis` + `kid`
3. Verify PASETO v4 signature and expiration claims
4. Return `PasetoCompleteResult` with parsed `payload.data`

### Fluxis `POST /v1/naspip/read` response shape

```json
{
  "status": "success",
  "data": {
    "version": "v4",
    "purpose": "public",
    "footer": null,
    "payload": {
      "iss": "fluxis.us",
      "sub": "naspip",
      "exp": "2026-12-31T23:59:59.000Z",
      "iat": "2026-01-01T00:00:00.000Z",
      "kid": "fluxis.qr.dyn.1",
      "kis": "fluxis.us",
      "data": { "payment": { "...": "..." } }
    }
  }
}
```

::::warning Swagger mismatch
OpenAPI currently documents `data` as flat `PasetoV4PayloadData` (`url`, `payment`, `order`). The runtime response is `PasetoCompleteResult` as shown above. See `NASPIP_ENHANCEMENTS.md` for the planned fix.
:::::

## Network Support

Payment instructions reference assets by **`unique_asset_id`** (UAI), not by network name or chain ID. Fluxis supports multiple networks — see [UAI](/docs/key-concepts/uai) for the full asset list.

Example UAIs:

| Network | Asset | Example UAI |
| ------- | ----- | ----------- |
| Polygon | USDC | `npolygon_t0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359` |
| Base | USDC | `nbase_t0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913` |
| Avalanche | USDC | `navalanche_t0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E` |
| Avalanche | ARGt | `navalanche_t0x2E4e93eCA2E16E4989b894e188B7F7fC0175703B` |
| Arbitrum | USDC | `narbitrum_t0xaf88d065e77c8cC2239327C5EDb3A432268e5831` |
| Arbitrum | USDT | `narbitrum_t0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9` |

## QR Code Format

NASPIP tokens are encoded in QR codes as the **raw token string** (not a `naspip://` URI):

```
naspip;fluxis.us;fluxis.qr.dyn.1;v4.public.IhYyMDI...
```

### QR Code Specifications

- **Error Correction**: Level M (15% recovery)
- **Size**: Minimum 256x256 pixels
- **Format**: Standard QR Code (ISO/IEC 18004)

## Versioning

NASPIP tokens use **PASETO v4** (`v4.public.*`). The semicolon-delimited wrapper prefix is `naspip`. Breaking changes to payload schemas are managed through naspip-go version releases.

## Error Handling

### Fluxis API error codes (NASPIP-related)

| Code | HTTP | Description |
| ---- | ---- | ----------- |
| `MD0006` | 406 | NASPIP token expired |
| `GE0003` | 404 | Public key expired |
| `MD0004` | 400 | Invalid data (e.g. invalid token or URL) |
| `PR0006` | 404 | No active payment request (cashier POS; returned when resolving URL payload) |

### Error response format

```json
{
  "status": "error",
  "error": {
    "code": "MD0006",
    "message": "NASPIP token expired"
  }
}
```

## Security Considerations

### Best Practices

1. **Key Management**: Fluxis manages signing keys; integrators verify via public key lookup (`kis` + `kid`)
2. **Token Expiration**: Payment instruction tokens expire after 1 hour by default
3. **Amount Validation**: Validate amounts on both sender and receiver sides
4. **Asset Verification**: Confirm `unique_asset_id` matches the expected network and token
5. **Signature Verification**: Always verify PASETO tokens before processing payments

### Threat Model

NASPIP protects against:

- **Data Tampering**: PASETO v4 signatures prevent modification
- **Replay Attacks**: Token expiration and payment request lifecycle prevent reuse
- **Impersonation**: Public key verification via `kis` + `kid` ensures authenticity

## Implementation Guidelines

### Required fields (instruction payload)

- `payment.address` — destination address
- `payment.unique_asset_id` — target asset (UAI)
- `payment.amount` — payment amount
- `payment.is_open` — whether the amount is open-ended

### Optional fields

- `payment.id` — payment request identifier
- `payment.expires_at` — Unix timestamp expiration
- `order` — merchant and order metadata

### Validation Rules

1. Token must parse as `naspip;{kis};{kid};v4.public.{paseto}`
2. PASETO signature and expiration must be valid
3. Public key for `kis` + `kid` must not be expired
4. `unique_asset_id` must be a supported UAI

## URL Payload Resolution (Fluxis)

When `POST /v1/naspip/read` receives a token whose `payload.data` contains a non-empty `url` **and** no `payment_options`:

1. Fluxis performs an HTTP GET to that URL
2. On success, replaces `payload.data` with the fetched checkout/payment instructions
3. On failure, returns `MD0004` or `PR0006` as appropriate

If `payment_options` is present, the token is returned as-is and the wallet selects an asset before a follow-up checkout call.

## Fluxis API Endpoints

| Endpoint | Method | Auth | Description |
| -------- | ------ | ---- | ----------- |
| `/v1/naspip/read` | POST | Bearer + `x-fluxis-api-key` | Verify token and return `PasetoCompleteResult` |
| `/v1/naspip/create` | POST | Bearer + `x-fluxis-api-key` | Create token from instruction or URL payload |

See the [Implementation Guide](/docs/key-concepts/naspip/implementation-guide) for curl examples.

## References

- [NASPIP Protocol (GitHub)](https://github.com/fluxisus/naspip)
- [naspip-go library](https://github.com/fluxisus/naspip-go)
- [PASETO specification](https://paseto.io/)
- [ISO/IEC 18004 - QR Code](https://www.iso.org/standard/62021.html)
