Este guia cobre a integração do NASPIP via API REST Fluxis (recomendado) ou a biblioteca naspip-go para implementações personalizadas.
Pré-requisitos
Credenciais da API Fluxis (Bearer token + API key) para integração REST
Para uso de biblioteca: Go 1.21+ e github.com/fluxisus/naspip-go/v3
Compreensão do formato de token NASPIP (naspip;{kis};{kid};v4.public....) — consulte Protocol Specification
API REST Fluxis (Recomendado)
Ler um 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...." }'
A resposta data é um PasetoCompleteResult (version, purpose, footer, payload). Para payloads URL sem payment_options, a Fluxis busca instruções de payload.data.url e retorna dados de pagamento resolvidos.
Criar um 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
}
}'
Payloads URL também são suportados: passe { "url": "https://...", "payment_options": ["..."] }.
::::note Aviso Swagger
OpenAPI pode documentar uma resposta de leitura plana com forma de checkout; a forma em runtime é PasetoCompleteResult. Consulte NASPIP_ENHANCEMENTS.md.
:::::
Implementações por linguagem
::::warning Exemplos legados abaixo
As seções JavaScript, Python e Go abaixo implementam um protocolo não padrão naspip:// + base64. Não interoperarão com Fluxis ou naspip-go. Prefira as seções REST API ou naspip-go acima até que estes exemplos sejam reescritos.
:::::
Implementação JavaScript/TypeScript
1. Instalar dependências
npm install crypto-js qrcode ed25519-supercop
2. Classe 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. Criar uma instrução de pagamento (TypeScript)
A Fluxis assina tokens NASPIP com suas chaves emissoras. Não construa instruções de pagamento localmente a menos que opere seu próprio emissor NASPIP. Em produção, crie uma solicitação de pagamento e use o token da resposta.
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);
}
O payload assinado dentro do token corresponde ao esquema de payload de instrução : vault address, unique_asset_id, amount, is_open, expires_at, e metadados order opcionais. A Fluxis atribui o endereço vault quando a solicitação de pagamento é criada.
Para minting de tokens de baixo nível quando você já controla endereço e expiração (apenas ferramentas avançadas/internas), use POST /v1/naspip/create com um objeto payment — consulte o exemplo curl na seção API REST Fluxis acima.
Implementação Python
1. Instalar dependências
pip install cryptography qrcode pillow
2. Implementação 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" )
Implementação Go
1. Dependências
go mod init naspip - example
go get github.com / fluxisus / naspip -go/ v3
go get github.com / skip2 /go- qrcode
Use protocol.PaymentInstructionsBuilder com paseto.PasetoV4Handler{} para operações create/read. Consulte exemplos naspip-go .
2. Implementação 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)
}
Testar sua implementação
Testes unitários
// 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" );
});
});
Boas práticas
Segurança
Key Management : Armazene chaves privadas em módulos de hardware seguros (HSM) quando possível
Key Rotation : Implemente procedimentos regulares de rotação de chaves
Input Validation : Sempre valide todos os parâmetros de entrada
Error Handling : Não exponha informações sensíveis em mensagens de erro
Performance
Caching : Armazene em cache chaves públicas para destinatários frequentes
Batch Processing : Processe múltiplos tokens em lotes quando possível
Async Operations : Use operações assíncronas para tarefas intensivas em I/O
Integração
Webhooks : Implemente webhooks para atualizações de status de pagamento
Rate Limiting : Implemente rate limiting para geração de tokens
Monitoring : Adicione logging e monitoramento abrangente
Fallbacks : Implemente mecanismos de fallback para falhas de rede
Próximos passos
Depois de implementar a funcionalidade básica:
Add Network Support : Implemente suporte para redes adicionais
Multi-Currency : Adicione suporte para múltiplas moedas em um único token
Advanced Features : Implemente atomic swaps, pagamentos com bloqueio temporal
Mobile Integration : Crie SDKs móveis para iOS e Android
Testing : Adicione testes de integração abrangentes
Recursos
Last modified on October 12, 2026