How to create a custom API in AEM as a cloud service | Community
Skip to main content
Level 2
March 27, 2026
Question

How to create a custom API in AEM as a cloud service

  • March 27, 2026
  • 5 replies
  • 43 views

How do I create a custom API on AEM so that any external system (ex: postman, curl) can access the API via some authentication(OAUTH/SAML). Once the handshake is done external system needs to send AEM some data, AEM will do some business process and pass a response.

5 replies

VeenaVikraman
Community Advisor
Community Advisor
March 27, 2026

@Balasai_NikhilKa2 Can you explain bit more in detail ?

giuseppebaglio
Level 10
March 27, 2026

hi ​@Balasai_NikhilKa2

To create a custom API on AEM that accepts external data and returns a processed response, you must develop a SlingAllMethodsServlet to handle POST requests and configure OAuth Server-to-Server authentication for secure access. The external system will first request an access token from Adobe IMS and then pass this token along with the data payload to your AEM endpoint.

Create the Custom Servlet

To handle incoming data, create a Java class that extends SlingAllMethodsServlet and register it as an OSGi component. You must override the doPost method to read the incoming data payload, execute your specific business processes, and write a JSON response back to the external system. While you can register the servlet using a specific path like /bin/customapi, binding it to a resource type using @SlingServletResourceTypes is considered the best practice.[1][3]

Configure OAuth Authentication

For external systems to authenticate securely with AEM as a Cloud Service, use the OAuth Server-to-Server credential flow. You must create an integration project in the Adobe Developer Console, add the required Experience Cloud API, and select the OAuth Server-to-Server authentication method. This configuration generates the client_idclient_secret, and scopes needed by the external system to request access tokens without user interaction.[4][6]

Handle CSRF Protection

AEM enforces security by requiring a valid CSRF token for all authenticated POST requests. For machine-to-machine integrations, you can configure the Adobe Granite CSRF Filter in AEM's OSGi settings to exclude your custom API path, allowing external systems to bypass the token check. If you do not exclude the path, the external system must first perform a GET request to /libs/granite/csrf/token.json and pass the returned token in the CSRF-Token header of the POST request.[2]

Send Data to AEM

Once the handshake is complete, the external system uses tools like cURL or Postman to send a POST request directly to your custom AEM servlet endpoint. The request must include the obtained access token in the Authorization: Bearer <access_token> header. AEM will authenticate the request, pass the payload to your servlet for business processing, and return your generated response.[5][4]

Level 2
March 27, 2026

Example:-
 There is AEM servlet to collect some data from an external system.
How can that external system (Ex; postman, any other application) hit an AEM servlet, so that it sends some data and in return AEM sends some response.

AmitVishwakarma
Community Advisor
Community Advisor
March 27, 2026

Hi ​@Balasai_NikhilKa2 

1. Create a custom servlet as your API Implement an OSGi Sling Servlet with a fixed path (for example /bin/myapp/external) and handle JSON input/output.

package com.myapp.core.servlets;

import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.Gson;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.servlets.SlingAllMethodsServlet;
import org.osgi.service.component.annotations.Component;

import javax.servlet.Servlet;
import javax.servlet.ServletException;
import java.io.IOException;

@Component(
service = Servlet.class,
property = {
"sling.servlet.methods=POST", // or GET/PUT if needed
"sling.servlet.paths=/bin/myapp/external", // API endpoint
"sling.servlet.extensions=json"
}
)
public class ExternalApiServlet extends SlingAllMethodsServlet {

@Override
protected void doPost(SlingHttpServletRequest request,
SlingHttpServletResponse response)
throws ServletException, IOException {

JsonObject input = JsonParser
.parseReader(request.getReader())
.getAsJsonObject();

// Your business logic
String foo = input.get("foo").getAsString();

JsonObject result = new JsonObject();
result.addProperty("foo", foo);
result.addProperty("processed", true);

response.setContentType("application/json");
new Gson().toJson(result, response.getWriter());
}
}

Deploy this with your normal AEM as a Cloud Service pipeline.

2. Allow the servlet through Dispatcher (publish)

In dispatcher filter rules (publish tier), allow this path:

/0100 {
/type "allow"
/method "POST"
/url "/bin/myapp/external"
}

Deploy dispatcher config via your web tier/config pipeline.

3. Use token‑based auth (OAuth / service credentials)

For Postman / backend systems, use token-based authentication, not SAML:

In AEM, make sure the corresponding technical account user has permissions to access your servlet path.

4. Call the servlet from Postman / cURL

Postman:

  • Method: POST
  • URL:  https:///bin/myapp/external.json
  • Headers:
    Authorization: Bearer <ACCESS_TOKEN>
    Content-Type: application/json
  • Body (raw JSON):
    {
    "foo": "bar"
    }
  • cURL:
    curl -X POST \
    https://<author-or-publish-domain>/bin/myapp/external.json \
    -H "Authorization: Bearer <ACCESS_TOKEN>" \
    -H "Content-Type: application/json" \
    -d '{"foo":"bar"}'

    Response (example):

    {
    "foo": "bar",
    "processed": true
    }

5. Why OAuth/token and not SAML?

Amit Vishwakarma - Adobe Commerce Champion 2025 | 16x Adobe certified | 4x Adobe SME
Level 2
March 27, 2026

I have created project but when i click on add API  this option is not available “AEM as a Cloud Service API.”

 

Level 1
March 29, 2026

Actually, you can build a servlet and deploy as an OSGI bundle. In order to do that, you should open the project code ( if using archetype, create a new java class inside Core folder).

Alternativelly you can leverage App Builder, create some serverless function and interact with AEM through it’s Rest API.