@salvatorela/cap-plugin-adobe-forms
A CAP plugin that wraps the SAP Forms service by Adobe on BTP as a CAP service, rendering a PDF from a form template with credentials from a destination or direct configuration.
Renders a PDF from a form template without hand-writing the BTP call: credentials come from a destination or direct config, the way CAP resolves everything else.
Facts
Where it sits
Who is behind it
In the atlas: maintains 1, contributes to 1@salvatorelaspatamaintainer
Before choosing this
Conditions
LicenceSAP Developer License Agreement 3.2 CAP§ 1, 2, 3A cds-plugin is used with SAP CAP materials, or an artifact is explicitly identified as a CAP plugin or application.
- § 1 License. Productive customer applications are limited to SAP BTP or another SAP-licensed platform, and mass extraction to a non-SAP product is restricted except where solely required for SAP interoperability.
- § 2 Intellectual Property. The agreement retains SAP's rights in the covered materials and limits making APIs, tools or software available to third parties, while preserving ownership of customer applications subject to SAP's underlying rights.
- § 3 Artificial Intelligence Training. The agreement prohibits use of the covered materials and customer applications for training artificial-intelligence models or systems.
What it declares
Every artifact
- Type
- CDS plugin
- Origin
- Independently maintained
- Runtime
- Node.js
- Runs on
- Cloud Foundrylocal
As a CDS plugin
- Declared for
- ^9.1.0
- Distributed through
- npm
Connections
Producing printed forms, PDFs and filled templates for people
Named, credentialed addresses of other systems resolved at runtime
Download
Install
npm add @salvatorela/cap-plugin-adobe-formsDerived from the package name. No recipe recorded; the README has the configuration.
Where it sits in your app
Download
README
quoted from salvatorelaspata/cap-plugin-adobe-forms under MIT, readcap-plugin-adobe-forms
Reusable SAP CAP Node.js plugin that wraps SAP Forms service by Adobe on SAP BTP.
Installation
npm install @salvatorela/cap-plugin-adobe-forms
Configuration
The plugin supports two authentication modes. Destination service is preferred for BTP deployments; direct credentials are useful for local development.
Option 1 — BTP Destination (recommended)
Configure an HTTP destination named ADOBE_FORMS_API with OAuth2ClientCredentials authentication in BTP Cockpit, then reference it in your CAP app:
{
"cds": {
"requires": {
"adobeForms": {
"destination": "ADOBE_FORMS_API"
}
}
}
}
Recommended destination settings:
| Field | Value |
|---|---|
| Name | ADOBE_FORMS_API |
| Type | HTTP |
| Proxy Type | Internet |
| Authentication | OAuth2ClientCredentials |
| URL | Adobe REST API base URL from the service key |
| Client ID | uaa.clientid from the service key |
| Client Secret | uaa.clientsecret from the service key |
| Token Service URL | uaa.url + /oauth/token |
Option 2 — Direct credentials (local development)
{
"cds": {
"requires": {
"adobeForms": {
"credentials": {
"baseUrl": "https://<adsrestapi-host>",
"tokenUrl": "https://<xsuaa-host>/oauth/token",
"clientId": "<uaa.clientid>",
"clientSecret": "<uaa.clientsecret>"
}
}
}
}
}
For local development with a
.envfile see TEST.md.
Usage
Programmatic API (CAP service handler)
Connect to the service with cds.connect.to and call methods directly:
const cds = require('@sap/cds')
module.exports = cds.service.impl(async function () {
const adobeForms = await cds.connect.to('adobeForms')
this.on('generateReport', async (req) => {
// Render a PDF and return it as a Buffer
const pdf = await adobeForms.renderPDF({
templateName: 'MY_FORM',
payload: {
Header: { Title: 'Annual Report', Year: 2026 },
Items: { Row: [{ Label: 'Revenue', Value: '1000' }] }
},
locale: 'it-IT'
})
return pdf // Buffer
})
this.on('listAvailableForms', async () => {
return adobeForms.listForms()
})
this.on('getSchema', async (req) => {
const { formId } = req.data
return adobeForms.getFormSchema(formId)
})
})
Render PDF as base64
Pass options.base64: true to get a base64 string instead of a Buffer (useful for JSON responses or email attachments):
const b64 = await adobeForms.renderPDF({
templateName: 'MY_FORM',
payload: { ... },
options: { base64: true }
})
// b64 is a base64-encoded string
Raw XML payload
If your data is already valid XML, pass it as a string — no conversion is applied:
const pdf = await adobeForms.renderPDF({
templateName: 'MY_FORM',
payload: '<?xml version="1.0" encoding="UTF-8"?><FormData><Title>Hello</Title></FormData>'
})
HTTP / OData (REST endpoint)
The plugin also exposes a CAP OData service at /adobe/forms. Call it directly via HTTP:
# List all forms
curl -X POST https://<app>/adobe/forms/listForms
# Render a PDF
curl -X POST https://<app>/adobe/forms/renderPDF \
-H 'Content-Type: application/json' \
-d '{"templateName":"MY_FORM","payload":"{\"Header\":{\"Title\":\"Test\"}}","locale":"it-IT"}' \
--output report.pdf
# Health checks
curl -X POST https://<app>/adobe/forms/health
curl -X POST https://<app>/adobe/forms/remoteHealth
Note:
options.base64is only available via the programmatic API. The OData action always returns binary (application/pdf).
CAP service
The plugin registers the service at path /adobe/forms.
@path: '/adobe/forms'
service AdobeFormsService {
@Core.MediaType: 'application/pdf'
action renderPDF(
templateName : String(255),
payload : LargeString,
locale : String(10)
) returns LargeBinary;
action listForms() returns LargeString;
action getFormDetails(formId : String(255)) returns LargeString;
action getFormSchema(formId : String(255)) returns LargeString;
action health() returns HealthStatus;
action remoteHealth() returns RemoteHealthStatus;
}
API reference
renderPDF({ templateName, payload, locale, options })
Renders a PDF for the given form template.
Internally the plugin:
- Fetches the form details (
GET /v1/forms/{templateName}) to retrieve the available XDP templates - Selects the template whose
languagematches thelocalelanguage code; falls back to the first template if no match is found - Converts
payloadto XML and base64-encodes it - Calls
POST /v1/adsRender/pdfwithxdpTemplateandtemplateName(from the selected template), then returns the decoded PDF as aBuffer
| Parameter | Type | Required | Description |
|---|---|---|---|
templateName | string | yes | Form name as returned by listForms |
payload | object | string | yes | Data to fill the form. JS objects are serialized to XML automatically. Strings are sent as-is (must be valid XML). |
locale | string | no | Locale in ll, ll-LL or ll_LL format (e.g. it, it-IT). Defaults to en_US. Used to select the matching language template variant. |
options.base64 | boolean | no | If true, returns the PDF as a base64 string instead of a Buffer. Defaults to false. |
Payload structure — JS objects are converted to XML with the root element FormData:
// Input
{
Header: { NumeroDelibera: 'TEST-001', Anno: 2026, Data: '2026-04-23' },
TabellaStringhe: { Riga: [{ Testo: 'Prima riga' }, { Testo: 'Seconda riga' }] }
}
// Serialized XML sent to the API
<?xml version="1.0" encoding="UTF-8"?>
<FormData>
<Header>
<NumeroDelibera>TEST-001</NumeroDelibera>
<Anno>2026</Anno>
<Data>2026-04-23</Data>
</Header>
<TabellaStringhe>
<Riga><Testo>Prima riga</Testo></Riga>
<Riga><Testo>Seconda riga</Testo></Riga>
</TabellaStringhe>
</FormData>
Returns: Buffer (PDF binary)
listForms()
Returns all form templates available in the Adobe Forms tenant.
GET /v1/forms
Returns: array of form objects, each with formName, metaData, schema, and templates.
getFormDetails(formId)
Returns full details for a specific form, including the XSD schema and XDP templates.
GET /v1/forms/{formId}
| Parameter | Type | Description |
|---|---|---|
formId | string | Form name (URL-encoded automatically) |
Returns: form object with formName, schema, templates, metaData.
getFormSchema(formId)
Returns the XSD schema of a form decoded as a plain string.
Internally calls getFormDetails and decodes schema.xsdSchema from base64.
| Parameter | Type | Description |
|---|---|---|
formId | string | Form name |
Returns:
{
formName: 'DELIBERA',
schemaName: 'Schema',
xsd: '<?xml version="1.0"...>', // decoded XSD
metaData: { objectId, versionNumber, creationDate, ... }
}
health()
Returns local plugin health without making any outbound call.
Returns: { status: 'UP', service: 'SAP Forms service by Adobe' }
remoteHealth()
Resolves the destination (or direct credentials) and performs a real call to the configured healthPath (default: GET /v1/forms) to verify end-to-end connectivity.
Returns:
{
status: 'UP' | 'DOWN',
service: 'SAP Forms service by Adobe',
destinationName: 'ADOBE_FORMS_API',
endpoint: '/v1/forms',
reachable: true | false,
authenticated: true | false,
details: '...'
}
Error codes
| Code | Thrown by | Description |
|---|---|---|
ADOBE_FORMS_API_FAILED | all API calls | HTTP error from the Adobe REST API (includes status) |
ADOBE_FORMS_CONFIG_MISSING | startup | Required credential fields are missing |
ADOBE_FORMS_XDP_NOT_FOUND | renderPDF | No XDP template found for the form (or the selected language variant) |
ADOBE_FORMS_SCHEMA_NOT_FOUND | getFormSchema | The form has no schema.xsdSchema field |
ADOBE_FORMS_DESTINATION_NOT_FOUND | all API calls | BTP destination resolved to null (destination mode) |
ADOBE_FORMS_OAUTH_FAILED | all API calls | OAuth token endpoint returned an error (direct mode) |
Testing
See TEST.md for instructions on running unit tests and integration tests against a real BTP instance.
# Unit tests (no credentials needed)
npm test
# Integration test against real BTP service
node --env-file=.env test/integration.jsHistory
Others providing
Compare all 11 on the Document output page →- abap2xlsxabap2xlsxA library that reads and generates .xlsx Excel workbooks directly from ABAP data, without exporting through a list viewer, installed through abapGit and tested from SAP_ABA 731.independent, abapLibrary that reads and generates Excel spreadsheets from ABAPfrom ABAP
- zcl_docxzcl_docxAn ABAP class that fills a Word .docx template tagged with content controls, with a report, ZDOCX_GET_TYPES, that generates the ABAP types the template needs; the document opens in Word or returns as an xstring.independent, abapABAP class filling a tagged Word .docx template with datafrom ABAP
- zcl_pdfzcl_pdfA standalone ABAP class that draws simple PDFs without Adobe Document Server: text in built-in fonts, text fitted into a box and rectangles, returned as a raw string to store, send or display.independent, abapStandalone ABAP class drawing PDFs without Adobe Document Serverfrom ABAP
- XTTXTTAn ABAP template engine that merges data, including nested structures, tables and trees, into Excel, Word, HTML and PDF templates prepared in ordinary editors with markers in curly brackets.independent, abapABAP template engine for Excel, Word, HTML and PDFfrom ABAP
- SAP Forms Service by AdobeSAP Forms Service by AdobeAdobe Document Services on BTP: renders print and interactive PDF forms from stored templates, called over a REST API from a cloud application or connected to an ABAP system.sap official, btpAdobe Document Services on BTP for print and interactive PDFsfrom BTP/BAIP
- SAP Print serviceSAP Print servicePrint queues between cloud applications and a customer's local printers: an application queries queues and creates print queue items through public APIs, and the queues are managed in the service.sap official, btpPrint queues between cloud applications and local printersfrom BTP/BAIP
- @cap-js/print@cap-js/printA CDS plugin that prints a document held in a CAP entity, through SAP Print service and a @PDF.Printable annotation.sap official, capPrints documents held in CAP entities through SAP Print servicefrom CAP
- HandlebarsABAPHandlebarsABAPA single-file Handlebars templating implementation for ABAP 7.40 SP02 and up that fills a template from an ABAP structure or table, with block helpers, partials and custom helpers.independent, abapSingle-file Handlebars templating for ABAP 7.40 SP02 and upfrom ABAP
- open-abap-pdfopen-abap-pdfA standalone PDF generator written in ABAP that builds a multi-page document from text, lines, rectangles and circles placed at given coordinates and returns it as a string or an xstring.community org, abapStandalone PDF generator written in ABAPfrom ABAP
- SAP Spool PDFSAP Spool PDFAn ABAP class that submits a report to the spool, typically in the background, and converts the resulting spool request into a PDF it can return as an xstring, save, show or email.independent, abapSubmits an ABAP report to the spool and converts the output to PDFfrom ABAP
Details
Sources
Sources are graph entities: the same page may back several entries, and an unreachable source flags every row that rests on it.
Compatibility and provenance
History in the atlas
- First seen.
For your agent
- Ref
artifact:salvatorelaspata-cap-plugin-adobe-forms- JSON
- /artifacts/salvatorelaspata-cap-plugin-adobe-forms.json
- MCP
- Connecting an agent