Passa al contenuto principale

Guida all'utilizzo di NoPos Connect

Questa guida ti accompagnerà passo dopo passo nell'integrazione di NoPos Connect nella tua applicazione.

Suggerimento

Questa guida assume che tu abbia già familiarità con OAuth 2.0. Se è la tua prima volta, ti consigliamo di leggere prima l'introduzione a NoPos Connect.

Prerequisiti

  • Account NoPos attivo
  • Applicazione registrata nella dashboard NoPos
  • Conoscenza base di OAuth 2.0

Setup iniziale

1. Registra la tua applicazione

Accedi alla dashboard NoPos e crea una nuova applicazione:

  1. Vai su ImpostazioniApplicazioni
  2. Clicca Nuova Applicazione
  3. Compila i dettagli:
    • Nome: Nome della tua app
    • Descrizione: Breve descrizione
    • Redirect URI: URL di ritorno dopo l'autorizzazione
    • Scopes: Permessi richiesti

2. Ottieni le credenziali

Dopo la creazione, riceverai:

  • Client ID: Identificatore pubblico della tua app
  • Client Secret: Chiave segreta (mantienila sicura!)

Implementazione

Flusso di autorizzazione

1. Genera URL di autorizzazione

function generateAuthUrl() {
const params = new URLSearchParams({
client_id: 'YOUR_CLIENT_ID',
client_secret: 'YOUR_CLIENT_SECRET',
redirect_uri: 'https://your-app.com/callback',
scopes: 'payments:read payments:write fiscal:read',
state: generateRandomState(),
response_type: 'code'
});

return `https://app.nopos.it/auth?${params}`;
}

function generateRandomState() {
return crypto.randomBytes(32).toString('hex');
}

2. Gestisci il callback

// Express.js example
app.get('/callback', (req, res) => {
const { access_token, token_type, expires_in, scope, state, error } = req.query;

// Gestisci errori
if (error) {
console.error('OAuth error:', error);
return res.redirect('/error?message=' + encodeURIComponent(req.query.error_description));
}

// Valida state per sicurezza CSRF
if (!validateState(state)) {
return res.status(400).send('Invalid state parameter');
}

// Salva il token
const tokenData = {
access_token,
token_type,
expires_in: parseInt(expires_in),
scope: scope.split(' '),
expires_at: Date.now() + (parseInt(expires_in) * 1000)
};

saveTokenToSession(req.session, tokenData);

res.redirect('/dashboard');
});

function validateState(state) {
// Implementa la validazione dello state
// Confronta con quello salvato in sessione
return true; // Placeholder
}

3. Usa il token per le API

class NoPosClient {
constructor(token) {
this.token = token;
this.baseUrl = 'https://api.nopos.it/v1';
}

async makeRequest(endpoint, options = {}) {
const url = `${this.baseUrl}${endpoint}`;
const headers = {
'Authorization': `Bearer ${this.token}`,
'Content-Type': 'application/json',
...options.headers
};

const response = await fetch(url, {
...options,
headers
});

if (!response.ok) {
throw new Error(`API Error: ${response.status} ${response.statusText}`);
}

return response.json();
}

// Esempi di utilizzo
async getPayments() {
return this.makeRequest('/payments');
}

async createPayment(paymentData) {
return this.makeRequest('/payments', {
method: 'POST',
body: JSON.stringify(paymentData)
});
}

async getInvoices() {
return this.makeRequest('/fiscal/invoices');
}
}

// Utilizzo
const client = new NoPosClient(accessToken);
const payments = await client.getPayments();

Gestione del token

Refresh automatico

class TokenManager {
constructor() {
this.token = null;
this.refreshTimer = null;
}

setToken(tokenData) {
this.token = tokenData;

// Imposta refresh automatico 5 minuti prima della scadenza
const refreshTime = tokenData.expires_at - (5 * 60 * 1000);
const timeUntilRefresh = refreshTime - Date.now();

if (timeUntilRefresh > 0) {
this.refreshTimer = setTimeout(() => {
this.refreshToken();
}, timeUntilRefresh);
}
}

async refreshToken() {
try {
// Implementa il refresh del token
const newToken = await this.requestNewToken();
this.setToken(newToken);
} catch (error) {
console.error('Token refresh failed:', error);
// Reindirizza al login
this.redirectToAuth();
}
}

async requestNewToken() {
// Implementa la richiesta di un nuovo token
// Questo dipende dalla tua implementazione
throw new Error('Not implemented');
}

redirectToAuth() {
window.location.href = generateAuthUrl();
}
}

Storage sicuro

// Per applicazioni web - usa sessionStorage
function saveTokenToSession(tokenData) {
sessionStorage.setItem('nopos_token', JSON.stringify(tokenData));
}

function getTokenFromSession() {
const tokenData = sessionStorage.getItem('nopos_token');
if (!tokenData) return null;

const parsed = JSON.parse(tokenData);

// Controlla se il token è scaduto
if (Date.now() >= parsed.expires_at) {
sessionStorage.removeItem('nopos_token');
return null;
}

return parsed;
}

// Per applicazioni mobile - usa storage sicuro
// React Native example
import AsyncStorage from '@react-native-async-storage/async-storage';

async function saveTokenSecure(tokenData) {
await AsyncStorage.setItem('nopos_token', JSON.stringify(tokenData));
}

async function getTokenSecure() {
const tokenData = await AsyncStorage.getItem('nopos_token');
if (!tokenData) return null;

const parsed = JSON.parse(tokenData);

if (Date.now() >= parsed.expires_at) {
await AsyncStorage.removeItem('nopos_token');
return null;
}

return parsed;
}

Esempi pratici

E-commerce Integration

class EcommerceIntegration {
constructor(noposClient) {
this.client = noposClient;
}

async processOrder(orderData) {
try {
// 1. Crea il pagamento
const payment = await this.client.createPayment({
amount: orderData.total * 100, // Converti in centesimi
currency: 'EUR',
description: `Ordine #${orderData.id}`,
metadata: {
order_id: orderData.id,
customer_email: orderData.customer.email
}
});

// 2. Crea la fattura
const invoice = await this.client.createInvoice({
customer: orderData.customer,
items: orderData.items,
payment_id: payment.id
});

// 3. Invia conferma
await this.sendOrderConfirmation(orderData.customer.email, {
order: orderData,
payment: payment,
invoice: invoice
});

return { payment, invoice };

} catch (error) {
console.error('Order processing failed:', error);
throw error;
}
}

async sendOrderConfirmation(email, data) {
// Implementa l'invio email
console.log('Sending confirmation to:', email);
}
}

Dashboard Analytics

class AnalyticsDashboard {
constructor(noposClient) {
this.client = noposClient;
}

async getDashboardData() {
try {
const [payments, invoices, webhooks] = await Promise.all([
this.client.getPayments({ limit: 100 }),
this.client.getInvoices({ limit: 100 }),
this.client.getWebhooks()
]);

return {
totalRevenue: payments.data.reduce((sum, p) => sum + p.amount, 0),
totalInvoices: invoices.data.length,
activeWebhooks: webhooks.data.filter(w => w.active).length,
recentPayments: payments.data.slice(0, 10),
recentInvoices: invoices.data.slice(0, 10)
};

} catch (error) {
console.error('Failed to load dashboard data:', error);
throw error;
}
}
}

Testing

Ambiente di test

// Configurazione per test
const TEST_CONFIG = {
client_id: 'test_client_id',
client_secret: 'test_client_secret',
redirect_uri: 'http://localhost:3000/callback',
base_url: 'https://api.nopos.it/v1'
};

// Mock per test
class MockNoPosClient {
constructor() {
this.calls = [];
}

async makeRequest(endpoint, options = {}) {
this.calls.push({ endpoint, options });

// Restituisci dati mock
if (endpoint === '/payments') {
return {
data: [
{ id: '1', amount: 1000, status: 'completed' },
{ id: '2', amount: 2000, status: 'pending' }
]
};
}

return { data: [] };
}
}

// Test example
describe('NoPos Integration', () => {
let client;

beforeEach(() => {
client = new MockNoPosClient();
});

test('should fetch payments', async () => {
const payments = await client.makeRequest('/payments');
expect(payments.data).toHaveLength(2);
expect(client.calls).toHaveLength(1);
});
});

Troubleshooting

Problemi comuni

Token scaduto

if (error.status === 401) {
// Token scaduto, reindirizza al login
redirectToAuth();
}

Scope insufficienti

if (error.status === 403) {
// Permessi insufficienti
console.error('Insufficient permissions. Required scopes:', error.required_scopes);
}

Rate limiting

if (error.status === 429) {
// Troppe richieste, aspetta
const retryAfter = error.headers['retry-after'];
setTimeout(() => retryRequest(), retryAfter * 1000);
}

Debug

// Abilita logging dettagliato
const DEBUG = process.env.NODE_ENV === 'development';

class NoPosClient {
async makeRequest(endpoint, options = {}) {
if (DEBUG) {
console.log('NoPos API Request:', {
endpoint,
method: options.method || 'GET',
headers: options.headers
});
}

const response = await fetch(url, options);

if (DEBUG) {
console.log('NoPos API Response:', {
status: response.status,
headers: Object.fromEntries(response.headers.entries())
});
}

return response.json();
}
}

Risorse aggiuntive


NoPos Connect - Integrazione semplice, risultati potenti