> ## Documentation Index
> Fetch the complete documentation index at: https://docs.e-invoice.be/llms.txt
> Use this file to discover all available pages before exploring further.

# Admin API

> Organization and tenant management API for resellers

<Warning>
  The Admin API is only available to resellers with an **organization API key**. This is a privileged API for managing multiple customer tenants. If you're looking for standard invoice operations, see the [regular API documentation](/guides/creating-invoices).
</Warning>

## Overview

The Admin API enables resellers to programmatically manage customer organizations (tenants), provision API credentials, and handle Peppol network registration on behalf of customers.

This is separate from the standard e-invoice.be API and uses different authentication.

### Key Capabilities

* **Tenant Management** - Create and manage customer organizations
* **API Key Provisioning** - Generate and manage API keys for customers
* **Peppol Registration** - Register customers on the Peppol network
* **Credential Rotation** - Update and revoke API keys without customer involvement

## Authentication

The Admin API requires an **organization API key** (also called admin API key), which is different from standard tenant API keys.

```bash theme={null}
curl -X GET "https://api.e-invoice.be/api/admin/tenants" \
     -H "Authorization: Bearer YOUR_ORGANIZATION_API_KEY"
```

<Note>
  Organization API keys are only provided to approved resellers. Contact [support@e-invoice.be](mailto:support@e-invoice.be) to discuss the reseller programme.
</Note>

## Tenant Management

### List All Tenants

Retrieve all customer organizations under your reseller account:

```bash theme={null}
curl -X GET "https://api.e-invoice.be/api/admin/tenants?skip=0&limit=100" \
     -H "Authorization: Bearer YOUR_ORGANIZATION_API_KEY"
```

**Query Parameters:**

* `skip` - Number of records to skip (default: 0)
* `limit` - Maximum records to return (default: 100)

**Response:**

```json theme={null}
{
  "tenants": [
    {
      "id": "ten-9k2m4p7q3w5x8r",
      "name": "customer-company-bvba",
      "description": "Customer Company BVBA",
      "created_at": "2026-04-16T10:00:00.000000Z",
      "updated_at": "2026-04-16T10:00:00.000000Z",
      "is_deleted": false
    }
  ],
  "total": 1
}
```

### Create a Tenant

Create a new customer organization:

```bash theme={null}
curl -X POST "https://api.e-invoice.be/api/admin/tenants" \
     -H "Authorization: Bearer YOUR_ORGANIZATION_API_KEY" \
     -H "Content-Type: application/json" \
     -d '{
       "name": "customer-company-bvba",
       "description": "Customer Company BVBA - Accounting Software Integration",
       "company_number": "0123456789",
       "company_tax_id": "BE0123456789",
       "peppol_ids": ["0208:0123456789"]
     }'
```

**Request Body:**

* `name` (required) - Unique identifier for the tenant (lowercase, no spaces)
* `description` (optional) - Human-readable description
* `company_number` (optional) - Company registration number (e.g., CBE/KBO for Belgium, KvK for Netherlands, RCS for Luxembourg)
* `company_tax_id` (optional) - Tax identification number (e.g., VAT number like BE0123456789)
* `peppol_ids` (recommended) - Array containing the tenant's Peppol ID

**Response (201 Created):**

```json theme={null}
{
  "id": "ten-9k2m4p7q3w5x8r",
  "name": "customer-company-bvba",
  "description": "Customer Company BVBA - Accounting Software Integration",
  "company_number": "0123456789",
  "company_tax_id": "BE0123456789",
  "peppol_ids": ["0208:0123456789"],
  "created_at": "2026-04-16T10:00:00.000000Z",
  "updated_at": "2026-04-16T10:00:00.000000Z",
  "is_deleted": false
}
```

<Warning>
  **You are responsible for determining and setting the correct Peppol ID for each tenant.** Although `peppol_ids` is an array, the platform currently only supports a single Peppol ID per tenant. Setting the Peppol ID at tenant creation is important for proper Peppol registration later.
</Warning>

#### Company Number vs Tax ID

The tenant schema now separates company registration identifiers:

* **`company_number`** - The official company registration number from the national business register:
  * Belgium: CBE/KBO number (e.g., `0123456789`)
  * Netherlands: KvK number (Chamber of Commerce)
  * Luxembourg: RCS number (Registre de Commerce et des Sociétés)
  * Other countries: Equivalent business registration number

* **`company_tax_id`** - The actual VAT or tax identification number:
  * Format includes country prefix (e.g., `BE0123456789`, `NL123456789B01`)
  * Used for tax purposes and invoicing
  * May be different from the company number in some jurisdictions

<Note>
  For Belgian companies, the CBE number (without "BE" prefix) is typically used in the Peppol ID as `0208:<CBE number>`, while the full VAT number (with "BE" prefix) goes in `company_tax_id`.
</Note>

#### Peppol ID Format

The Peppol ID follows the format `scheme:identifier`:

**Belgium (most common):**

```
Format: 0208:<CBE number>
Example: 0208:0123456789
```

For Belgian companies, use scheme `0208` with the CBE/KBO number (enterprise number).

Example relationship:

* `company_number`: `0123456789` (CBE number)
* `company_tax_id`: `BE0123456789` (VAT number)
* `peppol_ids`: `["0208:0123456789"]` (scheme 0208 + CBE number)

**Other schemes:**

* `9999` - DUNS number (international)
* `0088` - Global Location Number (GLN)
* `0184` - Dutch KVK number
* `9956` - Belgian company number (alternative)

#### Why Set Peppol ID During Creation?

The Peppol ID is used when:

1. **Registering on the SMP** (Service Metadata Publisher) - Maps the Peppol ID to e-invoice.be's access point
2. **Writing to the Peppol Directory** - Creates a searchable entry for participant lookup
3. **Routing documents** - Ensures incoming invoices reach the correct tenant

<Note>
  Every tenant must have exactly one associated Peppol ID. Setting it during tenant creation ensures the tenant is properly configured before Peppol registration.
</Note>

<Tip>
  Use a consistent naming convention for tenant names, such as `customer-slug` or `company-id`. This makes it easier to manage multiple customers.
</Tip>

### Get a Tenant

Retrieve details for a specific tenant:

```bash theme={null}
curl -X GET "https://api.e-invoice.be/api/admin/tenants/ten-9k2m4p7q3w5x8r" \
     -H "Authorization: Bearer YOUR_ORGANIZATION_API_KEY"
```

### Update a Tenant

Update tenant information:

```bash theme={null}
curl -X PUT "https://api.e-invoice.be/api/admin/tenants/ten-9k2m4p7q3w5x8r" \
     -H "Authorization: Bearer YOUR_ORGANIZATION_API_KEY" \
     -H "Content-Type: application/json" \
     -d '{
       "name": "customer-company-bvba",
       "description": "Updated description",
       "company_number": "0123456789",
       "company_tax_id": "BE0123456789",
       "peppol_ids": ["0208:0123456789"]
     }'
```

<Note>
  You can update the `company_number`, `company_tax_id`, and `peppol_ids` fields after tenant creation if needed.
</Note>

### Delete a Tenant

Soft-delete a tenant (marks as deleted, doesn't remove data):

```bash theme={null}
curl -X DELETE "https://api.e-invoice.be/api/admin/tenants/ten-9k2m4p7q3w5x8r" \
     -H "Authorization: Bearer YOUR_ORGANIZATION_API_KEY"
```

## API Key Management

Provision and manage API keys for customer tenants.

### Create an API Key

Generate a new API key for a tenant:

```bash theme={null}
curl -X POST "https://api.e-invoice.be/api/admin/tenants/ten-9k2m4p7q3w5x8r/api-keys" \
     -H "Authorization: Bearer YOUR_ORGANIZATION_API_KEY" \
     -H "Content-Type: application/json" \
     -d '{
       "name": "production-key",
       "description": "Production API key for Customer Company"
     }'
```

**Request Body:**

* `name` (required) - Identifier for the API key
* `description` (optional) - Purpose or environment

**Response:**

```json theme={null}
{
  "id": "api-3h8f5j2k9l4m7n6p1q5r8s2t4v6w9x3y",
  "tenant_id": "ten-9k2m4p7q3w5x8r",
  "name": "production-key",
  "description": "Production API key for Customer Company",
  "created_at": "2026-04-16T10:00:00.000000Z",
  "updated_at": "2026-04-16T10:00:00.000000Z",
  "is_deleted": false
}
```

<Warning>
  **The `id` field IS the API key.** There is no separate `key` field — the value returned in `id` (e.g. `api-3h8f5j2k9l4m7n6p1q5r8s2t4v6w9x3y`) is the bearer token your customer must include in the `Authorization` header of every API request:

  ```
  Authorization: Bearer api-3h8f5j2k9l4m7n6p1q5r8s2t4v6w9x3y
  ```

  Treat the `id` as a secret. Capture it on creation, store it securely (e.g. encrypted at rest), and deliver it to your customer over a secure channel. Never log it, commit it to version control, or expose it in client-side code.
</Warning>

### List API Keys

Get all API keys for a tenant:

```bash theme={null}
curl -X GET "https://api.e-invoice.be/api/admin/tenants/ten-9k2m4p7q3w5x8r/api-keys?limit=100" \
     -H "Authorization: Bearer YOUR_ORGANIZATION_API_KEY"
```

**Response:**

```json theme={null}
{
  "api_keys": [
    {
      "id": "api-3h8f5j2k9l4m7n6p1q5r8s2t4v6w9x3y",
      "tenant_id": "ten-9k2m4p7q3w5x8r",
      "name": "production-key",
      "description": "Production API key",
      "created_at": "2026-04-16T10:00:00.000000Z",
      "updated_at": "2026-04-16T10:00:00.000000Z",
      "is_deleted": false
    }
  ],
  "total": 1
}
```

<Warning>
  Because the `id` is itself the bearer token, listing API keys returns the live credentials for this tenant. Treat the response as sensitive credential material: restrict who can call this endpoint, avoid logging the response body, and never return it to end users.
</Warning>

### Get Latest API Key

Retrieve the most recently created API key for a tenant:

```bash theme={null}
curl -X GET "https://api.e-invoice.be/api/admin/tenants/ten-9k2m4p7q3w5x8r/api-keys/latest" \
     -H "Authorization: Bearer YOUR_ORGANIZATION_API_KEY"
```

### Update an API Key

Update API key metadata (name/description):

```bash theme={null}
curl -X PUT "https://api.e-invoice.be/api/admin/tenants/ten-9k2m4p7q3w5x8r/api-keys/api-3h8f5j2k9l4m7n6p1q5r8s2t4v6w9x3y" \
     -H "Authorization: Bearer YOUR_ORGANIZATION_API_KEY" \
     -H "Content-Type: application/json" \
     -d '{
       "name": "production-key-v2",
       "description": "Updated production key"
     }'
```

### Revoke an API Key

Delete (revoke) an API key:

```bash theme={null}
curl -X DELETE "https://api.e-invoice.be/api/admin/tenants/ten-9k2m4p7q3w5x8r/api-keys/api-3h8f5j2k9l4m7n6p1q5r8s2t4v6w9x3y" \
     -H "Authorization: Bearer YOUR_ORGANIZATION_API_KEY"
```

<Tip>
  For credential rotation, create a new API key, update your customer's configuration, then revoke the old key.
</Tip>

## Peppol Registration

Manage Peppol network registration for customer tenants.

### Check Registration Status

Check if a tenant is registered on Peppol:

```bash theme={null}
curl -X GET "https://api.e-invoice.be/api/admin/tenants/ten-9k2m4p7q3w5x8r/peppol/" \
     -H "Authorization: Bearer YOUR_ORGANIZATION_API_KEY"
```

**Response:**

```json theme={null}
{
  "peppol_id": "0208:0123456789",
  "state": "e-invoice",
  "smp": {
    "service_group": {
      "participant_identifier": "0123456789",
      "participant_scheme": "0208",
      "service_metadata_references": []
    },
    "business_card": {
      "participant_identifier": "0123456789",
      "participant_scheme": "0208",
      "business_entity": { "name": "Your Company BV", "country_code": "BE" }
    },
    "document_types": [
      {
        "document_type_code": "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice",
        "process_identifier": "urn:fdc:peppol.eu:2017:poacc:billing:01:1.0"
      }
    ]
  },
  "last_checked_at": "2026-04-16T10:00:00.000000Z"
}
```

<Note>
  `state` reflects the SMP registration status: `not_registered`, `e-invoice` (registered on our SMP), or `other`. `smp` is a structured object describing the SMP service group, business card, and supported document types (`null` when not registered).
</Note>

### Register on Peppol

Register a tenant on the Peppol network:

```bash theme={null}
curl -X POST "https://api.e-invoice.be/api/admin/tenants/ten-9k2m4p7q3w5x8r/peppol/register" \
     -H "Authorization: Bearer YOUR_ORGANIZATION_API_KEY" \
     -H "Content-Type: application/json" \
     -d '{
       "peppol_id": "0208:0123456789",
       "company_name": "Customer Company BVBA"
     }'
```

**For Belgian companies**, the system can automatically fetch company data from KBO (Crossroads Bank for Enterprises):

```bash theme={null}
curl -X POST "https://api.e-invoice.be/api/admin/tenants/ten-9k2m4p7q3w5x8r/peppol/register" \
     -H "Authorization: Bearer YOUR_ORGANIZATION_API_KEY" \
     -H "Content-Type: application/json" \
     -d '{
       "peppol_id": "0208:0123456789"
     }'
```

The system will:

1. Fetch company details from KBO using the CBE number
2. Register with the SMP (Service Metadata Publisher)
3. Create a business card on the Peppol network

<Warning>
  Peppol operations are not available for organizations in test mode. Calling the Peppol endpoints for a test-mode organization returns `403 Forbidden`. Ensure your organization is in production mode before attempting registration.
</Warning>

### Update Business Card

Update the business card information on Peppol:

```bash theme={null}
curl -X PUT "https://api.e-invoice.be/api/admin/tenants/ten-9k2m4p7q3w5x8r/peppol/business-card" \
     -H "Authorization: Bearer YOUR_ORGANIZATION_API_KEY" \
     -H "Content-Type: application/json" \
     -d '{
       "company_name": "Updated Company Name BVBA"
     }'
```

<Note>
  Currently, only company name updates are supported for business cards.
</Note>

### Unregister from Peppol

Remove a tenant from the Peppol network:

```bash theme={null}
curl -X DELETE "https://api.e-invoice.be/api/admin/tenants/ten-9k2m4p7q3w5x8r/peppol/unregister" \
     -H "Authorization: Bearer YOUR_ORGANIZATION_API_KEY"
```

This will:

* Remove SMP registration
* Delete the business card
* Mark the tenant as unregistered

## Testing

### Simulate an Inbound Document

Inject a UBL document into a tenant's inbox as if it had been received over Peppol. This is the supported way to test a customer's receive-side integration: the document is created in the `RECEIVED` state, appears in `GET /api/inbox/`, and any `document.received` webhooks configured on the tenant fire normally.

<Warning>
  Simulation is only available for **test-mode tenants**. Calling this on a tenant that is not in test mode returns `400 Bad Request`.
</Warning>

The request is `multipart/form-data` with the UBL XML supplied as a `ubl_file` field (**not** a raw XML request body). The receiver identifiers in the UBL should match the tenant you are simulating for.

```bash theme={null}
curl -X POST "https://api.e-invoice.be/api/admin/tenants/ten-9k2m4p7q3w5x8r/simulate-inbound" \
     -H "Authorization: Bearer YOUR_ORGANIZATION_API_KEY" \
     -F "ubl_file=@invoice.xml"
```

**Form fields:**

* `ubl_file` - The UBL Invoice or Credit Note XML file (required, max 25 MB)

**Response** (`201 Created`):

```json theme={null}
{
  "document_id": "doc-7h3k9m2p4q6r8t",
  "state": "RECEIVED"
}
```

The sender and receiver Peppol identifiers, document type (invoice vs. credit note), and line-item details are extracted from the uploaded UBL. Use the returned `document_id` with the standard document endpoints (for example `GET /api/documents/{document_id}`) to inspect the result.

<Note>
  This endpoint powers the **Simulate inbound** button shown in a test workspace's inbox in the e-invoice.be app. See [Testing Received Documents](/environments#testing-received-documents) for the app-based workflow.
</Note>

## Complete Workflow Example

Here's a complete Node.js example showing the typical reseller workflow:

```javascript theme={null}
const axios = require('axios');

const adminApi = axios.create({
  baseURL: 'https://api.e-invoice.be',
  headers: {
    'Authorization': `Bearer ${process.env.ORGANIZATION_API_KEY}`,
    'Content-Type': 'application/json'
  }
});

async function onboardNewCustomer(customerData) {
  try {
    // 1. Create tenant with company details and Peppol ID
    console.log('Creating tenant...');
    const tenant = await adminApi.post('/api/admin/tenants', {
      name: customerData.slug,
      description: customerData.companyName,
      company_number: customerData.companyNumber,
      company_tax_id: customerData.vatNumber,
      peppol_ids: [customerData.peppolId]
    });
    console.log('✓ Tenant created:', tenant.data.id);
    console.log('✓ Company number:', customerData.companyNumber);
    console.log('✓ Tax ID:', customerData.vatNumber);
    console.log('✓ Peppol ID set:', customerData.peppolId);

    // 2. Create API key for customer
    console.log('Generating API key...');
    const apiKey = await adminApi.post(
      `/api/admin/tenants/${tenant.data.id}/api-keys`,
      {
        name: 'production-key',
        description: 'Production API key'
      }
    );
    // IMPORTANT: The id IS the bearer token — capture it now and store it securely.
    // There is no separate `key` field, and you cannot retrieve the value again later.
    const customerApiKey = apiKey.data.id;
    console.log('✓ API key created (id IS the bearer token):', customerApiKey);

    // 3. Register on Peppol (for Belgian companies)
    console.log('Registering on Peppol...');
    const registration = await adminApi.post(
      `/api/admin/tenants/${tenant.data.id}/peppol/register`,
      {
        peppol_id: customerData.peppolId
      }
    );
    console.log('✓ Peppol registration complete');

    // 4. Return customer credentials
    return {
      tenantId: tenant.data.id,
      apiKey: customerApiKey,
      peppolId: customerData.peppolId,
      status: 'active'
    };

  } catch (error) {
    console.error('Onboarding failed:', error.response?.data || error.message);
    throw error;
  }
}

// Usage
const customerData = {
  slug: 'customer-company-bvba',
  companyName: 'Customer Company BVBA',
  companyNumber: '0123456789',  // CBE/KBO number
  vatNumber: 'BE0123456789',     // Full VAT number
  peppolId: '0208:0123456789'    // Peppol ID (scheme 0208 + CBE number)
};

onboardNewCustomer(customerData)
  .then(credentials => {
    console.log('Customer onboarded successfully:');
    console.log('- Tenant ID:', credentials.tenantId);
    console.log('- API Key:', credentials.apiKey);
    console.log('- Peppol ID:', credentials.peppolId);
  });
```

## Key Rotation Example

Rotate API keys without customer downtime:

```javascript theme={null}
async function rotateApiKey(tenantId, oldKeyId) {
  try {
    // 1. Create new API key
    console.log('Creating new API key...');
    const newKey = await adminApi.post(
      `/api/admin/tenants/${tenantId}/api-keys`,
      {
        name: 'production-key-v2',
        description: 'Rotated production key'
      }
    );
    // The id IS the bearer token — capture it now; it cannot be retrieved later.
    const newApiKey = newKey.data.id;
    console.log('✓ New key created:', newApiKey);

    // 2. Provide new key to customer
    // (Send via secure channel, update their configuration)

    // 3. Wait for customer to switch over
    console.log('Waiting for customer to update configuration...');
    await new Promise(resolve => setTimeout(resolve, 3600000)); // 1 hour

    // 4. Revoke old key
    console.log('Revoking old API key...');
    await adminApi.delete(
      `/api/admin/tenants/${tenantId}/api-keys/${oldKeyId}`
    );
    console.log('✓ Old key revoked');

    return newKey.data;

  } catch (error) {
    console.error('Key rotation failed:', error.response?.data || error.message);
    throw error;
  }
}
```

## Error Handling

Common error responses:

### 401 Unauthorized

```json theme={null}
{
  "detail": "Invalid authentication credentials"
}
```

**Solution**: Verify your organization API key is correct and active.

### 404 Not Found

```json theme={null}
{
  "detail": "Tenant not found"
}
```

**Solution**: Check the tenant ID is correct and the tenant exists.

### 409 Conflict

```json theme={null}
{
  "detail": "A tenant with similar name already exists"
}
```

**Solution**: Choose a different tenant name.

### 422 Validation Error

```json theme={null}
{
  "detail": [
    {
      "loc": ["body", "name"],
      "msg": "field required",
      "type": "value_error.missing"
    }
  ]
}
```

**Solution**: Ensure all required fields are provided.

## Best Practices

<AccordionGroup>
  <Accordion title="Secure Key Management">
    * Remember: the `id` returned from the create-key endpoint IS the bearer token. Treat it as a secret from the moment you receive it.
    * Never log or display organization API keys
    * Store customer API keys securely (encrypted database)
    * Provide keys to customers via secure channels only
    * Implement key rotation policies (e.g., every 90 days)

    ```javascript theme={null}
    // ✓ Good: Secure handling — the id IS the bearer token
    const encryptedKey = encrypt(apiKey.data.id);
    await database.storeCustomerKey(customerId, encryptedKey);

    // ✗ Bad: Insecure handling
    console.log('API Key:', apiKey.data.id);
    localStorage.setItem('key', apiKey.data.id);
    ```
  </Accordion>

  <Accordion title="Tenant Naming Convention">
    Use consistent, predictable tenant names:

    ```javascript theme={null}
    // ✓ Good patterns
    const tenantName = 'customer-company-bvba';
    const tenantName = `cust-${customerId}`;
    const tenantName = companyName.toLowerCase().replace(/\s+/g, '-');

    // ✗ Bad patterns
    const tenantName = 'Customer 1';
    const tenantName = Math.random().toString();
    ```
  </Accordion>

  <Accordion title="Error Recovery">
    Implement idempotent operations and error recovery:

    ```javascript theme={null}
    async function createTenantSafely(name, description) {
      try {
        return await adminApi.post('/api/admin/tenants', { name, description });
      } catch (error) {
        if (error.response?.status === 409) {
          // Tenant already exists, fetch it instead
          console.log('Tenant exists, fetching...');
          const tenants = await adminApi.get('/api/admin/tenants');
          return tenants.data.tenants.find(t => t.name === name);
        }
        throw error;
      }
    }
    ```
  </Accordion>

  <Accordion title="Audit Logging">
    Log all admin operations for compliance:

    ```javascript theme={null}
    async function auditedTenantCreate(tenantData) {
      const result = await adminApi.post('/api/admin/tenants', tenantData);

      await auditLog.create({
        action: 'TENANT_CREATE',
        tenant_id: result.data.id,
        admin_user: currentUser.id,
        timestamp: new Date(),
        details: { name: tenantData.name }
      });

      return result.data;
    }
    ```
  </Accordion>

  <Accordion title="Peppol Registration Checks">
    Always verify registration prerequisites:

    ```javascript theme={null}
    async function registerOnPeppol(tenantId, peppolId) {
      // 1. Verify Peppol ID format
      if (!/^\d{4}:\d+$/.test(peppolId)) {
        throw new Error('Invalid Peppol ID format');
      }

      // 2. Register. Peppol operations are gated at the organization
      // level: a test-mode organization gets 403 Forbidden here.
      return await adminApi.post(
        `/api/admin/tenants/${tenantId}/peppol/register`,
        { peppol_id: peppolId }
      );
    }
    ```
  </Accordion>
</AccordionGroup>

## Environment

The Admin API is available on the single API host:

| Base URL                   |
| -------------------------- |
| `https://api.e-invoice.be` |

<Note>
  To test your integration before going live, create tenants in **test mode** (the API's test Organization) and use their API keys. Test-mode tenants divert sends to email, support [Simulate an Inbound Document](#simulate-an-inbound-document), and never touch the Peppol network. See [Environments](/environments) for details.
</Note>

## Rate Limiting

Rate limits are applied **per API key** on write and validation endpoints (see [API reference — Rate Limiting](/api-reference#rate-limiting)). When a limit is exceeded, the API returns `429 Too Many Requests` with a `Retry-After` header. Honor `Retry-After` and use exponential backoff when driving bulk tenant operations.

## Support

For Admin API access or technical questions:

* Email: [support@e-invoice.be](mailto:support@e-invoice.be)
* Reseller programme: [Learn more](/reseller-programme)

## Related Documentation

* [Reseller Programme](/reseller-programme)
* [Authentication](/authentication)
* [Creating Invoices](/guides/creating-invoices)
* [API Reference](/api-reference)
