Esta guía cubre la integración de NASPIP vía la API REST de Fluxis (recomendado) o la biblioteca naspip-go para implementaciones personalizadas.
Requisitos previos
Credenciales de API Fluxis (Bearer token + API key) para integración REST
Para uso de biblioteca: Go 1.21+ y github.com/fluxisus/naspip-go/v3
Comprensión del formato de token NASPIP (naspip;{kis};{kid};v4.public....) — consulte Protocol Specification
API REST de Fluxis (Recomendado)
Leer un token NASPIP
curl -X POST https://api.fluxis.us/v1/naspip/read \
-H "Authorization: Bearer <token>" \
-H "x-fluxis-api-key: <api_key_id>" \
-H "Content-Type: application/json" \
-d '{ "token": "naspip;fluxis.us;fluxis.qr.dyn.1;v4.public...." }'
La respuesta data es un PasetoCompleteResult (version, purpose, footer, payload). Para payloads URL sin payment_options, Fluxis obtiene instrucciones desde payload.data.url y devuelve datos de pago resueltos.
Crear un token NASPIP
curl -X POST https://api.fluxis.us/v1/naspip/create \
-H "Authorization: Bearer <token>" \
-H "x-fluxis-api-key: <api_key_id>" \
-H "Content-Type: application/json" \
-d '{
"payment": {
"address": "0x1234...",
"unique_asset_id": "npolygon_t0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",
"amount": 49.99,
"is_open": false,
"expires_at": 1759397652
}
}'
También se admiten payloads URL: pase { "url": "https://...", "payment_options": ["..."] }.
::::note Advertencia Swagger
OpenAPI puede documentar una respuesta de lectura plana con forma de checkout; la forma en runtime es PasetoCompleteResult. Consulte NASPIP_ENHANCEMENTS.md.
:::::
Implementaciones por lenguaje
::::warning Ejemplos heredados abajo
Las secciones JavaScript, Python y Go abajo implementan un protocolo no estándar naspip:// + base64. No interoperarán con Fluxis o naspip-go. Prefiera las secciones REST API o naspip-go arriba hasta que estos ejemplos se reescriban.
:::::
Implementación JavaScript/TypeScript
1. Instalar dependencias
npm install crypto-js qrcode ed25519-supercop
2. Clase NASPIP principal
import * as crypto from "crypto" ;
import * as QRCode from "qrcode" ;
interface PaymentInstruction {
version : string ;
id : string ;
amount : {
value : string ;
currency : string ;
type : "open" | "closed" ;
};
network : {
name : string ;
chainId : string ;
};
recipient : {
address : string ;
type : string ;
};
metadata ?: {
description ?: string ;
reference ?: string ;
expiresAt ?: string ;
};
options ?: {
allowPartial ?: boolean ;
maxAmount ?: string ;
minAmount ?: string ;
};
}
class NASPIP {
private privateKey : string ;
private publicKey : string ;
constructor ( privateKey ?: string ) {
if (privateKey) {
this .privateKey = privateKey;
this .publicKey = this . derivePublicKey (privateKey);
} else {
const keyPair = this . generateKeyPair ();
this .privateKey = keyPair.privateKey;
this .publicKey = keyPair.publicKey;
}
}
private generateKeyPair () {
const keyPair = crypto. generateKeyPairSync ( "ed25519" );
return {
privateKey: keyPair.privateKey. export ({ type: "pkcs8" , format: "pem" }),
publicKey: keyPair.publicKey. export ({ type: "spki" , format: "pem" }),
};
}
private derivePublicKey ( privateKey : string ) {
// Implementation depends on your crypto library
// This is a simplified example
return crypto
. createPublicKey (privateKey)
. export ({ type: "spki" , format: "pem" });
}
async createPaymentInstruction ( params : {
amount : string ;
currency : string ;
network : string ;
recipient : string ;
description ?: string ;
expiresAt ?: string ;
}) : Promise < string > {
const instruction : PaymentInstruction = {
version: "1.0" ,
id: this . generateUniqueId (),
amount: {
value: params.amount,
currency: params.currency,
type: "closed" ,
},
network: {
name: params.network,
chainId: "mainnet" ,
},
recipient: {
address: params.recipient,
type: "address" ,
},
metadata: {
description: params.description,
expiresAt: params.expiresAt || this . getDefaultExpiration (),
},
};
return this . signAndEncode (instruction);
}
private generateUniqueId () : string {
return crypto. randomBytes ( 16 ). toString ( "hex" );
}
private getDefaultExpiration () : string {
const expiration = new Date ();
expiration. setHours (expiration. getHours () + 24 ); // 24 hours from now
return expiration. toISOString ();
}
private async signAndEncode (
instruction : PaymentInstruction ,
) : Promise < string > {
// Canonical JSON serialization
const serialized = JSON . stringify (
instruction,
Object. keys (instruction). sort (),
);
// Create hash
const hash = crypto. createHash ( "sha256" ). update (serialized). digest ();
// Sign the hash
const signature = crypto. sign ( "ed25519" , hash, this .privateKey);
// Encode as NASPIP token
const tokenData = {
version: "1.0" ,
data: Buffer. from (serialized). toString ( "base64" ),
signature: signature. toString ( "base64" ),
};
return `naspip://${ Buffer . from ( JSON . stringify ( tokenData )). toString (
"base64" ,
) }` ;
}
async generateQRCode ( token : string ) : Promise < string > {
return await QRCode. toDataURL (token, {
errorCorrectionLevel: "M" ,
type: "image/png" ,
width: 256 ,
});
}
async verifyToken (
token : string ,
publicKey : string ,
) : Promise < PaymentInstruction > {
// Decode token
const tokenData = JSON . parse (
Buffer. from (token. replace ( "naspip://" , "" ), "base64" ). toString (),
);
// Decode payment instruction
const instruction : PaymentInstruction = JSON . parse (
Buffer. from (tokenData.data, "base64" ). toString (),
);
// Verify signature
const serialized = JSON . stringify (
instruction,
Object. keys (instruction). sort (),
);
const hash = crypto. createHash ( "sha256" ). update (serialized). digest ();
const signature = Buffer. from (tokenData.signature, "base64" );
const isValid = crypto. verify ( "ed25519" , hash, publicKey, signature);
if ( ! isValid) {
throw new Error ( "Invalid signature" );
}
return instruction;
}
}
3. Crear una instrucción de pago (TypeScript)
Fluxis firma tokens NASPIP con sus claves emisoras. No construya instrucciones de pago localmente a menos que opere su propio emisor NASPIP. En producción, cree una solicitud de pago y use el token de la respuesta.
import QRCode from "qrcode" ;
const API_BASE = "https://api.fluxis.us" ;
const POS_ID = process.env. FLUXIS_POS_ID ! ;
const BEARER = process.env. FLUXIS_ACCESS_TOKEN ! ;
const API_KEY_ID = process.env. FLUXIS_API_KEY_ID ! ;
type CreatePaymentRequestResponse = {
status : string ;
data : {
id : string ;
reference_id ?: string ;
status : string ;
token : string ; // NASPIP token: naspip;fluxis.us;fluxis.qr.dyn.1;v4.public....
expiration ?: number ;
};
};
async function createPaymentInstruction () : Promise < CreatePaymentRequestResponse [ "data" ]> {
const res = await fetch ( `${ API_BASE }/v1/pos/${ POS_ID }/payment-request` , {
method: "POST" ,
headers: {
Authorization: `Bearer ${ BEARER }` ,
"x-fluxis-api-key" : API_KEY_ID ,
"Content-Type" : "application/json" ,
},
body: JSON . stringify ({
amount: "49.99" ,
unique_asset_id: "npolygon_t0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359" ,
reference_id: "order-12345" ,
order: {
total: "49.99" ,
coin_code: "USD" ,
description: "Payment for services" ,
merchant: { name: "My Store" },
},
}),
});
if ( ! res.ok) {
throw new Error ( `Payment request failed: ${ res . status } ${ await res . text () }` );
}
const body = ( await res. json ()) as CreatePaymentRequestResponse ;
return body.data;
}
async function example () {
const { id , token , expiration } = await createPaymentInstruction ();
// Present the raw NASPIP string as a QR code (not a naspip:// URI)
const qrCode = await QRCode. toDataURL (token, { width: 256 , errorCorrectionLevel: "M" });
console. log ( "Payment request ID:" , id);
console. log ( "Expires at (unix):" , expiration);
console. log ( "NASPIP token:" , token);
console. log ( "QR data URL:" , qrCode);
// Optional: decode and verify via Fluxis
const readRes = await fetch ( `${ API_BASE }/v1/naspip/read` , {
method: "POST" ,
headers: {
Authorization: `Bearer ${ BEARER }` ,
"x-fluxis-api-key" : API_KEY_ID ,
"Content-Type" : "application/json" ,
},
body: JSON . stringify ({ token }),
});
const decoded = await readRes. json ();
console. log ( "Decoded payment:" , decoded.data.payload.data.payment);
}
El payload firmado dentro del token coincide con el esquema de payload de instrucción : vault address, unique_asset_id, amount, is_open, expires_at, y metadatos order opcionales. Fluxis asigna la dirección vault cuando se crea la solicitud de pago.
Para acuñación de tokens de bajo nivel cuando ya controla dirección y expiración (solo herramientas avanzadas/internas), use POST /v1/naspip/create con un objeto payment — consulte el ejemplo curl en la sección API REST de Fluxis arriba.
Implementación Python
1. Instalar dependencias
pip install cryptography qrcode pillow
2. Implementación principal
import json
import base64
import hashlib
from datetime import datetime, timedelta
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import ed25519
import qrcode
from typing import Dict, Any, Optional
class NASPIP :
def __init__ (self, private_key: Optional[ bytes ] = None ):
if private_key:
self .private_key = ed25519.Ed25519PrivateKey.from_private_bytes(private_key)
else :
self .private_key = ed25519.Ed25519PrivateKey.generate()
self .public_key = self .private_key.public_key()
def create_payment_instruction (self,
amount: str ,
currency: str ,
network: str ,
recipient: str ,
description: Optional[ str ] = None ,
expires_at: Optional[ str ] = None ) -> str :
instruction = {
"version" : "1.0" ,
"id" : self ._generate_unique_id(),
"amount" : {
"value" : amount,
"currency" : currency,
"type" : "closed"
},
"network" : {
"name" : network,
"chainId" : "mainnet"
},
"recipient" : {
"address" : recipient,
"type" : "address"
},
"metadata" : {
"description" : description,
"expiresAt" : expires_at or self ._get_default_expiration()
}
}
return self ._sign_and_encode(instruction)
def _generate_unique_id (self) -> str :
import secrets
return secrets.token_hex( 16 )
def _get_default_expiration (self) -> str :
expiration = datetime.now() + timedelta( hours = 24 )
return expiration.isoformat()
def _sign_and_encode (self, instruction: Dict[ str , Any]) -> str :
# Canonical JSON serialization
serialized = json.dumps(instruction, sort_keys = True , separators = ( ',' , ':' ))
# Create hash
hash_obj = hashlib.sha256(serialized.encode( 'utf-8' ))
hash_bytes = hash_obj.digest()
# Sign the hash
signature = self .private_key.sign(hash_bytes)
# Encode as NASPIP token
token_data = {
"version" : "1.0" ,
"data" : base64.b64encode(serialized.encode( 'utf-8' )).decode( 'utf-8' ),
"signature" : base64.b64encode(signature).decode( 'utf-8' )
}
token_json = json.dumps(token_data, separators = ( ',' , ':' ))
return f "naspip:// { base64.b64encode(token_json.encode( 'utf-8' )).decode( 'utf-8' ) } "
def generate_qr_code (self, token: str ) -> bytes :
qr = qrcode.QRCode(
version = 1 ,
error_correction = qrcode.constants. ERROR_CORRECT_M ,
box_size = 10 ,
border = 4 ,
)
qr.add_data(token)
qr.make( fit = True )
img = qr.make_image( fill_color = "black" , back_color = "white" )
# Convert to bytes
import io
img_bytes = io.BytesIO()
img.save(img_bytes, format = 'PNG' )
return img_bytes.getvalue()
def verify_token (self, token: str , public_key_bytes: bytes ) -> Dict[ str , Any]:
# Decode token
token_data = json.loads(
base64.b64decode(token.replace( 'naspip://' , '' )).decode( 'utf-8' )
)
# Decode payment instruction
instruction = json.loads(
base64.b64decode(token_data[ 'data' ]).decode( 'utf-8' )
)
# Verify signature
serialized = json.dumps(instruction, sort_keys = True , separators = ( ',' , ':' ))
hash_obj = hashlib.sha256(serialized.encode( 'utf-8' ))
hash_bytes = hash_obj.digest()
signature = base64.b64decode(token_data[ 'signature' ])
public_key = ed25519.Ed25519PublicKey.from_public_bytes(public_key_bytes)
try :
public_key.verify(signature, hash_bytes)
return instruction
except Exception :
raise ValueError ( "Invalid signature" )
# Usage example
def example ():
naspip = NASPIP()
# Create payment instruction
token = naspip.create_payment_instruction(
amount = "100.00" ,
currency = "USD" ,
network = "polygon" ,
recipient = "0x1234567890abcdef1234567890abcdef12345678" ,
description = "Payment for services"
)
# Generate QR code
qr_code_bytes = naspip.generate_qr_code(token)
# Save QR code to file
with open ( 'payment_qr.png' , 'wb' ) as f:
f.write(qr_code_bytes)
print ( f "Generated token: { token } " )
print ( "QR code saved as payment_qr.png" )
Implementación Go
1. Dependencias
go mod init naspip - example
go get github.com / fluxisus / naspip -go/ v3
go get github.com / skip2 /go- qrcode
Use protocol.PaymentInstructionsBuilder con paseto.PasetoV4Handler{} para operaciones create/read. Consulte ejemplos naspip-go .
2. Implementación principal
package main
import (
" crypto/ed25519 "
" crypto/rand "
" crypto/sha256 "
" encoding/base64 "
" encoding/json "
" fmt "
" time "
" github.com/skip2/go-qrcode "
)
type PaymentInstruction struct {
Version string `json:"version"`
ID string `json:"id"`
Amount struct {
Value string `json:"value"`
Currency string `json:"currency"`
Type string `json:"type"`
} `json:"amount"`
Network struct {
Name string `json:"name"`
ChainID string `json:"chainId"`
} `json:"network"`
Recipient struct {
Address string `json:"address"`
Type string `json:"type"`
} `json:"recipient"`
Metadata struct {
Description string `json:"description,omitempty"`
ExpiresAt string `json:"expiresAt,omitempty"`
} `json:"metadata,omitempty"`
}
type TokenData struct {
Version string `json:"version"`
Data string `json:"data"`
Signature string `json:"signature"`
}
type NASPIP struct {
privateKey ed25519 . PrivateKey
publicKey ed25519 . PublicKey
}
func NewNASPIP () ( * NASPIP , error ) {
publicKey, privateKey, err := ed25519. GenerateKey (rand.Reader)
if err != nil {
return nil , err
}
return & NASPIP {
privateKey: privateKey,
publicKey: publicKey,
}, nil
}
func ( n * NASPIP ) CreatePaymentInstruction ( amount , currency , network , recipient , description string ) ( string , error ) {
instruction := PaymentInstruction {
Version: "1.0" ,
ID: generateUniqueID (),
}
instruction.Amount.Value = amount
instruction.Amount.Currency = currency
instruction.Amount.Type = "closed"
instruction.Network.Name = network
instruction.Network.ChainID = "mainnet"
instruction.Recipient.Address = recipient
instruction.Recipient.Type = "address"
instruction.Metadata.Description = description
instruction.Metadata.ExpiresAt = getDefaultExpiration ()
return n. signAndEncode (instruction)
}
func ( n * NASPIP ) signAndEncode ( instruction PaymentInstruction ) ( string , error ) {
// Canonical JSON serialization
data, err := json. Marshal (instruction)
if err != nil {
return "" , err
}
// Create hash
hash := sha256. Sum256 (data)
// Sign the hash
signature := ed25519. Sign (n.privateKey, hash[:])
// Encode as NASPIP token
tokenData := TokenData {
Version: "1.0" ,
Data: base64.StdEncoding. EncodeToString (data),
Signature: base64.StdEncoding. EncodeToString (signature),
}
tokenJSON, err := json. Marshal (tokenData)
if err != nil {
return "" , err
}
return "naspip://" + base64.StdEncoding. EncodeToString (tokenJSON), nil
}
func ( n * NASPIP ) GenerateQRCode ( token string ) error {
return qrcode. WriteFile (token, qrcode.Medium, 256 , "payment_qr.png" )
}
func ( n * NASPIP ) VerifyToken ( token string ) ( * PaymentInstruction , error ) {
// Decode token
tokenDataBytes, err := base64.StdEncoding. DecodeString (token[ 8 :]) // Remove "naspip://"
if err != nil {
return nil , err
}
var tokenData TokenData
if err := json. Unmarshal (tokenDataBytes, & tokenData); err != nil {
return nil , err
}
// Decode payment instruction
instructionBytes, err := base64.StdEncoding. DecodeString (tokenData.Data)
if err != nil {
return nil , err
}
var instruction PaymentInstruction
if err := json. Unmarshal (instructionBytes, & instruction); err != nil {
return nil , err
}
// Verify signature
hash := sha256. Sum256 (instructionBytes)
signature, err := base64.StdEncoding. DecodeString (tokenData.Signature)
if err != nil {
return nil , err
}
if ! ed25519. Verify (n.publicKey, hash[:], signature) {
return nil , fmt. Errorf ( "invalid signature" )
}
return & instruction, nil
}
func generateUniqueID () string {
b := make ([] byte , 16 )
rand. Read (b)
return fmt. Sprintf ( " %x " , b)
}
func getDefaultExpiration () string {
return time. Now (). Add ( 24 * time.Hour). Format (time.RFC3339)
}
func main () {
naspip, err := NewNASPIP ()
if err != nil {
panic (err)
}
// Create payment instruction
token, err := naspip. CreatePaymentInstruction (
"100.00" ,
"USD" ,
"polygon" ,
"0x1234567890abcdef1234567890abcdef12345678" ,
"Payment for services" ,
)
if err != nil {
panic (err)
}
fmt. Printf ( "Generated token: %s\n " , token)
// Generate QR code
if err := naspip. GenerateQRCode (token); err != nil {
panic (err)
}
fmt. Println ( "QR code saved as payment_qr.png" )
// Verify token
instruction, err := naspip. VerifyToken (token)
if err != nil {
panic (err)
}
fmt. Printf ( "Verified instruction: %+v\n " , instruction)
}
Probar su implementación
Pruebas unitarias
// JavaScript/TypeScript example
describe ( "NASPIP" , () => {
let naspip : NASPIP ;
beforeEach (() => {
naspip = new NASPIP ();
});
test ( "should create valid payment instruction" , async () => {
const token = await naspip. createPaymentInstruction ({
amount: "100.00" ,
currency: "USD" ,
network: "polygon" ,
recipient: "0x1234567890abcdef1234567890abcdef12345678" ,
description: "Test payment" ,
});
expect (token). toMatch ( / ^ naspip: \/\/ / );
});
test ( "should verify valid token" , async () => {
const token = await naspip. createPaymentInstruction ({
amount: "100.00" ,
currency: "USD" ,
network: "polygon" ,
recipient: "0x1234567890abcdef1234567890abcdef12345678" ,
});
const instruction = await naspip. verifyToken (token, naspip.publicKey);
expect (instruction.amount.value). toBe ( "100.00" );
});
test ( "should reject invalid signature" , async () => {
const fakeToken = "naspip://invalid-token" ;
await expect (
naspip. verifyToken (fakeToken, naspip.publicKey),
).rejects. toThrow ( "Invalid signature" );
});
});
Buenas prácticas
Seguridad
Key Management : Almacene claves privadas en módulos de hardware seguros (HSM) cuando sea posible
Key Rotation : Implemente procedimientos regulares de rotación de claves
Input Validation : Valide siempre todos los parámetros de entrada
Error Handling : No exponga información sensible en mensajes de error
Rendimiento
Caching : Almacene en caché claves públicas para destinatarios frecuentes
Batch Processing : Procese múltiples tokens en lotes cuando sea posible
Async Operations : Use operaciones asíncronas para tareas intensivas en I/O
Integración
Webhooks : Implemente webhooks para actualizaciones de estado de pago
Rate Limiting : Implemente rate limiting para generación de tokens
Monitoring : Agregue logging y monitoreo comprehensivo
Fallbacks : Implemente mecanismos de respaldo para fallos de red
Próximos pasos
Después de implementar la funcionalidad básica:
Add Network Support : Implemente soporte para redes adicionales
Multi-Currency : Agregue soporte para múltiples monedas en un solo token
Advanced Features : Implemente atomic swaps, pagos con bloqueo temporal
Mobile Integration : Cree SDKs móviles para iOS y Android
Testing : Agregue pruebas de integración comprehensivas
Recursos
Last modified on October 12, 2026