Protocol Specification
This document provides the technical specification for the Network-Agnostic Secure Payment Instruction Protocol (NASPIP) as implemented by Fluxis and 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:
Code
| 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)
Code
URL payload (checkout / deferred instructions)
Code
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 or the REST API — do not implement raw Ed25519+SHA-256 over JSON.
Signing (create)
- Build
InstructionPayloadorUrlPayload - Encode payload as protobuf
- Sign with PASETO v4 using the issuer's Ed25519 private key
- Prefix with
naspip;{kis};{kid};
Default token TTL: 1 hour for payment instructions; 10 years (87600h) for URL-only payloads.
Verification (read)
- Split token on
;and validate prefixnaspip - Resolve public key by
kis+kid - Verify PASETO v4 signature and expiration claims
- Return
PasetoCompleteResultwith parsedpayload.data
Fluxis POST /v1/naspip/read response shape
Code
::::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 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):
Code
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
Code
Security Considerations
Best Practices
- Key Management: Fluxis manages signing keys; integrators verify via public key lookup (
kis+kid) - Token Expiration: Payment instruction tokens expire after 1 hour by default
- Amount Validation: Validate amounts on both sender and receiver sides
- Asset Verification: Confirm
unique_asset_idmatches the expected network and token - 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+kidensures authenticity
Implementation Guidelines
Required fields (instruction payload)
payment.address— destination addresspayment.unique_asset_id— target asset (UAI)payment.amount— payment amountpayment.is_open— whether the amount is open-ended
Optional fields
payment.id— payment request identifierpayment.expires_at— Unix timestamp expirationorder— merchant and order metadata
Validation Rules
- Token must parse as
naspip;{kis};{kid};v4.public.{paseto} - PASETO signature and expiration must be valid
- Public key for
kis+kidmust not be expired unique_asset_idmust 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:
- Fluxis performs an HTTP GET to that URL
- On success, replaces
payload.datawith the fetched checkout/payment instructions - On failure, returns
MD0004orPR0006as 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 for curl examples.