> ## Documentation Index
> Fetch the complete documentation index at: https://apidocs.royalti.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Merlin Addon Guide

> Automate royalty data import from FTP servers with intelligent file discovery and approval workflows

## Overview

The Merlin addon enables automated discovery, download, and processing of royalty data files from FTP servers. It provides intelligent file recognition, duplicate detection, and a comprehensive approval workflow with confidence scoring.

## Key Features

* **Encrypted credential storage** using PostgreSQL pgcrypto with AES-256
* **Scheduled and manual imports** with configurable cron patterns, timezone support, and blackout windows
* **Intelligent file discovery** with DSP folder mapping and filename pattern recognition
* **Duplicate detection** via path and content hash to prevent re-importing files
* **Confidence-based auto-approval** for high-confidence matches with detailed scoring breakdown
* **Multi-step approval workflow** with single, grouped, and bulk operations
* **File preview capability** to review contents before approval
* **AI-powered recommendations** based on historical patterns and success rates
* **Complete audit trail** with event notifications and metrics tracking
* **Advanced analytics** with success rates, processing times, and trend analysis

## Prerequisites

> [!NOTE]
>
> The Merlin addon requires an active subscription with addon access enabled. Contact support to enable the addon for your workspace.

### Environment Variables

Set the following environment variables for encryption:

```bash theme={null}
# Primary encryption key (required, minimum 64 characters for production)
MERLIN_CREDENTIAL_ENCRYPTION_KEY=your-64-character-secure-random-key-here

# Optional: Enable key derivation for enhanced security
MERLIN_KDF_ENABLED=true
MERLIN_KDF_SALT=your-unique-salt-value-here

# Optional: Specify default import schedule (cron format)
MERLIN_DEFAULT_IMPORT_SCHEDULE="0 6 * * *"
```

> [!WARNING]
>
> Never commit encryption keys to version control. Use environment secrets or a secure key management service like Google Cloud Secret Manager.

## Quick Start

### Step 1: Configure FTP Credentials

```javascript Node.js theme={null}
const response = await fetch('https://api.royalti.io/merlin/config', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    credentials: {
      host: 'ftp.merlin.com',
      port: 21,
      username: 'your-username',
      password: 'your-password',
      secure: true,
      passiveMode: true,
      timeout: 30000
    },
    features: {
      royaltyImport: true
    }
  })
});

const result = await response.json();
console.log('Configuration saved:', result.data.id);
```

> [!NOTE]
>
> Credentials are automatically encrypted using PostgreSQL pgcrypto before storage. Plaintext credentials are never stored in the database.

### Step 2: Test Connection

```javascript Node.js theme={null}
const response = await fetch('https://api.royalti.io/merlin/test-connection', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${token}`
  }
});

const result = await response.json();
console.log('Available periods:', result.data.availablePeriods);
// Output: ['202401', '202402', '202403']
console.log('DSP folders:', result.data.dspFolders);
// Output: ['DistroKid', 'CD Baby', 'TuneCore']
```

### Step 3: Configure Import Settings

```javascript Node.js theme={null}
const response = await fetch('https://api.royalti.io/merlin/import/config', {
  method: 'PUT',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    autoImportEnabled: true,
    importSchedule: '0 6 * * *',  // Daily at 6 AM UTC
    importPath: '/royalties',
    royaltySourceId: 123,
    autoApproveHighConfidence: false,
    confidenceThreshold: 0.75,
    scheduleType: 'daily',
    scheduleTime: '06:00',
    timezone: 'America/New_York'
  })
});

const result = await response.json();
console.log('Import config updated:', result.data);
```

### Step 4: Trigger First Import

```javascript Node.js theme={null}
const response = await fetch('https://api.royalti.io/merlin/import/trigger', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    period: '202401',
    dspFolder: 'DistroKid'  // Optional: limit to specific DSP
  })
});

const result = await response.json();
console.log('Import batch started:', result.data.id);
console.log('Status:', result.data.status);
// Status progression: discovering → downloading → completed
```

## Understanding Confidence Scoring

The Merlin addon uses a sophisticated 7-factor confidence scoring algorithm to determine file authenticity and correct period detection. Each factor contributes to an overall score from 0.0 (no confidence) to 1.0 (complete confidence).

### Scoring Factors

> [!NOTE]
>
> Confidence scores are calculated when files are discovered and updated throughout the import process as more data becomes available.

| Factor | Weight | Description | Scoring Logic |
| - | - | - | - |
| **File Naming** | 15% | Pattern matching against known DSP naming conventions | Matches patterns like `DistroKid-202401.csv`, `CD_Baby_202401.xlsx` |
| **File Size** | 15% | Typical file size ranges for DSP data | 50KB-500MB range scores high; outliers score lower |
| **DSP Folder** | 15% | File located in expected DSP folder path | Direct matches (e.g., `/royalties/DistroKid/`) score highest |
| **Header Format** | 15% | CSV/Excel headers match expected columns | Presence of standard columns (ISRC, UPC, Streams, Revenue) |
| **Period Detection** | 20% | Date/period information in filename or headers | YYYYMM format (202401) or date columns in headers |
| **Source Detection** | 10% | Fingerprinting based on file structure and content patterns | Unique patterns learned from first uploads |
| **Historical Success** | 10% | Based on past successful imports from this source | Files from previously successful periods score higher |

### Interpretation Guide

**1. Low Confidence (0.0 - 0.3)**

* File doesn't match expected patterns
* Ambiguous period detection
* Unusual file structure
* **Action**: Requires manual review and explicit confirmation

**2. Medium Confidence (0.3 - 0.75)**

* Some factors align with expectations
* Period detection is clear but source less certain, or vice versa
* **Action**: Shows in approval queue, user should preview before approving

**3. High Confidence (0.75 - 0.9)**

* Most factors align with known patterns
* Clear period and source detection
* Matches historical successful patterns
* **Action**: Can be approved with confidence, suitable for auto-approval policies

**4. Very High Confidence (0.9 - 1.0)**

* Nearly all factors align perfectly
* Exact match to known patterns
* Multiple confirming factors
* **Action**: Excellent candidate for automatic approval

### Viewing Detailed Scores

```javascript Node.js theme={null}
const response = await fetch('https://api.royalti.io/merlin/pending/12345', {
  headers: {
    'Authorization': `Bearer ${token}`
  }
});

const { data: pendingImport } = await response.json();
console.log('Overall confidence:', pendingImport.confidenceScore);  // 0.87

console.log('Factor breakdown:', pendingImport.confidenceBreakdown);
// Output:
// {
//   fileNaming: 0.9,
//   fileSize: 0.85,
//   dspFolder: 0.95,
//   headerFormat: 0.8,
//   periodDetection: 0.92,
//   sourceDetection: 0.75,
//   historicalSuccess: 0.88
// }
```

## Advanced Approval Patterns

The Merlin addon supports three distinct approval workflows for different use cases. Choose the pattern that best fits your operational process.

### Pattern 1: Single File Approval

Best for careful, deliberate reviews with full control over each file.

```javascript Node.js theme={null}
// First, preview the file
const previewResponse = await fetch(
  'https://api.royalti.io/merlin/pending/file-id-123/preview',
  {
    headers: { 'Authorization': `Bearer ${token}` }
  }
);
const preview = await previewResponse.json();
console.log('Columns:', preview.data.headers);
console.log('Sample rows:', preview.data.sampleRows);
console.log('Warnings:', preview.data.warnings);

// Then approve with confirmed period
const approveResponse = await fetch(
  'https://api.royalti.io/merlin/pending/file-id-123/approve',
  {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${token}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      accountingPeriod: '2024-01'  // Must be YYYY-MM format
    })
  }
);

const approved = await approveResponse.json();
console.log('File approved:', approved.data.confirmedAccountingPeriod);
```

**When to use**: High-value files, unfamiliar sources, policy/regulatory compliance reviews, training/onboarding scenarios.

### Pattern 2: Grouped Approval by DSP + Period

Best for batch processing when you trust the source and period.

```javascript Node.js theme={null}
// Get files grouped by DSP and period
const groupedResponse = await fetch(
  'https://api.royalti.io/merlin/pending/grouped?groupBy=dsp_period',
  {
    headers: { 'Authorization': `Bearer ${token}` }
  }
);
const groups = await groupedResponse.json();

// Find and review a group
const distrokidGroup = groups.data.find(g => g.groupKey === 'DistroKid_202401');
console.log('Files in group:', distrokidGroup.count);
console.log('Average confidence:', distrokidGroup.averageConfidence);
console.log('All ready?', distrokidGroup.allApprovalReady);

// Approve entire group at once
const bulkResponse = await fetch('https://api.royalti.io/merlin/pending/bulk-approve', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    dsp: 'DistroKid',
    period: '202401',
    accountingPeriod: '2024-01'
  })
});

const result = await bulkResponse.json();
console.log(`Approved ${result.data.approved} files`);
```

**When to use**: Regular DSP uploads, established revenue sources, high-volume import scenarios, end-of-month batch processing.

### Pattern 3: Bulk Approval by Period Only

Best for multi-DSP months or rapid processing.

```javascript Node.js theme={null}
// Get grouped files by period only
const groupedResponse = await fetch(
  'https://api.royalti.io/merlin/pending/grouped?groupBy=period',
  {
    headers: { 'Authorization': `Bearer ${token}` }
  }
);
const periodGroups = await groupedResponse.json();

// Review the period group
const period202401 = periodGroups.data.find(g => g.groupKey === '202401');
console.log('Total files for January:', period202401.count);
console.log('Average confidence:', period202401.averageConfidence);

// Approve all files for the period
const bulkResponse = await fetch('https://api.royalti.io/merlin/pending/bulk-approve', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    period: '202401',
    accountingPeriod: '2024-01'
  })
});

const result = await bulkResponse.json();
console.log(`Approved ${result.data.approved} files for period`);
```

**When to use**: Month-end closing procedures, all sources received for a period, rapid deployment environments.

### Decision Tree

```
┌─ Is this a new/unknown source?
│  └─ YES → Use Pattern 1 (Single approval with preview)
│
├─ Do you have multiple DSPs for this period?
│  └─ NO → Use Pattern 2 (Group by DSP+period)
│  └─ YES → Use Pattern 3 (Bulk by period)
│
└─ What's your confidence level?
   └─ HIGH (>0.85) → Consider auto-approval
   └─ MEDIUM (0.6-0.85) → Use Pattern 2 or 3
   └─ LOW (<0.6) → Use Pattern 1
```

## File Preview Before Approval

Preview file contents to validate structure and detect issues before committing to import.

```javascript Node.js theme={null}
const response = await fetch(
  'https://api.royalti.io/merlin/pending/file-id-xyz/preview',
  {
    headers: { 'Authorization': `Bearer ${token}` }
  }
);

const { data } = await response.json();

console.log('Column Headers:', data.headers);
// ['ISRC', 'UPC', 'Product_Title', 'Streams', 'Revenue', 'Currency']

console.log('Sample Data:');
data.sampleRows.forEach((row, idx) => {
  console.log(`Row ${idx}:`, row);
});
// Row 0: ['USRC1234567', '9780123456789', 'Sample Song', '1000', '45.50', 'USD']
// Row 1: ['USRC7654321', '9780987654321', 'Another Song', '2500', '112.75', 'USD']

console.log('File Info:', {
  totalRows: data.rowCount,
  fileSize: data.fileSize,
  warnings: data.warnings
});
// {
//   totalRows: 15420,
//   fileSize: '2.3 MB',
//   warnings: [
//     'Missing ISRC in row 5',
//     'Invalid currency code in row 12'
//   ]
// }
```

**What to look for in preview**:

* Are all expected columns present?
* Do data values look reasonable?
* Are there data quality warnings?
* Does the sample data match the expected format for this DSP?

## Auto-Approval & Recommendations

Streamline approval workflows with intelligent recommendations and automatic approval for high-confidence files.

### Get Auto-Approval Candidates

```javascript Node.js theme={null}
const response = await fetch(
  'https://api.royalti.io/merlin/pending/auto-approvable',
  {
    headers: { 'Authorization': `Bearer ${token}` }
  }
);

const { data: autoApprovable } = await response.json();

console.log(`${autoApprovable.count} files ready for auto-approval`);

// Review before auto-approving
autoApprovable.forEach(file => {
  console.log(`${file.fileName}: confidence ${file.confidenceScore}`);
});
```

### Get AI-Powered Recommendations

```javascript Node.js theme={null}
const response = await fetch(
  'https://api.royalti.io/merlin/pending/recommendations?limit=10',
  {
    headers: { 'Authorization': `Bearer ${token}` }
  }
);

const { data: recommendations } = await response.json();

recommendations.forEach(rec => {
  console.log(`${rec.filePath}`);
  console.log(`  Recommendation: ${rec.recommendation.toUpperCase()}`);
  console.log(`  Confidence: ${rec.confidenceScore}`);
  console.log(`  Reason: ${rec.reason}`);
  console.log(`  Suggested Period: ${rec.suggestedAccountingPeriod}`);
});

// Output:
// /royalties/202401/DistroKid-202401.csv
//   Recommendation: APPROVE
//   Confidence: 0.94
//   Reason: Matches 18 of 18 historical pattern factors
//   Suggested Period: 2024-01
//
// /royalties/202401/Unknown-20240101.xlsx
//   Recommendation: REVIEW
//   Confidence: 0.62
//   Reason: Unfamiliar file format and naming pattern
//   Suggested Period: 2024-01
```

### Enable Auto-Approval for High Confidence Files

```javascript Node.js theme={null}
// Configure auto-approval threshold
const response = await fetch('https://api.royalti.io/merlin/import/config', {
  method: 'PUT',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    autoApproveHighConfidence: true,
    confidenceThreshold: 0.85  // Only auto-approve >= 85% confidence
  })
});
```

> [!WARNING]
>
> Auto-approval bypasses manual review. Only enable for established sources with consistently high confidence scores. Monitor auto-approved files in your import history to catch any issues quickly.

## Advanced Filtering & Search

Find and filter pending imports with sophisticated query capabilities.

### Filter by Multiple Criteria

```javascript Node.js theme={null}
// Get pending imports with filters
const params = new URLSearchParams({
  status: 'discovered',
  minConfidence: '0.75',
  dsp: 'DistroKid',
  period: '202401',
  offset: '0',
  limit: '100'
});

const response = await fetch(`https://api.royalti.io/merlin/pending?${params}`, {
  headers: { 'Authorization': `Bearer ${token}` }
});

const { data, total } = await response.json();
console.log(`Found ${total} files matching criteria`);
```

### Available Filters

| Parameter | Type | Example | Notes |
| - | - | - | - |
| `status` | enum | `discovered`, `approved`, `rejected` | Current approval status |
| `minConfidence` | float | `0.75` | Minimum confidence score (0-1) |
| `dsp` | string | `DistroKid` | Filter by DSP/source name |
| `period` | string | `202401` | Filter by period (YYYYMM format) |
| `offset` | integer | `0` | Pagination offset |
| `limit` | integer | `50` | Results per page (max 500) |

### Advanced Grouping for Batch Operations

```javascript Node.js theme={null}
// Get files eligible for group approval
const response = await fetch(
  'https://api.royalti.io/merlin/pending/groupable',
  {
    headers: { 'Authorization': `Bearer ${token}` }
  }
);

const { data: groupable } = await response.json();

groupable.forEach(group => {
  console.log(`
    Group: ${group.groupKey}
    Files: ${group.count}
    Avg Confidence: ${(group.averageConfidence * 100).toFixed(1)}%
    All Ready: ${group.allApprovalReady ? 'YES' : 'NO'}
  `);
});
```

## Enhanced Scheduled Imports

Configure sophisticated import schedules with timezone support and blackout windows.

### Simple Daily Schedule

```javascript Node.js theme={null}
const response = await fetch('https://api.royalti.io/merlin/import/config', {
  method: 'PUT',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    scheduleType: 'daily',
    scheduleTime: '06:00',
    timezone: 'America/New_York'
  })
});
```

### Weekly Schedule

```javascript Node.js theme={null}
const response = await fetch('https://api.royalti.io/merlin/import/config', {
  method: 'PUT',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    scheduleType: 'weekly',
    scheduleTime: '09:00',
    timezone: 'America/New_York',
    dayOfWeek: 2  // Tuesday (0=Sunday, 6=Saturday)
  })
});
```

### Monthly Schedule

```javascript Node.js theme={null}
const response = await fetch('https://api.royalti.io/merlin/import/config', {
  method: 'PUT',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    scheduleType: 'monthly',
    scheduleTime: '08:00',
    timezone: 'America/New_York',
    dayOfMonth: 5  // 5th of each month
  })
});
```

### Custom Cron Expression

```javascript Node.js theme={null}
const response = await fetch('https://api.royalti.io/merlin/import/config', {
  method: 'PUT',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    scheduleType: 'custom',
    importSchedule: '0 6 * * 1-5'  // Weekdays at 6 AM
  })
});
```

### Blackout Windows

Prevent imports during certain periods (maintenance, cutoff times, etc.):

```javascript Node.js theme={null}
const response = await fetch('https://api.royalti.io/merlin/import/config', {
  method: 'PUT',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    scheduleType: 'daily',
    scheduleTime: '06:00',
    timezone: 'America/New_York',
    blackoutWindows: [
      {
        startTime: '23:00',
        endTime: '01:00'  // Don't import between 11 PM - 1 AM
      },
      {
        startTime: '12:00',
        endTime: '13:00'  // Don't import during lunch hour
      }
    ]
  })
});
```

> [!TIP]
>
> Use blackout windows to avoid system maintenance windows, data cutoff times, or high-traffic periods in your accounting system.

## Import History & Analytics

Track completed imports and analyze operational metrics.

### View Import History

```javascript Node.js theme={null}
const response = await fetch(
  'https://api.royalti.io/merlin/history?status=completed&limit=50',
  {
    headers: { 'Authorization': `Bearer ${token}` }
  }
);

const { data: completed } = await response.json();

completed.forEach(import => {
  console.log(`
    Period: ${import.accountingPeriod}
    DSP: ${import.dspName}
    Rows: ${import.rowsImported}
    Confidence: ${(import.confidenceScore * 100).toFixed(1)}%
    Imported: ${new Date(import.importedAt).toLocaleDateString()}
  `);
});
```

### Get Import Statistics

```javascript Node.js theme={null}
const response = await fetch(
  'https://api.royalti.io/merlin/stats?period=month',
  {
    headers: { 'Authorization': `Bearer ${token}` }
  }
);

const { data: stats } = await response.json();

console.log(`
  Total Batches: ${stats.totalBatches}
  Successful: ${stats.successfulBatches}
  Failed: ${stats.failedBatches}
  Total Files: ${stats.totalFilesProcessed}
  Success Rate: ${((stats.successfulBatches / stats.totalBatches) * 100).toFixed(1)}%
  Avg Confidence: ${(stats.averageConfidenceScore * 100).toFixed(1)}%
  Avg Processing Time: ${stats.averageProcessingTime}ms
`);
```

### Get Detailed Metrics

```javascript Node.js theme={null}
const response = await fetch(
  'https://api.royalti.io/merlin/metrics?timePeriod=month',
  {
    headers: { 'Authorization': `Bearer ${token}` }
  }
);

const { data: metrics } = await response.json();

console.log('Import Metrics:', {
  successRate: `${(metrics.successRate * 100).toFixed(1)}%`,
  averageConfidence: `${(metrics.averageConfidence * 100).toFixed(1)}%`,
  averageProcessingTime: `${metrics.averageProcessingTime}ms`,
  totalFilesProcessed: metrics.totalFilesProcessed,
  filesByDSP: metrics.filesByDSP,
  filesByPeriod: metrics.filesByPeriod
});

// Output example:
// {
//   successRate: '96.2%',
//   averageConfidence: '84.5%',
//   averageProcessingTime: '2340ms',
//   totalFilesProcessed: 127,
//   filesByDSP: {
//     'DistroKid': 45,
//     'CD Baby': 38,
//     'TuneCore': 44
//   },
//   filesByPeriod: {
//     '202401': 42,
//     '202402': 43,
//     '202403': 42
//   }
// }
```

## Error Handling & Troubleshooting

### Common Issues

**1. Connection Failed**

**Cause**: FTP credentials incorrect or server unreachable

```javascript theme={null}
// Test connection to get detailed error
const response = await fetch('https://api.royalti.io/merlin/test-connection', {
  method: 'POST',
  headers: { 'Authorization': `Bearer ${token}` }
});

const result = await response.json();
console.log(result.error.message);
// Check: hostname, port, username, password, firewall rules
```

**2. Files Not Discovered**

**Cause**: Incorrect path or no files in expected location

```javascript theme={null}
// Check available periods and folders
const response = await fetch('https://api.royalti.io/merlin/connection-status', {
  headers: { 'Authorization': `Bearer ${token}` }
});

const { data } = await response.json();
console.log('Available periods:', data.availablePeriods);
console.log('DSP folders:', data.dspFolders);
// Verify importPath matches actual FTP directory structure
```

**3. Low Confidence Scores**

**Cause**: File structure differs from expected patterns

* Check file naming against DSP conventions
* Verify CSV/Excel column headers match expected names
* Ensure period information is clearly embedded
* Look for warnings in file preview

**Solution**: Use file preview to diagnose, or manually confirm accounting period in single-file approval

**4. Duplicate File Detection**

**Cause**: File already imported based on content hash

```javascript theme={null}
// Check import history to see if file was previously imported
const response = await fetch('https://api.royalti.io/merlin/history?status=completed', {
  headers: { 'Authorization': `Bearer ${token}` }
});
```

**Solution**: Use file preview to confirm it's actually different content, then contact support if needed

### Handling Import Failures

```javascript Node.js theme={null}
// Check failed imports
const response = await fetch(
  'https://api.royalti.io/merlin/history?status=failed&limit=10',
  {
    headers: { 'Authorization': `Bearer ${token}` }
  }
);

const { data: failedImports } = await response.json();

failedImports.forEach(failure => {
  console.log(`
    File: ${failure.filePath}
    Period: ${failure.accountingPeriod}
    Error: ${failure.error}
    Failed At: ${failure.importedAt}
  `);
});

// Common failure reasons:
// - Invalid data format (mismatched columns, type errors)
// - Duplicate content already imported
// - Missing required fields
// - Data validation failures in your accounting system
```

## Best Practices

**1. 1. Start with Manual Reviews**

Begin with single-file approvals to understand patterns before enabling auto-approval.

**2. 2. Monitor Initial Confidence Scores**

Track confidence scores for 2-3 weeks to establish baseline and identify problematic sources.

**3. 3. Use File Preview Regularly**

Preview files to validate structure, especially from new DSP sources.

**4. 4. Set Appropriate Confidence Thresholds**

Don't set auto-approval threshold too low. Start at 0.90 and lower gradually as you verify accuracy.

**5. 5. Establish Blackout Windows**

Add blackout windows during accounting period cutoffs or system maintenance.

**6. 6. Review Metrics Regularly**

Check import success rates and average confidence monthly to catch trends early.

**7. 7. Handle Rejections Properly**

When rejecting files, include detailed reason notes for audit trail and future pattern learning.

## API Reference

For complete API documentation, see the [Merlin Addon API Reference](/api-reference/merlin).

### Key Endpoints

* **Configuration**: `/merlin/config`, `/merlin/import/config`, `/merlin/features`
* **Connection**: `/merlin/test-connection`, `/merlin/connection-status`
* **Import Operations**: `/merlin/import/trigger`
* **Pending Management**: `/merlin/pending`, `/merlin/pending/{id}`, `/merlin/pending/grouped`
* **Approval Workflows**: `/merlin/pending/{id}/approve`, `/merlin/pending/bulk-approve`
* **Intelligence**: `/merlin/pending/recommendations`, `/merlin/pending/auto-approvable`
* **History**: `/merlin/history`, `/merlin/stats`, `/merlin/metrics`

## Support & Questions

For issues, feature requests, or questions:

**1. Check Documentation**

Review this guide and API reference for common patterns

**2. Review Import History**

Check `/merlin/history` and `/merlin/metrics` for operational insights

**3. Test Connection**

Use `/merlin/test-connection` to verify FTP credentials and data availability

**4. Contact Support**

Reach out to [support@royalti.io](mailto:support@royalti.io) with your tenant ID and specific error messages


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.