Sales Invoice API Documentation

Overview

This API provides read-only access to posted sales invoices with the ability to retrieve invoice data and PDF attachments from Business Central.

API Information

  • Version: 1.0.0
  • Type: RESTful API
  • Format: JSON (OData v4)
  • Authentication: OAuth2
  • License: Proprietary

Base URLs

Production Environment

https://{environment}.api.businesscentral.dynamics.com/v2.0/{tenant}/Production/api/yourcompany/editinoutlook/v1.0

Sandbox Environment

https://{environment}.api.businesscentral.dynamics.com/v2.0/{tenant}/Sandbox/api/yourcompany/editinoutlook/v1.0

URL Variables: - {environment}: Business Central environment (api for SaaS, or custom domain for on-premises) - {tenant}: Azure AD tenant ID or domain

Authentication

OAuth2 Configuration

The API uses OAuth2 authentication with the following scope: - Scope: https://api.businesscentral.dynamics.com/Financials.ReadWrite.All - Authorization URL: https://login.microsoftonline.com/common/oauth2/v2.0/authorize<br> - Token URL: https://login.microsoftonline.com/common/oauth2/v2.0/token

Example Authorization Header

Authorization: Bearer {your-access-token}

Endpoints

1. Get Sales Invoices

GET /salesInvoices

Retrieves a list of posted sales invoices with basic information and Base64 encoded PDF content.

Query Parameters

ParameterTypeRequiredDescriptionExample
$selectstringNoSelect specific fields to returnid,no,billToName,amount,pdfInvoice
$filterstringNoFilter the resultsbillToCustomerNo eq '20000'
$orderbystringNoOrder the resultspostingDate desc
$topintegerNoLimit number of results (1-20000)50
$skipintegerNoSkip a number of results0

Example Request

GET /salesInvoices?$filter=billToCustomerNo eq '20000'&$top=10&$orderby=postingDate desc
Authorization: Bearer {your-access-token}

Example Response (200 OK)

{
  "@odata.context": "https://api.businesscentral.dynamics.com/v2.0/tenant/Production/api/yourcompany/editinoutlook/v1.0/$metadata#salesInvoices",
  "value": [
    {
      "@odata.etag": "W/\"JzE5OzczNjYzNDM4MjIxNDY2OTcwMTYxOzAwOyc=\"",
      "id": "c44ac32c-80d0-f011-8bcf-6045bdc89f91",
      "billToCustomerNo": "20000",
      "no": "103001",
      "postingDate": "2023-01-17",
      "billToName": "Trey Research",
      "amount": 165.6,
      "amountIncludingVAT": 200.38,
      "pdfInvoice": "JVBERi0xLjcNCiW..."
    }
  ]
}

2. Get Sales Invoice by ID

GET /salesInvoices({id})

Retrieves a specific sales invoice by its unique identifier, including the Base64 encoded PDF.

Path Parameters

ParameterTypeRequiredDescriptionExample
idstring (UUID)YesUnique identifier of the sales invoicec44ac32c-80d0-f011-8bcf-6045bdc89f91

Query Parameters

ParameterTypeRequiredDescriptionExample
$selectstringNoSelect specific fields to returnid,no,billToName,pdfInvoice

Example Request

GET /salesInvoices(c44ac32c-80d0-f011-8bcf-6045bdc89f91)?$select=id,no,billToName,pdfInvoice
Authorization: Bearer {your-access-token}

Example Response (200 OK)

{
  "@odata.context": "https://api.businesscentral.dynamics.com/v2.0/tenant/Production/api/yourcompany/editinoutlook/v1.0/$metadata#salesInvoices/$entity",
  "@odata.etag": "W/\"JzE5OzczNjYzNDM4MjIxNDY2OTcwMTYxOzAwOyc=\"",
  "id": "c44ac32c-80d0-f011-8bcf-6045bdc89f91",
  "billToCustomerNo": "20000",
  "no": "103001",
  "postingDate": "2023-01-17",
  "billToName": "Trey Research",
  "amount": 165.6,
  "amountIncludingVAT": 200.38,
  "pdfInvoice": "JVBERi0xLjcNCiW..."
}

Data Models

Sales Invoice Object

FieldTypeDescriptionExampleMax Length
@odata.etagstringETag for optimistic concurrencyW/\"JzE5OzczNjY...\"-
idstring (UUID)Unique identifier (SystemId)c44ac32c-80d0-f011-8bcf-6045bdc89f91-
billToCustomerNostringCustomer number for billing2000020
nostringInvoice number10300120
postingDatestring (date)Date when invoice was posted2023-01-17-
billToNamestringName of customer being billedTrey Research100
amountnumber (decimal)Invoice amount excluding VAT165.6-
amountIncludingVATnumber (decimal)Invoice amount including VAT200.38-
pdfInvoicestring (base64)Base64 encoded PDF contentJVBERi0xLjcNCiW...-

PDF Invoice Field

The pdfInvoice field contains the complete sales invoice as a Base64 encoded PDF file:

  • Format: Base64 string
  • Content: Complete PDF document
  • Usage: Can be decoded and saved as a PDF file
  • Fallback: Returns empty string if PDF generation fails

Decoding PDF Example (JavaScript)

// Convert Base64 to PDF and download
function downloadPDF(base64Data, filename) {
    const byteCharacters = atob(base64Data);
    const byteNumbers = new Array(byteCharacters.length);
    
    for (let i = 0; i < byteCharacters.length; i++) {
        byteNumbers[i] = byteCharacters.charCodeAt(i);
    }
    
    const byteArray = new Uint8Array(byteNumbers);
    const blob = new Blob([byteArray], {type: 'application/pdf'});
    
    const url = window.URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.style.display = 'none';
    a.href = url;
    a.download = filename;
    document.body.appendChild(a);
    a.click();
    window.URL.revokeObjectURL(url);
}

// Usage
downloadPDF(invoiceData.pdfInvoice, `Invoice-${invoiceData.no}.pdf`);

HTTP Response Codes

CodeStatusDescription
200OKRequest successful
400Bad RequestInvalid query parameters
401UnauthorizedInvalid or missing authentication
403ForbiddenInsufficient permissions
404Not FoundSales invoice not found
500Internal Server ErrorServer error occurred

Error Response Format

All error responses follow this structure:

{
  "error": {
    "code": "BadRequest",
    "message": "Invalid query parameter",
    "details": [
      {
        "code": "InvalidFilter",
        "message": "The filter expression is not valid",
        "target": "$filter"
      }
    ]
  }
}

OData Query Examples

Basic Filtering

# Get invoices for specific customer
GET /salesInvoices?$filter=billToCustomerNo eq '20000'

# Get invoices from specific date
GET /salesInvoices?$filter=postingDate ge 2023-01-01

# Get invoices with amount greater than 1000
GET /salesInvoices?$filter=amount gt 1000

Sorting and Paging

# Sort by date (newest first), limit to 20 results
GET /salesInvoices?$orderby=postingDate desc&$top=20

# Skip first 50 results (pagination)
GET /salesInvoices?$skip=50&$top=25

# Sort by customer name then by date
GET /salesInvoices?$orderby=billToName,postingDate desc

Field Selection

# Get only essential fields
GET /salesInvoices?$select=id,no,billToName,amount

# Get only PDF without other data
GET /salesInvoices?$select=id,no,pdfInvoice

Combined Queries

# Complex query: Recent invoices for specific customer, sorted by amount
GET /salesInvoices?$filter=billToCustomerNo eq '20000' and postingDate ge 2023-01-01&$orderby=amount desc&$top=10&$select=id,no,postingDate,amount,pdfInvoice

Usage Examples

Example 1: Get Invoice List for Email Integration

async function getInvoicesForEmail(customerNo, limit = 10) {
    const response = await fetch(`/salesInvoices?$filter=billToCustomerNo eq '${customerNo}'&$top=${limit}&$select=id,no,postingDate,billToName,amount,pdfInvoice`, {
        headers: {
            'Authorization': 'Bearer ' + accessToken,
            'Content-Type': 'application/json'
        }
    });
    
    if (response.ok) {
        const data = await response.json();
        return data.value;
    } else {
        throw new Error('Failed to fetch invoices');
    }
}

Example 2: Download Single Invoice PDF

async function downloadInvoicePDF(invoiceId) {
    const response = await fetch(`/salesInvoices(${invoiceId})?$select=no,pdfInvoice`, {
        headers: {
            'Authorization': 'Bearer ' + accessToken
        }
    });
    
    if (response.ok) {
        const invoice = await response.json();
        if (invoice.pdfInvoice) {
            downloadPDF(invoice.pdfInvoice, `Invoice-${invoice.no}.pdf`);
        } else {
            console.error('PDF not available for this invoice');
        }
    }
}

Integration Notes

Performance Considerations

  • PDF Size: PDF files can be large, consider using $select to exclude PDF when not needed
  • Paging: Use $top and $skip for large result sets
  • Filtering: Always filter results to minimize data transfer
  • Caching: Consider caching frequently accessed invoice data

Security Notes

  • OAuth Scope: Requires Financials.ReadWrite.All scope
  • Tenant Isolation: API automatically filters data by tenant
  • User Permissions: Respects Business Central user permissions
  • HTTPS Only: All connections must use HTTPS

Rate Limiting

  • Follow Business Central API rate limiting guidelines
  • Implement retry logic with exponential backoff
  • Monitor API usage through Business Central telemetry

External Resources


For technical support, contact your solution provider or system administrator.