Skip to content

PLAN: Moodia Wiresphere API Integratie

Moodia

Moodia is de handelspartner/distributeur die Spranz producten afhandelt. Zij beheren het order fulfilment proces: zodra een Spranz klant een offerte accepteert, moet de order bij Moodia terechtkomen voor verwerking, verzending en levering. Moodia fungeert als de backoffice voor orderafhandeling — zij ontvangen orders, beheren voorraad, en verzorgen de logistiek.

Wiresphere

Wiresphere is het open-source applicatieframework (MIT licentie) waarop Moodia’s platform draait. Het is een TypeScript-based ecosysteem met een headless CMS, ingebouwd admin panel, en API-first architectuur. De API die wij aanspreken (staging-beton2go.mymoodia.de) is een Wiresphere-instantie die Moodia heeft ingericht voor hun order- en voorraadbeheer.

PartijRolVerantwoordelijkheden
Spranz (klant van Brinxx)Merkhouder / producteigenaarProductcatalogus, prijsstaffels, branding, klantrelaties
Brinxx / Magic e-Verse (wij)Platform & automatiseringAI sales agent, offerte generatie, e-mail verwerking, product search, designer tool, e-commerce platform
MoodiaFulfilment & distributieOrderverwerking, voorraadbeheer, verzending, CRM, logistiek
┌──────────────────────────────────────────────────────────────────────────┐
│ ORDER LIFECYCLE │
│ │
│ SPRANZ KLANT BRINXX / MAGIC e-VERSE MOODIA │
│ │
│ 1. Klant stuurt 2. Magic Agent Spranz 5. Order │
│ offerte-aanvraag ──► verwerkt e-mail wordt │
│ via e-mail opgepakt│
│ 3. AI genereert offerte │
│ 4. Klant accepteert met tierprijzen 6. Voorraad │
│ de offerte ──────► check │
│ ┌──── DEZE INTEGRATIE ────┐ │
│ │ │ 7. Pick, │
│ │ Geaccepteerde order ───►│──► pack & │
│ │ automatisch pushen │ ship │
│ │ naar Moodia via │ │
│ │ Wiresphere API │ 8. Status │
│ │ │◄── updates │
│ └──────────────────────────┘ │
│ │
│ 9. Klant ontvangt │
│ levering │
└──────────────────────────────────────────────────────────────────────────┘
  • Geen handmatige order invoer meer — geaccepteerde offertes worden automatisch doorgestuurd naar Moodia
  • Real-time voorraadcontrole — voordat een offerte wordt verstuurd kan de voorraad bij Moodia gecheckt worden
  • Order tracking — status van bestellingen opvragen via de agent of n8n flow
  • CRM synchronisatie — klantgegevens automatisch aanmaken/matchen in Moodia’s systeem
  • Foutafhandeling — bij API fouten automatische escalatie via WhatsApp
ComponentTechnologieLocatie
Magic Agent SpranzTypeScript/Express, Claude AI, PM2/home/adminwayne/magic_agent/agents/spranz/ (port 11010)
n8n SpranzMailFlow02n8n workflow enginehttp://192.168.1.26:8090
Moodia Wiresphere APIWiresphere framework, JWT authstaging-beton2go.mymoodia.de (46 endpoints)
Order tracking DBPostgreSQLmagic_agent_brinxxmoodia_order_sync tabel

╔══════════════════════════════════════════════════════════════════════╗
║ ║
║ STATUS: DRAFT — Wacht op API verkenning & antwoorden Moodia ║
║ BRON: Wayne → Michiel ║
║ PRIORITEIT: HIGH ║
║ ║
║ FASEN: ║
║ Fase 0: Voorbereiding & API Verkenning ⬜ PENDING ║
║ Fase 1: Moodia API Service Module ⬜ PENDING ║
║ Fase 2: Agent Tool Definities ⬜ PENDING ║
║ Fase 3: n8n SpranzMailFlow02 Uitbreiding ⬜ PENDING ║
║ Fase 4: End-to-End Testing ⬜ PENDING ║
║ Fase 5: Productie Migratie ⬜ BLOCKED ║
║ ║
║ BLOCKER: Geen zichtbaar order creation endpoint in API docs. ║
║ Moet bij Moodia nagevraagd worden (zie Open Vragen #2). ║
║ ║
╚══════════════════════════════════════════════════════════════════════╝

SpranzMailFlow02

n8n workflow die inkomende e-mails verwerkt, producten matcht, tierprijzen ophaalt en professionele offertes genereert. Draait op http://192.168.1.26:8090.

Magic Agent Spranz

TypeScript/Express agent (PM2: magic-agent-spranz, port 11010) met Claude Tool Use, product search, photo search, n8n bridge en e-mail service.

Moodia Staging API

46 endpoints beschikbaar op staging-beton2go.mymoodia.de. Auth via JWT. Geen productie URL beschikbaar. Onduidelijk hoe orders worden aangemaakt.

Order Push

Nog niet geïmplementeerd. Geaccepteerde offertes worden niet automatisch doorgestuurd naar Moodia.

┌─────────────────────────────────────────────────────────────────┐
│ HUIDIGE SITUATIE │
│ │
│ Klant e-mail │
│ │ │
│ ▼ │
│ ┌──────────────────────────┐ │
│ │ n8n SpranzMailFlow02 │ │
│ │ │ │
│ │ 1. Email ontvangen │ │
│ │ 2. Claude analyse │ │
│ │ 3. Product matching │ │
│ │ 4. Tierprijzen ophalen │ │
│ │ 5. Offerte genereren │ │
│ │ 6. ??? (hier stopt het) │ │
│ └──────────────────────────┘ │
│ │
│ ┌──────────────────────────┐ ┌───────────────────────────┐ │
│ │ Magic Agent Spranz │ │ Moodia Wiresphere │ │
│ │ (port 11010) │ │ (staging API) │ │
│ │ │ │ │ │
│ │ ✅ Product search │ │ ✅ Inventory endpoints │ │
│ │ ✅ Photo search │ │ ✅ Transaction endpoints │ │
│ │ ✅ n8n bridge │ │ ✅ CRM endpoints │ │
│ │ ❌ Moodia integratie │ ←──│ ❓ Order creation ??? │ │
│ └──────────────────────────┘ └───────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ DOEL SITUATIE │
│ │
│ Klant e-mail │
│ │ │
│ ▼ │
│ ┌──────────────────────────┐ │
│ │ n8n SpranzMailFlow02 │ │
│ │ │ │
│ │ 1. Email ontvangen │ │
│ │ 2. Claude analyse │ │
│ │ 3. Product matching │ │
│ │ 4. Tierprijzen ophalen │ │
│ │ 5. Offerte genereren │ │
│ │ 6. ✅ Offerte accepted? │ │
│ │ 7. ✅ Moodia klant check│───────┐ │
│ │ 8. ✅ Moodia order push │ │ │
│ │ 9. ✅ Status tracking │ │ │
│ └──────────────────────────┘ │ │
│ ▼ │
│ ┌──────────────────────────┐ ┌───────────────────────────┐ │
│ │ Magic Agent Spranz │ │ Moodia Wiresphere │ │
│ │ (port 11010) │ │ (productie API) │ │
│ │ │ │ │ │
│ │ ✅ Product search │ │ ✅ Auth (JWT) │ │
│ │ ✅ Photo search │ │ ✅ Inventory check │ │
│ │ ✅ n8n bridge │◄──►│ ✅ Order push │ │
│ │ ✅ Moodia tools (5x) │ │ ✅ CRM sync │ │
│ │ ✅ Order tracking DB │ │ ✅ Status tracking │ │
│ └──────────────────────────┘ └───────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘

Moodia Wiresphere API — Endpoint Overzicht

Section titled “Moodia Wiresphere API — Endpoint Overzicht”

Relevante Endpoints (46 totaal, hieronder de key endpoints)

Section titled “Relevante Endpoints (46 totaal, hieronder de key endpoints)”

Base URL: https://staging-beton2go.mymoodia.de

MethodEndpointBeschrijving
POST/api/v1/auth/token-authJWT token ophalen
MethodEndpointBeschrijving
GET/api/v1/admin/inventory/Alle producten ophalen
PUT/api/v1/admin/inventory/Product aanmaken of bijwerken (upsert)
DELETE/api/v1/admin/inventory/Producten verwijderen
GET/api/v1/admin/inventory/{sku}Product ophalen op SKU
MethodEndpointBeschrijving
GET/api/v1/admin/transaction/Alle transacties ophalen
GET/api/v1/admin/transaction/{processId}/{docId}Specifieke transactie ophalen
POST/api/v1/admin/transaction/{processId}/cancelTransactie annuleren
POST/api/v1/admin/transaction/{processId}/{docId}/cancelSpecifiek document annuleren
GET/api/v1/transaction/Publieke transacties endpoint
GET/api/v1/transaction/{processId}/{docId}Publieke transactie detail
MethodEndpointBeschrijving
POST/api/v1/admin/business-contacts/organisationsOrganisatie aanmaken
GET/api/v1/admin/business-contacts/organisationsAlle organisaties
GET/api/v1/admin/business-contacts/organisations/{id}Organisatie op ID
PUT/api/v1/admin/business-contacts/organisations/{id}Organisatie bijwerken
POST/api/v1/admin/business-contacts/peoplePersoon registreren
GET/api/v1/admin/business-contacts/people/allAlle contactpersonen
MethodEndpointBeschrijving
POST/api/v1/admin/import/{entity}Entity importeren (bulk)
GET/api/v1/admin/export/{entity}Entity exporteren

#VraagImpactStatus
1Wat is de productie base URL? (nu alleen staging beschikbaar)Fase 5 geblokkeerd⬜ Open
2Hoe werkt order aanmaak precies? Geen POST /transaction/ zichtbaar — alleen GET en cancelHele integratie geblokkeerd⬜ Open
3Is er een webhook/callback als transactiestatus wijzigt? (order verzonden, geleverd, etc.)Status tracking design⬜ Open
4Hoe mappen Spranz SKUs naar Moodia inventory SKUs? (1:1 of vertaaltabel?)SKU mapping implementatie⬜ Open
5Is er rate limiting op de API? Zo ja, hoeveel requests/minuut?Retry/throttle design⬜ Open
6Welke credentials voor POST /api/v1/auth/token-auth? Aparte staging vs productie?Auth implementatie⬜ Open
7Welke verplichte velden bij het aanmaken van organisatie/persoon/transactie? (Swagger schema)Type definities⬜ Open
#VraagContextImpact
8Welke entity waarden accepteert POST /api/v1/admin/import/{entity}? (bijv. transaction, order, invoice) En wat is het verwachte payload formaat?Als dit het order creation mechanisme is, moeten we exact weten welke entity values geldig zijn en wat de request body structuur is.Bepaalt of import endpoint bruikbaar is als order push
9Is er een sandbox/test modus op staging? Kunnen we test-transacties aanmaken die geen echte inventory of fulfilment triggeren?We willen veilig kunnen testen zonder bijwerkingen op voorraad of leveringen.Voorkomt ongewenste side-effects tijdens development
10Wat is het error response formaat? Is er een consistent schema met error codes en messages? (bijv. { "error": { "code": "...", "message": "..." } })We moeten errors gestructureerd kunnen loggen en afhandelen in de retry/escalatie logica.Error handling implementatie
11Wat is de JWT token lifetime? Is er een refresh token mechanisme of moeten we opnieuw authenticeren?Plan gaat uit van refresh 5 min voor expiry — maar we weten de werkelijke lifetime niet.Token management strategie
12Hoe werkt paginering op list endpoints? (transactions, inventory, organisations) Is er een page size limiet?Bij grote datasets moeten we alle resultaten kunnen ophalen zonder data te missen.API service implementatie
13Ondersteunt de API idempotency keys? Wat gebeurt er als dezelfde order twee keer wordt gepusht? (bijv. bij network retry)Zonder idempotency risico op dubbele orders bij retry na timeout.Retry logica en data integriteit
#VraagContextImpact
14Welke Spranz producten staan in Moodia’s inventory? Is dit de volledige Spranz catalogus of een subset? Moeten we eerst producten syncen via PUT /inventory/?Als Moodia niet alle Spranz SKUs kent, falen orders op onbekende SKUs.Bepaalt of product sync nodig is voor order push
15Wat is de unieke sleutel voor klant matching in Moodia? E-mailadres, bedrijfsnaam, KvK/BTW nummer?We moeten bestaande klanten kunnen vinden om duplicaten te voorkomen.CRM zoek- en matchlogica
16Wat is de order lifecycle? Welke statussen kan een transactie doorlopen? (bijv. pending → confirmed → shipped → delivered) Moeten we op statuswijzigingen reageren?Bepaalt welke statussen we in moodia_order_sync moeten bijhouden en of we polling of webhooks nodig hebben.Status tracking architectuur
17Is Moodia de pricing authority? Worden de prijzen uit onze offerte gevalideerd/overschreven door Moodia, of worden ze 1:1 overgenomen?Als Moodia prijzen overschrijft, kunnen klant en offerte niet meer overeenkomen.Prijsintegriteit en klantcommunicatie
18Hoe wordt BTW/valuta afgehandeld? Verwacht de API prijzen inclusief of exclusief BTW? Welke valuta?Spranz tier pricing is in EUR excl. BTW — mismatch leidt tot verkeerde facturatie.Prijs mapping in order push
19Hoe gaat Moodia om met partial fulfillment? Als een artikel niet op voorraad is, wordt de hele order geweigerd of deels geleverd?Bepaalt of we vooraf voorraad moeten checken en hoe we de klant informeren.Inventory check flow en klantcommunicatie
#VerzoekToelichting
20Postman collection of curl voorbeelden voor de belangrijkste flows: auth → create org → create orderSwagger UI retourneert geen schema’s bij remote access. Werkende voorbeelden versnellen ontwikkeling aanzienlijk.
21Technisch contactpersoon voor doorlopende integratie-vragen tijdens developmentVoorkomt vertragingen door wachten op meetings voor elke technische vraag.
22Sample request/response payloads voor minimaal: authenticatie, organisatie aanmaken, order aanmakenWe hebben de exacte veldnamen, types en required fields nodig voor onze TypeScript type definities.

Core Questions (must be answered before development starts)

Section titled “Core Questions (must be answered before development starts)”
#QuestionImpactStatus
1What is the production base URL? (currently only staging is available)Phase 5 blockedOpen
2How does order creation work exactly? There is no visible POST /api/v1/admin/transaction/ endpoint — only GET (retrieve) and POST cancel are documented. How do we push a new order into the system?Entire integration blockedOpen
3Are there webhooks/callbacks when a transaction status changes? (e.g. order shipped, delivered, etc.)Determines polling vs. push architecture for status trackingOpen
4How do Spranz SKUs map to Moodia inventory SKUs? Are they identical (1:1) or do we need a translation table?SKU mapping implementationOpen
5Is there rate limiting on the API? If so, how many requests per minute/hour?Retry and throttle designOpen
6What are the authentication credentials for POST /api/v1/auth/token-auth? Are staging and production credentials separate?Auth implementationOpen
7What are the required fields when creating an organisation, person, or transaction? (Swagger schemas are not accessible remotely)TypeScript type definitionsOpen
#QuestionContextImpact
8What entity values does POST /api/v1/admin/import/{entity} accept? (e.g. transaction, order, invoice) And what is the expected payload format?If this is the order creation mechanism, we need to know the exact valid entity values and request body structure.Determines if the import endpoint can be used for order push
9Is there a sandbox/test mode on staging? Can we create test transactions that don’t affect real inventory or trigger fulfilment?We want to test safely without side effects on stock or shipments.Prevents unwanted side effects during development
10What is the error response format? Is there a consistent schema with error codes and messages? (e.g. { "error": { "code": "...", "message": "..." } })We need to log and handle errors in a structured way for retry and escalation logic.Error handling implementation
11What is the JWT token lifetime? Is there a refresh token mechanism, or do we need to re-authenticate with username/password each time?Our plan assumes refreshing 5 minutes before expiry — but we don’t know the actual token lifetime.Token management strategy
12How does pagination work on list endpoints? (transactions, inventory, organisations) Is there a page size limit?With large datasets we need to be able to retrieve all results without missing data.API service implementation
13Does the API support idempotency keys? What happens if the same order is pushed twice? (e.g. during a network retry after timeout)Without idempotency there is a risk of duplicate orders on retry.Retry logic and data integrity
#QuestionContextImpact
14Which Spranz products are in Moodia’s inventory? Is this the full Spranz catalogue or a subset? Do we need to sync products first via PUT /inventory/?If Moodia doesn’t know all Spranz SKUs, orders will fail on unknown SKUs.Determines if product sync is needed before order push
15What is the unique key for customer matching in Moodia? Email address, company name, tax/VAT number?We need to find existing customers to prevent duplicates.CRM search and match logic
16What is the order lifecycle? What statuses can a transaction go through? (e.g. pending → confirmed → shipped → delivered) Do we need to react to status changes on our side?Determines which statuses we track in our moodia_order_sync table and whether we need polling or webhooks.Status tracking architecture
17Is Moodia the pricing authority? Are the prices from our quotation validated/overridden by Moodia, or accepted as-is?If Moodia overrides prices, the customer’s accepted quotation and actual invoice won’t match.Price integrity and customer communication
18How is VAT/currency handled? Does the API expect prices including or excluding VAT? What currency?Spranz tier pricing is in EUR excluding VAT — a mismatch leads to incorrect invoicing.Price mapping in order push
19How does Moodia handle partial fulfilment? If an item is out of stock, is the entire order rejected or partially fulfilled?Determines whether we need to check inventory before pushing and how we inform the customer.Inventory check flow and customer communication
#RequestExplanation
20Postman collection or curl examples for the main flows: auth → create organisation → create orderThe Swagger UI does not return schemas when accessed remotely. Working examples will significantly speed up development.
21Technical contact person for ongoing integration questions during developmentPrevents delays from having to wait for meetings for every technical question.
22Sample request/response payloads for at minimum: authentication, create organisation, create orderWe need the exact field names, types, and required fields for our TypeScript type definitions.

Doel: Alle open vragen beantwoorden, API handmatig testen, n8n capaciteit evalueren.

  1. Open vragen naar Moodia sturen

    Stuur de 7 open vragen hierboven naar het Moodia contactpersoon. Zonder antwoord op vraag 2 (order aanmaak) kan er niet verder ontwikkeld worden.

  2. Staging API authenticatie testen

    Terminal window
    # JWT token ophalen
    curl -X POST https://staging-beton2go.mymoodia.de/api/v1/auth/token-auth \
    -H "Content-Type: application/json" \
    -d '{"username": "<MOODIA_USER>", "password": "<MOODIA_PASS>"}'
    # Token bewaren en testen met inventory endpoint
    TOKEN="<jwt-token-hier>"
    curl -H "Authorization: Bearer $TOKEN" \
    https://staging-beton2go.mymoodia.de/api/v1/admin/inventory/
  3. Alle relevante endpoints handmatig testen

    Test met curl of Postman:

    • GET /api/v1/admin/inventory/ — producten ophalen
    • GET /api/v1/admin/inventory/{sku} — specifiek product
    • GET /api/v1/admin/business-contacts/organisations — organisaties
    • POST /api/v1/admin/business-contacts/organisations — organisatie aanmaken
    • GET /api/v1/admin/transaction/ — transacties ophalen
    • POST /api/v1/admin/import/transactiontesten als order creation mechanisme
    • GET /api/v1/admin/export/transaction — export om schema te reverse-engineeren

    Documenteer request/response schemas voor elk endpoint.

  4. n8n capaciteitscheck

    Check op http://192.168.1.26:8090:
    - Huidig execution/worker gebruik
    - Beschikbare execution slots voor extra Moodia stappen
    - Test connectiviteit: n8n → staging-beton2go.mymoodia.de (firewall, DNS)
  5. SKU mapping analyseren

    Vergelijk Spranz product SKUs uit de aplt_products tabel (magic_spranz_logo database) met de Moodia inventory. Bepaal of SKUs 1:1 matchen of dat een mapping tabel nodig is.


Doel: Centrale TypeScript service class voor alle Moodia API communicatie.

1.1 Nieuw bestand: src/services/moodia-api.ts

Section titled “1.1 Nieuw bestand: src/services/moodia-api.ts”

Locatie: /home/adminwayne/magic_agent/agents/spranz/src/services/moodia-api.ts

  1. MoodiaApiService class implementeren

    import axios, { AxiosInstance } from 'axios';
    import logger from '../utils/logger';
    import { moodia } from '../../config/config';
    export class MoodiaApiService {
    private client: AxiosInstance;
    private token: string | null = null;
    private tokenExpiry: number = 0;
    constructor() {
    this.client = axios.create({
    baseURL: moodia.apiUrl,
    timeout: moodia.timeout,
    headers: { 'Content-Type': 'application/json' },
    });
    }
    // ── Auth ─────────────────────────────────────────
    async authenticate(): Promise<string> { /* POST /api/v1/auth/token-auth */ }
    async getToken(): Promise<string> { /* Auto-refresh 5min voor expiry */ }
    // ── Inventory ────────────────────────────────────
    async getInventory(): Promise<MoodiaProduct[]> { /* GET /api/v1/admin/inventory/ */ }
    async getProductBySku(sku: string): Promise<MoodiaProduct> { /* GET /api/v1/admin/inventory/{sku} */ }
    async upsertProduct(data: any): Promise<void> { /* PUT /api/v1/admin/inventory/ */ }
    // ── Transactions / Orders ────────────────────────
    async getTransactions(): Promise<MoodiaTransaction[]> { /* GET /api/v1/admin/transaction/ */ }
    async getTransaction(processId: string, docId: string): Promise<MoodiaTransaction> { /* GET .../{processId}/{docId} */ }
    async createOrder(orderData: any): Promise<MoodiaOrderResult> { /* Endpoint TBD — zie Open Vraag #2 */ }
    async cancelTransaction(processId: string): Promise<void> { /* POST .../cancel */ }
    // ── CRM — Organisaties ──────────────────────────
    async findOrganisation(query: string): Promise<MoodiaOrganisation[]> { /* GET .../organisations */ }
    async getOrganisation(id: string): Promise<MoodiaOrganisation> { /* GET .../organisations/{id} */ }
    async createOrganisation(data: any): Promise<MoodiaOrganisation> { /* POST .../organisations */ }
    async updateOrganisation(id: string, data: any): Promise<MoodiaOrganisation> { /* PUT .../organisations/{id} */ }
    // ── CRM — Personen ──────────────────────────────
    async findPerson(query: string): Promise<MoodiaPerson[]> { /* GET .../people/all */ }
    async createPerson(data: any): Promise<MoodiaPerson> { /* POST .../people */ }
    // ── Import (potentieel voor order push) ──────────
    async importEntity(entity: string, data: any): Promise<void> { /* POST .../import/{entity} */ }
    async exportEntity(entity: string): Promise<any> { /* GET .../export/{entity} */ }
    }
    export const moodiaApi = new MoodiaApiService();

    Token Management:

    • JWT token cachen in geheugen
    • Automatisch refreshen 5 minuten voor expiry
    • Bij 401 response automatisch re-authenticeren en request herhalen (max 3 retries)

    Error Handling:

    • Retry met exponential backoff (1s, 2s, 4s) voor 5xx errors
    • Geen retry voor 4xx errors (behalve 401 → re-auth)
    • Gestructureerde error logging via Winston logger
    • Timeout van 30 seconden per request
  2. Type definities aanmaken

    Locatie: /home/adminwayne/magic_agent/agents/spranz/src/types/moodia.types.ts

    export interface MoodiaAuthResponse {
    token: string;
    expires_in?: number;
    }
    export interface MoodiaProduct {
    sku: string;
    name: string;
    description?: string;
    price?: number;
    stock?: number;
    category?: string;
    // Verdere velden na API verkenning in Fase 0
    }
    export interface MoodiaTransaction {
    processId: string;
    docId: string;
    status: string;
    items: MoodiaTransactionItem[];
    customer?: MoodiaOrganisation;
    createdAt: string;
    updatedAt: string;
    }
    export interface MoodiaTransactionItem {
    sku: string;
    quantity: number;
    price: number;
    description?: string;
    }
    export interface MoodiaOrganisation {
    id: string;
    name: string;
    email?: string;
    phone?: string;
    address?: MoodiaAddress;
    contactPersons?: MoodiaPerson[];
    }
    export interface MoodiaPerson {
    id: string;
    firstName: string;
    lastName: string;
    email?: string;
    phone?: string;
    organisationId?: string;
    }
    export interface MoodiaAddress {
    street: string;
    city: string;
    postalCode: string;
    country: string;
    }
    export interface MoodiaOrderResult {
    success: boolean;
    processId: string;
    docId: string;
    status: string;
    }
    export interface SpranzToMoodiaOrderMapping {
    spranzOrderId: string;
    moodiaProcessId: string;
    moodiaDocId: string;
    status: string;
    createdAt: Date;
    updatedAt: Date;
    }
  3. Config uitbreiden

    Wijzig: /home/adminwayne/magic_agent/agents/spranz/config/config.ts

    Voeg toe na de bestaande n8n config:

    /**
    * Moodia Wiresphere API Configuration
    */
    export const moodia = {
    apiUrl: process.env.MOODIA_API_URL || 'https://staging-beton2go.mymoodia.de',
    username: process.env.MOODIA_API_USERNAME || '',
    password: process.env.MOODIA_API_PASSWORD || '',
    timeout: parseInt(process.env.MOODIA_API_TIMEOUT || '30000', 10),
    enabled: !!process.env.MOODIA_API_URL,
    };

    En aan de default export toevoegen: moodia.

  4. Environment variabelen toevoegen

    Wijzig: /home/adminwayne/magic_agent/agents/spranz/.env en .env.example

    Terminal window
    # Moodia Wiresphere API
    MOODIA_API_URL=https://staging-beton2go.mymoodia.de
    MOODIA_API_USERNAME=<op te vragen bij Moodia>
    MOODIA_API_PASSWORD=<op te vragen bij Moodia>
    MOODIA_API_TIMEOUT=30000

Er is een mapping nodig tussen Spranz SKUs en Moodia inventory SKUs. Drie opties:

OptieWanneerComplexiteit
A: Directe 1:1 mappingSKUs zijn identiek in beide systemenLaag
B: Database mapping tabelSKUs verschillen, vertaaltabel nodigMiddel
C: Prefix/suffix transformatieSystematisch verschil (bijv. SPRANZ-376-00.001)Laag

Doel: 5 nieuwe Claude Tool Use tools voor Moodia integratie in de Spranz Agent.

2.1 Nieuw bestand: src/api/moodia-tools.ts

Section titled “2.1 Nieuw bestand: src/api/moodia-tools.ts”

Locatie: /home/adminwayne/magic_agent/agents/spranz/src/api/moodia-tools.ts

De tools volgen het bestaande patroon uit photo-search-agentic.ts — gedefinieerd als Anthropic.Tool objecten.

  1. Tool 1: moodia_check_inventory

    const MOODIA_CHECK_INVENTORY: Anthropic.Tool = {
    name: 'moodia_check_inventory',
    description: 'Controleer productvoorraad en details in het Moodia/Wiresphere systeem op basis van SKU.',
    input_schema: {
    type: 'object',
    properties: {
    sku: { type: 'string', description: 'Product SKU code (bijv. "376-00.001")' }
    },
    required: ['sku']
    }
    };
    // Handler: moodiaApi.getProductBySku(sku) → GET /api/v1/admin/inventory/{sku}
  2. Tool 2: moodia_push_order

    const MOODIA_PUSH_ORDER: Anthropic.Tool = {
    name: 'moodia_push_order',
    description: 'Stuur een geaccepteerde Spranz order door naar het Moodia/Wiresphere systeem.',
    input_schema: {
    type: 'object',
    properties: {
    customer_name: { type: 'string', description: 'Naam van de klant/organisatie' },
    customer_email: { type: 'string', description: 'E-mailadres van de klant' },
    items: {
    type: 'array',
    items: {
    type: 'object',
    properties: {
    sku: { type: 'string', description: 'Product SKU' },
    quantity: { type: 'number', description: 'Aantal stuks' },
    unit_price: { type: 'number', description: 'Prijs per stuk in EUR' },
    description: { type: 'string', description: 'Productomschrijving' }
    },
    required: ['sku', 'quantity']
    },
    description: 'Orderregels met producten'
    },
    reference: { type: 'string', description: 'Spranz order/offerte referentienummer' },
    notes: { type: 'string', description: 'Opmerkingen bij de order' }
    },
    required: ['customer_name', 'customer_email', 'items']
    }
    };

    Handler logica:

    1. moodiaApi.findOrganisation(customer_name) → bestaat klant al?
    2. Zo nee: moodiaApi.createOrganisation({...}) → maak klant aan
    3. moodiaApi.createOrder({...}) → push order
    4. Sla mapping op in moodia_order_sync tabel (spranz_reference ↔ moodia_processId)
    5. Return processId + docId voor tracking
  3. Tool 3: moodia_get_transaction_status

    const MOODIA_GET_STATUS: Anthropic.Tool = {
    name: 'moodia_get_transaction_status',
    description: 'Haal de status op van een order/transactie in Moodia voor track & trace.',
    input_schema: {
    type: 'object',
    properties: {
    process_id: { type: 'string', description: 'Moodia process ID' },
    doc_id: { type: 'string', description: 'Moodia document ID' }
    },
    required: ['process_id', 'doc_id']
    }
    };
    // Handler: moodiaApi.getTransaction(processId, docId)
    // → GET /api/v1/transaction/{processId}/{docId}
  4. Tool 4: moodia_find_organisation

    const MOODIA_FIND_ORG: Anthropic.Tool = {
    name: 'moodia_find_organisation',
    description: 'Zoek een klant/organisatie in het Moodia CRM systeem.',
    input_schema: {
    type: 'object',
    properties: {
    query: { type: 'string', description: 'Zoekterm: bedrijfsnaam of e-mailadres' }
    },
    required: ['query']
    }
    };
    // Handler: moodiaApi.findOrganisation(query)
    // → GET /api/v1/admin/business-contacts/organisations
    // Filter resultaten op naam of e-mail match
  5. Tool 5: moodia_create_organisation

    const MOODIA_CREATE_ORG: Anthropic.Tool = {
    name: 'moodia_create_organisation',
    description: 'Maak een nieuwe klant/organisatie aan in het Moodia CRM systeem.',
    input_schema: {
    type: 'object',
    properties: {
    name: { type: 'string', description: 'Bedrijfsnaam' },
    email: { type: 'string', description: 'E-mailadres' },
    phone: { type: 'string', description: 'Telefoonnummer' },
    street: { type: 'string', description: 'Straat + huisnummer' },
    city: { type: 'string', description: 'Plaats' },
    postal_code: { type: 'string', description: 'Postcode' },
    country: { type: 'string', description: 'Land (ISO code, bijv. "NL", "DE")' }
    },
    required: ['name', 'email']
    }
    };
    // Handler: moodiaApi.createOrganisation(data)
    // → POST /api/v1/admin/business-contacts/organisations
  6. Tools integreren in de agent chat flow

    Wijzig: /home/adminwayne/magic_agent/agents/spranz/src/api/send-message.ts

    De Moodia tools moeten beschikbaar worden gemaakt in de Claude API call wanneer de conversatie context over Moodia, orders, voorraad, of track & trace gaat. Dit volgt het bestaande patroon van photo-search-agentic.ts:

    // In send-message.ts, bij het samenstellen van de Claude API call:
    // Detecteer Moodia-gerelateerde intent
    const moodiaKeywords = /moodia|voorraad|inventory|order.*push|track.*trace|transactie.*status/i;
    if (moodiaKeywords.test(userMessage)) {
    tools = [...MOODIA_TOOLS]; // Alle 5 tools beschikbaar maken
    }

Aan te maken in: magic_agent_brinxx database

CREATE TABLE moodia_order_sync (
id SERIAL PRIMARY KEY,
spranz_reference VARCHAR(100), -- Spranz offerte/order referentie
moodia_process_id VARCHAR(100), -- Moodia processId
moodia_doc_id VARCHAR(100), -- Moodia docId
customer_name VARCHAR(255),
customer_email VARCHAR(255),
moodia_organisation_id VARCHAR(100), -- Moodia CRM organisatie ID
status VARCHAR(50) DEFAULT 'pushed', -- pushed, confirmed, shipped, delivered, cancelled
order_data JSONB, -- Volledige order data als JSON
moodia_response JSONB, -- Response van Moodia bij aanmaak
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW(),
synced_via VARCHAR(20) DEFAULT 'agent',-- 'agent' of 'n8n'
error_message TEXT -- Eventuele foutmelding
);
CREATE INDEX idx_moodia_sync_process ON moodia_order_sync(moodia_process_id);
CREATE INDEX idx_moodia_sync_reference ON moodia_order_sync(spranz_reference);
CREATE INDEX idx_moodia_sync_status ON moodia_order_sync(status);

Fase 3 — n8n SpranzMailFlow02 Uitbreiding

Section titled “Fase 3 — n8n SpranzMailFlow02 Uitbreiding”

Doel: De bestaande n8n flow uitbreiden met Moodia order-push stappen.

HUIDIGE FLOW:
Email → Claude analyse → Product matching → Tierprijzen → Offerte → [EINDE]
UITGEBREIDE FLOW:
Email → Claude analyse → Product matching → Tierprijzen → Offerte →
[NIEUW] Offerte geaccepteerd? →
JA → [NIEUW] Moodia Auth →
[NIEUW] Moodia Klant Check →
NIET GEVONDEN → [NIEUW] Moodia Klant Aanmaken →
[NIEUW] Moodia Order Push →
[NIEUW] Status Logging →
[NIEUW] Bevestiging
NEE → [bestaande flow]
  1. Node: “Moodia Auth” (HTTP Request)

    EigenschapWaarde
    MethodPOST
    URL{{$env.MOODIA_API_URL}}/api/v1/auth/token-auth
    Body (JSON){ "username": "{{$env.MOODIA_USERNAME}}", "password": "{{$env.MOODIA_PASSWORD}}" }
    OutputJWT token opslaan in flow variabele
  2. Node: “Moodia Klant Check” (HTTP Request)

    EigenschapWaarde
    MethodGET
    URL{{$env.MOODIA_API_URL}}/api/v1/admin/business-contacts/organisations
    HeadersAuthorization: Bearer {{$node.MoodiaAuth.json.token}}
    QueryZoek op klantnaam/email uit offerte
    LogicNiet gevonden → Node 3, wel gevonden → Node 4
  3. Node: “Moodia Klant Aanmaken” (HTTP Request)

    EigenschapWaarde
    MethodPOST
    URL{{$env.MOODIA_API_URL}}/api/v1/admin/business-contacts/organisations
    HeadersAuthorization: Bearer {{$node.MoodiaAuth.json.token}}
    BodyKlantgegevens uit de offerte/order data
  4. Node: “Moodia Order Push” (HTTP Request)

    EigenschapWaarde
    MethodNader te bepalen (zie Open Vraag #2)
    URLNader te bepalen
    HeadersAuthorization: Bearer {{$node.MoodiaAuth.json.token}}
    BodyOrder data gemapped vanuit Spranz offerte
  5. Node: “Order Status Logging” (PostgreSQL)

    INSERT INTO moodia_order_sync
    (spranz_reference, moodia_process_id, moodia_doc_id, customer_name,
    customer_email, status, order_data, moodia_response, synced_via)
    VALUES
    ($1, $2, $3, $4, $5, 'pushed', $6::jsonb, $7::jsonb, 'n8n');
  6. Node: “Error Handler” (IF + Webhook)

    Als Moodia API fout:
    → WhatsApp escalatie (bestaand patroon in flow)
    → Log error in moodia_order_sync tabel
    Als succes:
    → Optionele bevestigingsmail naar klant
    → Log succes
AanpakVoordeelNadeelAanbeveling
Elke execution nieuw tokenEenvoudig te implementerenIets trager (extra API call)Start hiermee
Token cachen in n8n static dataSneller, minder API callsComplexer, static data managementLater optimaliseren

Doel: Alle componenten testen op staging voordat productie wordt uitgerold.

TestVerwacht Resultaat
Authenticatie met geldige credentialsJWT token ontvangen
Authenticatie met ongeldige credentialsError 401, nette foutmelding
Token refresh mechanismeAutomatisch nieuw token na expiry
getProductBySku met bestaand SKUProduct data retour
getProductBySku met onbekend SKU404, nette foutmelding
findOrganisation met bestaande naamOrganisatie gevonden
createOrganisation met valide dataOrganisatie aangemaakt, ID retour
createOrder (endpoint TBD)Order aangemaakt, processId + docId retour
getTransaction met bestaand processIdTransactie status retour
Timeout handlingRequest faalt netjes na 30s
5xx retryRetry met backoff, max 3 pogingen
TestVerwacht Resultaat
Agent chat: “check voorraad SKU 376-00.001”Tool moodia_check_inventory aangeroepen, voorraad getoond
Agent chat: “push order naar Moodia”Tool moodia_push_order aangeroepen, klant check + order push
Agent chat: “status van mijn bestelling”Tool moodia_get_transaction_status aangeroepen met processId
Agent chat: “zoek klant Bedrijf X”Tool moodia_find_organisation aangeroepen
Agent chat: “maak klant aan”Tool moodia_create_organisation aangeroepen
Duplicate klant checkBestaande klant wordt gevonden, niet opnieuw aangemaakt
TestVerwacht Resultaat
Flow met geaccepteerde offerteMoodia auth + klant check + order push succesvol
Flow met nieuwe klantKlant aangemaakt in Moodia CRM
Flow met bestaande klantKlant gevonden, niet opnieuw aangemaakt
Flow met API errorWhatsApp escalatie, error gelogd
Flow execution tijd< 30 seconden inclusief Moodia API calls
Meerdere orders achter elkaarGeen race conditions, alle orders correct
  1. Volledige end-to-end flow

    • Stuur test e-mail naar Spranz mailbox
    • Verifieer offerte generatie
    • Simuleer offerte acceptatie
    • Controleer Moodia staging: klant aangemaakt?
    • Controleer Moodia staging: order zichtbaar?
    • Controleer database: moodia_order_sync record aanwezig?
  2. Status tracking test

    • Vraag transactie status op via agent
    • Controleer of processId/docId correct zijn
    • Controleer publieke endpoint: GET /api/v1/transaction/{processId}/{docId}
  3. Error recovery test

    • Simuleer Moodia API downtime (verkeerde URL)
    • Verifieer WhatsApp escalatie
    • Verifieer error logging in database
    • Herstel API URL en test opnieuw

  1. Productie configuratie

    Terminal window
    # Update .env op de server
    MOODIA_API_URL=https://<productie-url-van-moodia>
    MOODIA_API_USERNAME=<productie-credentials>
    MOODIA_API_PASSWORD=<productie-credentials>
  2. PM2 restart

    Terminal window
    pm2 restart magic-agent-spranz
    pm2 logs magic-agent-spranz --lines 50
  3. n8n credentials updaten

    Update Moodia API credentials in n8n voor de productie URL.

  4. Eerste productie order

    • Push handmatig 1 order via de agent
    • Verifieer in Moodia productie dashboard
    • Controleer transactie status ophalen
  5. Monitoring opzetten

    • Winston log level op info voor Moodia calls
    • Alerting bij herhaalde API failures
    • Dagelijkse check op moodia_order_sync tabel voor error status records

BestandActieBeschrijving
agents/spranz/src/services/moodia-api.tsNIEUWCentrale Moodia API service class met JWT auth, retry logic
agents/spranz/src/types/moodia.types.tsNIEUWTypeScript interfaces voor Moodia data modellen
agents/spranz/src/api/moodia-tools.tsNIEUW5 Claude Tool Use definities voor Moodia integratie
agents/spranz/config/config.tsWIJZIGMoodia config sectie toevoegen
agents/spranz/.envWIJZIGMoodia environment variabelen toevoegen
agents/spranz/.env.exampleWIJZIGMoodia env vars documenteren
agents/spranz/src/api/send-message.tsWIJZIGMoodia tools integreren in chat flow
agents/spranz/src/index.tsWIJZIGMoodia health check, export config
n8n SpranzMailFlow02WIJZIG6 nieuwe nodes voor Moodia integratie
DatabaseTabelActieBeschrijving
magic_agent_brinxxmoodia_order_syncNIEUWOrder tracking en sync status
magic_agent_brinxxmoodia_sku_mappingNIEUW (optioneel)SKU vertaaltabel indien nodig

RisicoImpactKansMitigatie
Geen POST endpoint voor order aanmaakHOOG — Gehele integratie geblokkeerdMiddelImport endpoint testen; Moodia contacten voor docs
Moodia staging API instabielMIDDEL — Testing vertraagdLaagRetry mechanisme; optioneel mock server
SKU mapping mismatchMIDDEL — Orders met verkeerde productenMiddelEerst inventory export vergelijken met Spranz SKUs
n8n capacity tekortLAAG — Extra stappen te traagLaagWorker/execution limiet verhogen
JWT token expiry tijdens flowLAAG — Order push faaltLaagAuto-refresh; retry op 401
Rate limiting niet bekendMIDDEL — API calls geblokkeerdMiddelThrottle implementeren; batch requests

ResourceURL / Locatie
Moodia staging API docshttps://staging-beton2go.mymoodia.de/api/docs/#/
Moodia auth endpointPOST /api/v1/auth/token-auth
n8n SpranzMailFlow02http://192.168.1.26:8090/workflow/SpranzMailFlow02
Spranz Agent codebase/home/adminwayne/magic_agent/agents/spranz/
Spranz Agent PM2magic-agent-spranz (port 11010)
Agent databasemagic_agent_brinxx (PostgreSQL)
Product databasemagic_spranz_logo (Spranz SKUs)

Plan aangemaakt: 4 maart 2026 | Bron ticket: Wayne → Michiel | Status: Draft — wacht op Moodia API verkenning