Specification for custom D365 FO report services

DynamicPoint Portal downloads report files (PDF, Excel) from Dynamics 365 Finance and Operations through custom JSON services. Portal is generic: it knows only the request and response contract below, never report specific fields. Any service that follows this contract will be supported natively in Portal.

1     Endpoint

POST {FO environment URL}/api/services/{ServiceGroup}/{Service}/{Operation}

Part Meaning Example (our test)
FO environment URL Root URL of the FO environment, without /data https://dpdemod365fo8b1f0f06ad91ea54aos.axcloud.dynamics.com
/api/services Fixed path of FO custom JSON services /api/services
ServiceGroup Name of the service group (AxServiceGroup) EasyAP365Extensions
Service Name of the service (AxService) EasyAP365SalesInvoiceDocument
Operation Name of the service operation (method) getSalesInvoiceDocument (PDF), getSalesInvoiceExcelDocument (Excel)

2     Authentication

  • Portal calls the service with an OAuth 2.0 bearer token from Microsoft Entra ID (client credentials of an app registration). The token is requested for the FO environment URL.
  • The app registration that Portal uses (configured in Portal as an Entra ID application credential) must be added in FO under System administration > Setup > Microsoft Entra applications and mapped to a user whose security roles allow the service operations.
  • Request headers: Authorization: Bearer <token>, Content-Type: application/json, Accept: application/json.

3     Request

Template:

{
“_request”: {
“DataAreaId”: “<company>”,
“<Parameter1>”: <value>,
“<Parameter2>”: <value>
}
}

  • _request: FO matches the top level key to the parameter name of the operation, so the operation must take one data contract parameter named _request, for example public MyReportResponse getDocument(MyReportRequest _request).
  • DataAreaId: always sent. It is the company configured on the report in Portal, unless the report is configured with its own DataAreaId parameter (for example the dataAreaId of the selected record). The service should run in that company (changecompany).
  • Other parameters: the names are configured per report in Portal and must match the data contract member names exactly, including case. Please avoid leading or trailing spaces.
  • Values: text is sent as a JSON string, numbers as JSON numbers, dates as “yyyy-MM-dd” strings (for example “2026-10-15”). A field that is empty in the record is sent as null, and an optional parameter the user leaves empty is not sent. A fixed value configured in Portal is always sent as text.

4     Response

The response is the same for every report service. Return it with HTTP 200 as the top level JSON object, for success and for business errors.

Template:

{
“Success”: true,
“ErrorCode”: “”,
“Message”: “”,
“FileName”: “<file name with extension>”,
“MimeType”: “<MIME type>”,
“FileContentBase64”: “<file content>”
}

Field Type Meaning
Success bool true when the file was produced
ErrorCode string Your error code when Success = false, empty otherwise
Message string Informational text, or the error text when Success = false
FileName string Download file name with extension, e.g. SalesInvoice_usmf_CIV-000002.pdf
MimeType string application/pdf for PDF, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet for Excel
FileContentBase64 string The whole file as Base64, without a data: prefix; empty when Success = false
  • Field names: please use exactly these names.
  • Errors: report a business error (record not found, no data, rendering failed) with Success = false, an ErrorCode and a Message. Portal shows them to the user as ErrorCode: Message and does not interpret the codes. HTTP errors (for example 401 or 500) are shown with their status and error text.
  • File name and type: if FileName is empty, Portal names the file after the report, with the extension of the file type configured on the report (.pdf or .xlsx). If MimeType is empty, Portal takes the type from the file extension. See section 7 for Excel.
  • Response time: Portal waits up to 220 seconds for the file. For reports over many documents, please limit the result (for example with a maximum count parameter) and return an error when the limit is exceeded.

5    Example: report attached to a record

The user opens a record in Portal, for example a sales invoice, and prints it. Portal reads the record and fills the parameters from its fields.

Request:

POST https://dpdemod365fo8b1f0f06ad91ea54aos.axcloud.dynamics.com/api/services/EasyAP365Extensions/EasyAP365SalesInvoiceDocument/getSalesInvoiceDocument

{
“_request”: {
“DataAreaId”: “USMF”,
“InvoiceId”: “CIV-000002”
}
}

Response:

{
“Success”: true,
“ErrorCode”: “”,
“Message”: “1 sales invoice(s) rendered to PDF.”,
“FileName”: “SalesInvoice_usmf_CIV-000002.pdf”,
“MimeType”: “application/pdf”,
“FileContentBase64”: “JVBERi0xLjQK…”
}

Another for the sales invoice service, with ReportType configured as a fixed value and DocumentReference taken from the invoice number:

POST {FO environment URL}/api/services/RACCustomerPortalServiceGroup/RACCustomerPortalReportService/getDocumentPdf

{
“_request”: {
“DataAreaId”: “USMF”,
“ReportType”: “SALESINVOICE”,
“DocumentReference”: “CIV-000002”
}
}

An error response, for example when the invoice does not exist:

{
“Success”: false,
“ErrorCode”: “InvoiceNotFound”,
“Message”: “Sales invoice CIV-999999 was not found in company usmf.”,
“FileName”: “”,
“MimeType”: “”,
“FileContentBase64”: “”
}

Portal shows: InvoiceNotFound: Sales invoice CIV-999999 was not found in company usmf.

6    Example: standalone report

The user opens the report from the report list in Portal, without a record. Portal fills the parameters from the values the user enters and from defaults configured on the report, for example the first and last day of the current month. In our test the parameters are FromDate and ToDate (dates), CustomerAccount (text) and InvoiceMaxCount (integer), and the service returns the matching invoices merged into one PDF.

Request:

POST https://dpdemod365fo8b1f0f06ad91ea54aos.axcloud.dynamics.com/api/services/EasyAP365Extensions/EasyAP365SalesInvoiceDocument/getSalesInvoiceDocument

{
“_request”: {
“DataAreaId”: “USMF”,
“FromDate”: “2026-10-01”,
“ToDate”: “2026-10-31”,
“CustomerAccount”: “US-001”,
“InvoiceMaxCount”: 50
}
}

Response: the same contract as above, with the merged PDF in FileContentBase64.

 

7    Excel reports

An Excel report uses the same request and response contract as a PDF report. Only the content differs:

  • File: FileContentBase64 holds the bytes of an .xlsx workbook, FileName ends with .xlsx, and MimeType is application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.
  • One operation per format: Portal does not tell the service which format to render. Please provide a separate operation for each format. Each operation is configured in Portal as its own report. If you prefer one operation for both formats, it can take a format parameter instead, which the administrator configures in Portal as a fixed value per report (for example “ReportFormat”: “Excel”).
  • File type in Portal: the administrator sets File type to Excel on an Excel report. Portal uses it only when the response has no FileName: the file is then named after the report with the extension .xlsx.
  • Several records: return one file per request. Our test service merges several invoices into one workbook, with one worksheet per invoice named after the invoice ID.

Example with our test service, an Excel report attached to a sales invoice:

POST https://dpdemod365fo8b1f0f06ad91ea54aos.axcloud.dynamics.com/api/services/EasyAP365Extensions/EasyAP365SalesInvoiceDocument/getSalesInvoiceExcelDocument

{
“_request”: {
“DataAreaId”: “USMF”,
“InvoiceId”: “CIV-000002”
}
}
{
“Success”: true,
“ErrorCode”: “”,
“Message”: “”,
“FileName”: “SalesInvoice_usmf_CIV-000002.xlsx”,
“MimeType”: “application/vnd.openxmlformats-officedocument.spreadsheetml.sheet”,
“FileContentBase64”: “UEsDBBQABgAIAAAAIQ…”
}

The standalone request from section 6 sent to getSalesInvoiceExcelDocument returns all matching invoices in one workbook, for example SalesInvoices_usmf_20261001_20261031_US-001.xlsx.

8    Checklist

  • The operation takes one data contract parameter named _request.
  • The request contract has a DataAreaId member, and the other member names match the parameter names configured in Portal exactly.
  • Dates are accepted as yyyy-MM-dd.
  • The response members are named Success, ErrorCode, Message, FileName, MimeType and FileContentBase64, returned at the top level with HTTP 200.
  • Business errors are returned as Success = false with an ErrorCode and a Message.
  • Each file format has its own operation (or a format parameter), and Excel files are returned as .xlsx with the Excel MIME type.
  • The app registration used by Portal is added in FO and has access to the service operations.