Skip to content

ERP Integration

Overview

PeSIT Wizard exposes a REST API that makes it easy to integrate file transfers into your business processes.

Typical Use Cases

1. Export Payments from the ERP

┌─────────┐     ┌─────────────┐     ┌─────────────────────┐     ┌────────┐
│   ERP   │────>│ XML File    │────>│ PeSIT Wizard Client  │────>│ Bank   │
└─────────┘     └─────────────┘     └─────────────────────┘     └────────┘

Your ERP generates a SEPA payment file, then calls the PeSIT Wizard API to send it.

2. Import Statements into Accounting

┌────────┐     ┌─────────────────────┐     ┌─────────────┐     ┌─────────────┐
│ Bank   │────>│ PeSIT Wizard Client  │────>│ XML File    │────>│ Accounting  │
└────────┘     └─────────────────────┘     └─────────────┘     └─────────────┘

PeSIT Wizard Client retrieves the statements, then your accounting software imports them.

Webhook Integration

Configuration

Configure a webhook to be notified of transfers:

bash
curl -X POST http://localhost:8080/api/webhooks \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://my-erp.com/api/pesitwizard/callback",
    "events": ["TRANSFER_COMPLETED", "TRANSFER_FAILED"],
    "secret": "my-webhook-secret"
  }'

Received Payload

json
{
  "event": "TRANSFER_COMPLETED",
  "timestamp": "2025-01-10T10:30:05Z",
  "transfer": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "direction": "RECEIVE",
    "filename": "STATEMENT_20250110.XML",
    "localPath": "/data/received/STATEMENT_20250110.XML",
    "size": 8542
  }
}

Signature Verification

python
import hmac
import hashlib

def verify_webhook(payload, signature, secret):
    expected = hmac.new(
        secret.encode(),
        payload.encode(),
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(f"sha256={expected}", signature)

Integration Examples

Python

python
import requests

class PesitClient:
    def __init__(self, base_url, api_key=None):
        self.base_url = base_url
        self.session = requests.Session()
        if api_key:
            self.session.headers['Authorization'] = f'Bearer {api_key}'

    def send_file(self, server_id, file_path, remote_name, partner_id, virtual_file):
        with open(file_path, 'rb') as f:
            response = self.session.post(
                f'{self.base_url}/api/transfers/send',
                files={'file': f},
                data={
                    'serverId': server_id,
                    'remoteFilename': remote_name,
                    'partnerId': partner_id,
                    'virtualFile': virtual_file
                }
            )
        return response.json()

    def receive_file(self, server_id, remote_name, partner_id, virtual_file):
        response = self.session.post(
            f'{self.base_url}/api/transfers/receive',
            json={
                'serverId': server_id,
                'remoteFilename': remote_name,
                'partnerId': partner_id,
                'virtualFile': virtual_file
            }
        )
        return response.json()

    def download_file(self, transfer_id, local_path):
        response = self.session.get(
            f'{self.base_url}/api/transfers/{transfer_id}/download',
            stream=True
        )
        with open(local_path, 'wb') as f:
            for chunk in response.iter_content(chunk_size=8192):
                f.write(chunk)

# Usage
client = PesitClient('http://localhost:8080')

# Send a payment
result = client.send_file(
    server_id=1,
    file_path='/data/payments/payment_20250110.xml',
    remote_name='PAYMENT_20250110.XML',
    partner_id='MY_COMPANY',
    virtual_file='PAYMENTS'
)
print(f"Transfer {result['status']}: {result['id']}")

# Receive a statement
result = client.receive_file(
    server_id=1,
    remote_name='STATEMENT_20250110.XML',
    partner_id='MY_COMPANY',
    virtual_file='STATEMENTS'
)
if result['status'] == 'COMPLETED':
    client.download_file(result['id'], '/data/statements/statement_20250110.xml')

Node.js

javascript
const axios = require('axios');
const FormData = require('form-data');
const fs = require('fs');

class PesitClient {
  constructor(baseUrl) {
    this.baseUrl = baseUrl;
  }

  async sendFile(serverId, filePath, remoteName, partnerId, virtualFile) {
    const form = new FormData();
    form.append('file', fs.createReadStream(filePath));
    form.append('serverId', serverId);
    form.append('remoteFilename', remoteName);
    form.append('partnerId', partnerId);
    form.append('virtualFile', virtualFile);

    const response = await axios.post(
      `${this.baseUrl}/api/transfers/send`,
      form,
      { headers: form.getHeaders() }
    );
    return response.data;
  }

  async receiveFile(serverId, remoteName, partnerId, virtualFile) {
    const response = await axios.post(
      `${this.baseUrl}/api/transfers/receive`,
      { serverId, remoteFilename: remoteName, partnerId, virtualFile }
    );
    return response.data;
  }
}

// Usage
const client = new PesitClient('http://localhost:8080');

async function main() {
  // Send
  const sendResult = await client.sendFile(
    1, './payment.xml', 'PAYMENT.XML', 'MY_COMPANY', 'PAYMENTS'
  );
  console.log('Send:', sendResult.status);

  // Receive
  const receiveResult = await client.receiveFile(
    1, 'STATEMENT.XML', 'MY_COMPANY', 'STATEMENTS'
  );
  console.log('Receive:', receiveResult.status);
}

main();

Java

java
import org.springframework.web.client.RestTemplate;
import org.springframework.core.io.FileSystemResource;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.http.*;

public class PesitClient {
    private final RestTemplate restTemplate;
    private final String baseUrl;

    public PesitClient(String baseUrl) {
        this.baseUrl = baseUrl;
        this.restTemplate = new RestTemplate();
    }

    public TransferResult sendFile(int serverId, String filePath,
            String remoteName, String partnerId, String virtualFile) {

        LinkedMultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
        body.add("file", new FileSystemResource(filePath));
        body.add("serverId", serverId);
        body.add("remoteFilename", remoteName);
        body.add("partnerId", partnerId);
        body.add("virtualFile", virtualFile);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.MULTIPART_FORM_DATA);

        ResponseEntity<TransferResult> response = restTemplate.exchange(
            baseUrl + "/api/transfers/send",
            HttpMethod.POST,
            new HttpEntity<>(body, headers),
            TransferResult.class
        );
        return response.getBody();
    }
}

Supported File Formats

FormatDescriptionUsage
CFONB 160Domestic paymentsLegacy
CFONB 240Account statementsLegacy
pain.001SEPA payments (XML)Standard
pain.008SEPA direct debits (XML)Standard
camt.053Account statements (XML)Standard

PeSIT Wizard transports files transparently - the format is handled by your ERP and your bank.

PeSIT Wizard - Solution PeSIT moderne pour les entreprises