# Providers & Configurations

Understanding how Docs-Dispatcher resolves provider configurations is critical for successful API integration. This guide explains the hybrid 3-tier provider resolution system and how to configure providers for your services.

## Overview

Docs-Dispatcher uses a flexible **3-tier provider resolution system** that balances simplicity with control:

```
Tier 1: Company Default Config
      ↓ (can be overridden)
Tier 2: User Override Config
      ↓ (can be overridden)
Tier 3: Explicit providerName in Request
```

This system allows:

* Companies to set default providers for all users
* Individual users to override with their preferred providers
* API requests to explicitly specify providers for one-off cases

## How Provider Resolution Works

When you make a dispatch request, Dispatcher resolves the provider in this order:

### Resolution Priority (Highest to Lowest)

1. **Explicit `providerName` in Request** - Always wins if provided
2. **User Override Configuration** - User-specific provider preference
3. **Company Default Configuration** - Fallback for all company users

If no configuration is found at any tier, the request fails with `400 Bad Request`.

## Real-World Example

Let's see how this works in practice:

### Scenario Setup

**Company: Acme Corp**

* Default invoicing provider: Qonto
* Default SMS provider: Brevo

**User: Alice**

* SMS override: OVH (she prefers OVH for SMS)

**User: Bob**

* No overrides (uses company defaults)

### Resolution Examples

#### Example 1: No Explicit Provider (Uses Defaults)

**Alice sends an invoice:**

```json
POST /api/invoicing
{
  "documentType": "INVOICE",
  "template": { "id": 123, "data": {...} }
}
```

**Resolution:** Qonto (company default, Alice has no override)

***

**Bob sends SMS:**

```json
POST /api/sms
{
  "phoneNumber": "+33612345678",
  "message": "Your order is ready"
}
```

**Resolution:** Brevo (company default, Bob has no override)

***

**Alice sends SMS:**

```json
POST /api/sms
{
  "phoneNumber": "+33612345678",
  "message": "Your order is ready"
}
```

**Resolution:** OVH (Alice's user override)

#### Example 2: Explicit Provider (Overrides Everything)

**Alice sends invoice with explicit provider:**

```json
POST /api/invoicing
{
  "providerName": "pennylane",
  "documentType": "INVOICE",
  "template": { "id": 123, "data": {...} }
}
```

**Resolution:** PennyLane (explicit request wins, ignores Qonto default)

***

**Bob sends SMS with explicit provider:**

```json
POST /api/sms
{
  "providerName": "sms_magic",
  "phoneNumber": "+33612345678",
  "message": "Your order is ready"
}
```

**Resolution:** SMS Magic (explicit request wins, ignores Brevo default)

## Provider Configuration Structure

Each provider requires a configuration object with provider-specific credentials and settings.

### Configuration Storage

Provider configurations are stored in:

* **Company level**: `GET /api/v1/companies/:companyId/configs`
* **User level**: `GET /api/v1/users/:userId/configs`

### Common Configuration Fields

All provider configs share these fields:

```json
{
  "service": "invoicing",
  "providerName": "qonto",
  "isDefault": true,
  "isActive": true,
  "config": {
    // Provider-specific fields
  }
}
```

| Field          | Type    | Description                                                           |
| -------------- | ------- | --------------------------------------------------------------------- |
| `service`      | string  | Service type: `invoicing`, `esign`, `postal`, `sms`, `email`          |
| `providerName` | string  | Provider identifier (see [Available Providers](#available-providers)) |
| `isDefault`    | boolean | Set as default for this service                                       |
| `isActive`     | boolean | Enable/disable without deleting                                       |
| `config`       | object  | Provider-specific credentials and settings                            |

### Provider-Specific Config Examples

#### Invoicing: Qonto

```json
{
  "service": "invoicing",
  "providerName": "qonto",
  "isDefault": true,
  "isActive": true,
  "config": {
    "apiKey": "qonto_live_abc123xyz",
    "organizationSlug": "acme-corp",
    "useSandbox": false
  }
}
```

#### eSign: Universign

```json
{
  "service": "esign",
  "providerName": "universign",
  "isDefault": true,
  "isActive": true,
  "config": {
    "username": "acme@example.com",
    "password": "secure-password",
    "apiUrl": "https://api.universign.com/v1"
  }
}
```

#### SMS: Brevo

```json
{
  "service": "sms",
  "providerName": "brevo",
  "isDefault": true,
  "isActive": true,
  "config": {
    "apiKey": "xkeysib-abc123xyz",
    "sender": "Acme"
  }
}
```

#### Postal: MySendingBox

```json
{
  "service": "postal",
  "providerName": "mysendingbox",
  "isDefault": true,
  "isActive": true,
  "config": {
    "apiKey": "msb_live_abc123xyz",
    "webhookSecret": "whsec_def456uvw"
  }
}
```

## Available Providers

Docs-Dispatcher supports 12 external providers across 7 services:

### Invoicing (4 providers)

| Provider  | `providerName` | Document Types                     | Webhooks |
| --------- | -------------- | ---------------------------------- | -------- |
| iPaidThat | `ipaidthat`    | INVOICE, E\_INVOICE, QUOTE, CREDIT | No       |
| PennyLane | `pennylane`    | INVOICE, E\_INVOICE, QUOTE, CREDIT | No       |
| Qonto     | `qonto`        | INVOICE, E\_INVOICE, QUOTE, CREDIT | No       |
| SuperPDP  | `superpdp`     | INVOICE, E\_INVOICE, QUOTE, CREDIT | No       |

### eSign (3 providers)

| Provider   | `providerName` | Webhooks |
| ---------- | -------------- | -------- |
| Signaturit | `signaturit`   | Yes      |
| Universign | `universign`   | Yes      |
| Yousign    | `yousign`      | No       |

### Postal (1 provider)

| Provider     | `providerName` | Webhooks |
| ------------ | -------------- | -------- |
| MySendingBox | `mysendingbox` | Yes      |

### SMS (4 providers)

| Provider   | `providerName` | Webhooks |
| ---------- | -------------- | -------- |
| Brevo      | `brevo`        | No       |
| OVH        | `ovh`          | No       |
| SMS Factor | `sms_factor`   | No       |
| SMS Magic  | `sms_magic`    | No       |

### Email (Built-in SMTP)

Email uses SMTP configuration without external providers.

### File & Upload

These services don't require provider configuration (internal printer services).

## Setting Up Provider Configurations

Provider configurations are managed through the **Templater UI** at company and user levels.

### Company-Level Setup (Admins Only)

1. Log in to Templater UI
2. Navigate to **Admin > Company Settings > Providers**
3. Add provider configuration:
   * Select service (e.g., Invoicing)
   * Select provider (e.g., Qonto)
   * Enter credentials
   * Set as default (optional)
   * Save configuration

### User-Level Setup

1. Log in to Templater UI
2. Navigate to **My Account > Provider Overrides**
3. Add override configuration:
   * Select service
   * Select provider
   * Enter credentials
   * Save override

{% hint style="info" %}
**Note:** User overrides only work if the provider is already configured at company level with proper credentials OR if the user provides their own credentials.
{% endhint %}

## Multi-Provider Scenarios

### Scenario 1: Different Providers Per User

**Use Case:** Each sales rep uses their own accounting platform.

**Setup:**

* Company: No default invoicing provider
* Alice: PennyLane configuration
* Bob: Qonto configuration
* Charlie: iPaidThat configuration

**Requests:**

```bash
# Alice's request (uses her PennyLane config)
curl -X POST https://api.docs-dispatcher.io/api/invoicing \
  -H "Authorization: Bearer $ALICE_JWT" \
  -d '{"documentType": "INVOICE", ...}'

# Bob's request (uses his Qonto config)
curl -X POST https://api.docs-dispatcher.io/api/invoicing \
  -H "Authorization: Bearer $BOB_JWT" \
  -d '{"documentType": "INVOICE", ...}'
```

### Scenario 2: Multiple Providers for Same Service

**Use Case:** Company uses different invoicing providers for different regions.

**Setup:**

* Company default: Qonto (France)
* Explicit provider in request for other regions

**Requests:**

```bash
# French invoice (uses Qonto default)
curl -X POST https://api.docs-dispatcher.io/api/invoicing \
  -H "Authorization: Bearer $JWT" \
  -d '{"documentType": "INVOICE", ...}'

# Swiss invoice (explicit SuperPDP)
curl -X POST https://api.docs-dispatcher.io/api/invoicing \
  -H "Authorization: Bearer $JWT" \
  -d '{"providerName": "superpdp", "documentType": "INVOICE", ...}'
```

### Scenario 3: Sandbox vs Production

**Use Case:** Test with sandbox before production dispatch.

**Setup:**

* Company default: Qonto with `useSandbox: true`
* Explicit production provider in request

**Requests:**

```bash
# Test in sandbox (uses company default with sandbox flag)
curl -X POST https://api.docs-dispatcher.io/api/invoicing \
  -H "Authorization: Bearer $JWT" \
  -d '{"documentType": "INVOICE", ...}'

# Production dispatch (explicit provider without sandbox)
curl -X POST https://api.docs-dispatcher.io/api/invoicing \
  -H "Authorization: Bearer $JWT" \
  -d '{
    "providerName": "qonto",
    "documentType": "INVOICE",
    "providerOverride": {
      "useSandbox": false
    },
    ...
  }'
```

## Common Configuration Issues

### Issue 1: "Provider not configured" (400)

**Error:**

```json
{
  "error": "provider_not_configured",
  "message": "No configuration found for service 'invoicing' and provider 'qonto'"
}
```

**Causes:**

* No company default configured
* No user override configured
* Explicit provider has no configuration

**Solution:**

1. Verify provider is configured in Templater UI
2. Check `isActive: true` in configuration
3. Verify JWT token belongs to correct user/company

### Issue 2: "Invalid provider credentials" (502)

**Error:**

```json
{
  "error": "provider_error",
  "message": "Authentication failed with provider 'qonto'"
}
```

**Causes:**

* API key expired or revoked
* Incorrect credentials
* Provider API down

**Solution:**

1. Re-enter credentials in Templater UI
2. Test credentials with provider's API directly
3. Check provider status page

### Issue 3: "Provider not supported for service" (400)

**Error:**

```json
{
  "error": "invalid_provider",
  "message": "Provider 'qonto' is not supported for service 'sms'"
}
```

**Causes:**

* Wrong `providerName` for service
* Typo in provider name (case-sensitive)

**Solution:**

* See [Available Providers](#available-providers) for valid combinations
* Verify provider name spelling

## Best Practices

### 1. Use Company Defaults for Consistency

Set company defaults for services used by all users:

```
✅ Good: Company default Qonto for invoicing
✅ Good: Company default Brevo for SMS
```

### 2. User Overrides for Special Cases

Use user overrides sparingly:

```
✅ Good: Sales rep with personal accounting platform
❌ Bad: Every user has different provider (manage at company level instead)
```

### 3. Explicit Providers for Edge Cases

Use explicit `providerName` for:

* Multi-region dispatches
* A/B testing providers
* One-off provider usage

### 4. Test with Validation Endpoint

Before configuring a new provider, test with validation:

```bash
# Test provider configuration
curl -X POST https://api.docs-dispatcher.io/api/invoicing/validate \
  -H "Authorization: Bearer $JWT" \
  -d '{
    "providerName": "qonto",
    "documentType": "INVOICE",
    "template": {...}
  }'
```

### 5. Secure Credential Storage

Never hardcode credentials in requests:

```javascript
// ❌ Bad - credentials in code
const request = {
  providerName: 'qonto',
  providerOverride: {
    apiKey: 'qonto_live_abc123xyz'  // NEVER do this
  }
};

// ✅ Good - credentials in Templater config
const request = {
  providerName: 'qonto'  // Uses configured credentials
};
```

### 6. Monitor Provider Usage

Track which providers are used for billing and monitoring:

```bash
# Get provider usage stats
curl -X GET https://api.docs-dispatcher.io/api/v1/stats/providers \
  -H "Authorization: Bearer $JWT"
```

## Code Examples

### Example 1: Using Company Default

```bash
# curl
curl -X POST https://api.docs-dispatcher.io/api/invoicing \
  -H "Authorization: Bearer $JWT" \
  -H "Content-Type: application/json" \
  -d '{
    "documentType": "INVOICE",
    "template": {
      "id": 123,
      "data": {...}
    }
  }'
```

```javascript
// Node.js
const response = await fetch('https://api.docs-dispatcher.io/api/invoicing', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${jwtToken}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    documentType: 'INVOICE',
    template: {
      id: 123,
      data: {...}
    }
  })
});
```

```php
// PHP
$client = new \GuzzleHttp\Client();
$response = $client->post('https://api.docs-dispatcher.io/api/invoicing', [
    'headers' => [
        'Authorization' => 'Bearer ' . $jwtToken,
        'Content-Type' => 'application/json'
    ],
    'json' => [
        'documentType' => 'INVOICE',
        'template' => [
            'id' => 123,
            'data' => [...]
        ]
    ]
]);
```

```java
// Java
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.docs-dispatcher.io/api/invoicing"))
    .header("Authorization", "Bearer " + jwtToken)
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString(
        "{\"documentType\":\"INVOICE\",\"template\":{\"id\":123,\"data\":{...}}}"
    ))
    .build();
```

### Example 2: Explicit Provider Override

```bash
# curl
curl -X POST https://api.docs-dispatcher.io/api/invoicing \
  -H "Authorization: Bearer $JWT" \
  -H "Content-Type: application/json" \
  -d '{
    "providerName": "pennylane",
    "documentType": "INVOICE",
    "template": {
      "id": 123,
      "data": {...}
    }
  }'
```

```javascript
// Node.js
const response = await fetch('https://api.docs-dispatcher.io/api/invoicing', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${jwtToken}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    providerName: 'pennylane',  // Explicit override
    documentType: 'INVOICE',
    template: {
      id: 123,
      data: {...}
    }
  })
});
```

```php
// PHP
$response = $client->post('https://api.docs-dispatcher.io/api/invoicing', [
    'headers' => [
        'Authorization' => 'Bearer ' . $jwtToken,
        'Content-Type' => 'application/json'
    ],
    'json' => [
        'providerName' => 'pennylane',  // Explicit override
        'documentType' => 'INVOICE',
        'template' => [
            'id' => 123,
            'data' => [...]
        ]
    ]
]);
```

```java
// Java
String requestBody = String.format(
    "{\"providerName\":\"pennylane\",\"documentType\":\"INVOICE\",\"template\":{\"id\":123,\"data\":{...}}}"
);

HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.docs-dispatcher.io/api/invoicing"))
    .header("Authorization", "Bearer " + jwtToken)
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString(requestBody))
    .build();
```

## Related Documentation

* [Services Overview](/docs-dispatcher/core-concepts/services.md) - Learn about all 7 services
* [Request Model](/docs-dispatcher/core-concepts/request-model.md) - Understand request structure
* [Validation](/docs-dispatcher/core-concepts/validation.md) - Test configurations before dispatch
* [Providers Reference](/docs-dispatcher/providers/providers.md) - Detailed provider docs

## Summary

Key takeaways:

1. **3-tier resolution**: Company Default → User Override → Explicit Request
2. **Explicit wins**: Always use `providerName` in request to override defaults
3. **Configure via UI**: Manage providers in Templater for security
4. **Test with validation**: Use `/validate` endpoint before real dispatch
5. **Monitor usage**: Track provider usage for billing and debugging

Understanding provider configuration is essential for production use. Once configured correctly, Dispatcher automatically routes requests to the right provider with the right credentials.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.docs-dispatcher.io/docs-dispatcher/core-concepts/providers-configurations.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
