Vai al contenuto principale
La Admin API (/api/v1/admin/*) espone la gestione completa del negozio: catalogo, prezzi, stock, ordini, clienti, contenuti, marketing, report, impostazioni. È pensata per backend, integrazioni (ERP/PIM/fatturazione) e automazioni — inclusi gli agenti AI via MCP.

Autenticazione e permessi

Ogni chiamata porta un Bearer token:
Il token può essere:
  • di un utente staff: si ottiene con POST /auth/login e si rinnova con il refresh a rotazione (vedi Autenticazione). Per gli account staff un refresh token superato e riusato chiude la sessione: non condividerlo fra processi.
  • un token API: la credenziale consigliata per integrazioni e agenti che lavorano a lungo. Si usa come Bearer, senza login né refresh, ha un ruolo scelto e una scadenza obbligatoria (da 1 a 365 giorni) e si revoca all’istante. Lo genera un amministratore, se la funzione è abilitata per il negozio (GET /admin/api-tokens/status; altrimenti 403 tenant_keys.admin_api_disabled).
I permessi sono granulari: catalog, sales, customers, marketing, content, reviews, reports, tax, shipping, system, users. Il ruolo dell’utente o del token decide quali ha (admin, manager, catalog_manager, sales_manager, marketing_manager, content_editor, customer_service, accountant): la matrice completa è in GET /admin/roles. Senza il permesso dell’area la risposta è 403 auth.permission_required. Ogni chiamata è vincolata al suo negozio (claim tenant_id).
La Admin API è server-side. Non incorporare mai un token staff o un token API in un client pubblico.

Regole che contano per chi integra

Dal rilascio del 10 ottobre 2026 l’API applica le regole qui sotto. Campi, corpi e risposte completi sono nella API Reference.

Soldi: chi può fare cosa

Oltre al permesso dell’area, alcune azioni guardano il ruolo:

Titolare, utenti staff e token API

  • Ogni negozio ha un titolare: un amministratore attivo, registrato e stabile, che non cambia se si promuove un altro account. GET /auth/me e la lista utenti lo indicano con is_owner: true. Lo cambia solo l’assistenza Vellaro.
  • Il titolare è protetto: password, ruolo, disattivazione, eliminazione e reset della 2FA del suo account rispondono 403 user.owner_protected. Sugli altri amministratori le stesse azioni le fa solo il titolare (403 user.owner_only). Un’azione che lascerebbe il negozio senza amministratori attivi dà 409 user.last_admin.
  • Un token API non gestisce utenti né credenziali: creare, modificare o eliminare utenti staff, resettarne la 2FA, generare o revocare token API e chiavi publishable risponde 403 auth.api_token_forbidden. Le letture restano permesse.

Ordini, rimborsi e resi

PATCH /admin/orders/{id} con "status": "refunded" su un ordine paid o partially_refunded esegue un rimborso vero del residuo sul gateway di pagamento: muove denaro, come POST /admin/orders/{id}/refunds. Se il gateway fallisce la risposta è 502 order.refund_gateway_error e l’ordine resta com’era. Su un ordine non incassato la risposta è 409 order.refund_not_collected: lo stato giusto è cancelled.
  • Le transizioni di stato sono validate: una non ammessa dà 409 order.invalid_transition.
  • comment è una nota interna per impostazione predefinita; con comment_public: true la vede anche il cliente nella sua cronologia.
  • Un rimborso totale o l’annullo di un ordine pagato restituiscono anche la parte pagata con un buono regalo. Lo stock rientra una volta sola.
  • I resi partono da una riga dell’ordine: GET /admin/returns/order-context/{order_id} elenca le righe con le quantità restituibili, poi POST /admin/returns. Una variante fuori dall’ordine o una quantità oltre il restituibile danno 422 return.item_not_in_order / return.quantity_exceeds_order. Motivi e stati dei resi sono un catalogo comune in sola lettura (403 return.lookup_global sulle scritture).
Rimborso esplicito, anche parziale (amount omesso = tutto il residuo):

Catalogo e prezzi

POST /admin/products salva tutti i campi del prodotto e crea le varianti inline nella stessa transazione. Lo SKU è unico nel negozio: un doppione (anche fra due varianti inline) dà 409 product.sku_taken e nulla viene scritto. Uno slug doppio dà 409 product.slug_taken; lo slug di un prodotto eliminato si libera da solo.
  • Prezzi speciali e sconti a quantità (/admin/products/{id}/specials, /discounts): il price deve essere maggiore di zero, altrimenti 422 product.price_rule_not_positive. Uno speciale vale per tutti (customer_group_id: null) o per un gruppo clienti attivo, nella sua finestra di date; fra più speciali vince la priority più bassa, poi il prezzo più basso. Lo speciale può solo abbassare il prezzo, e carrello e checkout lo applicano.
  • Saldo sulla variante: sale_price, sale_start e sale_end vanno insieme (422 product.sale_window_invalid se la finestra non è valida); per toglierlo mandali tutti e tre a null.

Coupon e buoni regalo

  • I coupon sono validati in creazione e modifica: 422 coupon.percentage_out_of_range, coupon.negative_discount, coupon.dates_inverted; 409 coupon.code_taken. La lista ha il filtro status (active, scheduled, expired, exhausted, inactive).
  • DELETE /admin/coupons/{id} elimina davvero un coupon mai usato (il codice torna libero) e disattiva quello già usato: leggi deleted e deactivated nella risposta.
  • Buoni regalo (/admin/vouchers, permesso marketing): codice, importo e saldo. Il saldo si spende al checkout (voucher_code), con amount_spent, redemption_count e lo storico in GET /admin/vouchers/{id}/history. Anche qui DELETE elimina solo un buono mai speso e altrimenti lo disattiva.

Abbonamenti e piani ricorrenti

Un piano (POST /admin/recurrings, permesso system) descrive la cadenza dei rinnovi:
All’acquisto il cliente paga il prezzo del prodotto; il primo rinnovo a 9,90 arriva dopo 14 giorni, poi ogni mese, per 12 rinnovi. trial_price è accettato ma non applicato. Un abbonamento con tutte le rate addebitate passa a completed, stato terminale (409 subscription.already_completed su cancel). Un piano che ha avuto abbonamenti non si elimina (409 recurring.has_subscriptions): disattivalo con {"is_active": false}. Se il piano del negozio non include gli abbonamenti, la creazione risponde 403 plan.required.

Clienti e affiliati

Anonimizzazione (diritto all’oblio), irreversibile: i dati personali spariscono, gli ordini restano per gli obblighi fiscali. Il corpo ripete l’email attuale del cliente come conferma.
Email di conferma sbagliata: 422 customer.anonymize_confirmation; cliente già anonimizzato: 409 customer.anonymized.
  • Disattivare un cliente (PATCH /admin/customers/{id} con is_active: false) chiude subito tutte le sue sessioni.
  • Commissioni degli affiliati (/admin/affiliate-commissions): si leggono con customers; approvare, segnare pagata o rifiutare richiede anche reports. Il riepilogo (/summary) ha una riga per affiliato e valuta: le valute non si sommano mai.

Report

  • Un ordine conta come ricavo se è incassato (paid o partially_refunded, non refunded); l’importo è il netto, totale meno rimborsato.
  • I numeri principali sono nella valuta base del negozio (campo currency); gli incassi in altre valute stanno a parte in other_currencies.
  • «Oggi», giorni e mesi seguono il fuso del negozio, restituito in timezone.

Impostazioni del negozio

PUT /admin/settings (permesso system) salva le chiavi di un gruppo. Un valore fuori regola blocca tutto il salvataggio con 422 settings.invalid_value (data.key dice quale).

Esempi

Buone pratiche

  • Errori: fai switch su error_code. Un 403 plan.required significa che la funzione non è inclusa nel piano del negozio: non ritentare.
  • Idempotenza & bulk: per aggiornamenti massivi (prezzi, stock), procedi a batch e gestisci i 409/422 per riga.
  • Audit: ogni mutazione admin è registrata nell’audit log del negozio.
  • Soft-delete: eliminare un prodotto imposta deleted_at (non distrugge lo storico ordini); disattivare è cosa diversa (is_active).
  • Webhook: per reagire agli eventi senza polling usa i webhook.
  • Versioning: l’API è su /api/v1 — cambi retrocompatibili; le rotture andranno su una nuova versione.
Il riferimento completo delle centinaia di endpoint admin è nella API Reference (gruppo Admin API), generata dallo schema OpenAPI live.