How to create a confluence page with ScriptRunner via REST API

I have ScriptRunner installed on a Confluence server and I want to be able to create a page via the REST API. All of the examples I see creating a Confluence page are setup to run from Jira to create a discussion page or assume there is an Application Link setup for the Confluence site, but I want to create directly from the Confluence Script Runner.

This is what I have so far, but it won’t work as it complains about the authentication part

import com.atlassian.applinks.api.ApplicationLink
import com.atlassian.applinks.api.ApplicationLinkService
import com.atlassian.applinks.api.application.confluence.ConfluenceApplicationType
import com.atlassian.sal.api.component.ComponentLocator
import groovy.json.JsonBuilder
import groovy.json.JsonSlurper

def confluenceLink = getPrimaryConfluenceLink()
assert confluenceLink // must have a working app link set up

def authenticatedRequestFactory = confluenceLink.createImpersonatingAuthenticatedRequestFactory()

// set the page title - this should be unique in the space or page creation will fail
def pageTitle = "Teset Discussion"
def pageBody = """h3. Test

{quote}This is a quote{quote}

Yada yada, use this page to discuss the above...

def params = [
        type: "page",
        title: pageTitle,
        space: [
                key: "COM" // set the space key - or calculate it from the project or something
        /* // if you want to specify create the page under another, do it like this:
         ancestors: [
                 type: "page",
                 id: "14123220",
        body: [
                storage: [
                        value: pageBody,
                        representation: "wiki"

        .createRequest(Request.MethodType.POST, "rest/api/content")
        .addHeader("Content-Type", "application/json")
        .setRequestBody(new JsonBuilder(params).toString())
        .execute(new ResponseHandler<Response>() {
    void handle(Response response) throws ResponseException {
        if(response.statusCode != HttpURLConnection.HTTP_OK) {
            throw new Exception(response.getResponseBodyAsString())
        else {
            def webUrl = new JsonSlurper().parseText(response.responseBodyAsString)["_links"]["webui"]

Any help would be greatly appreciated

1 Like

You are missing the authentication header, something like

String basicAuth = Base64.getEncoder().encodeToString((username+":"+password).getBytes(StandardCharsets.UTF_8));
httpConn.setRequestProperty ("Authorization", "Basic "+basicAuth);

You might as well have to add

X-Atlassian-Token: no-check

in the header

@Panos since this is being executed through the Admin console, does it need auth at all? Are you aware of any documentation that talks through how to do this with ScriptRunner? I feel like the example I’m going off of is too specific to the external app setup.

Well it claims auth error. Add headers check if it goes away. Is this an Atlassian hosted server?

@Panos I have this on a locally hosted confluence

Hello @Panos !

I’ve mixed the below 2 documentation to create this script.

Something strange was that my Confluence was not displaying the logs in Script Console, but they were logged in the atlassian-confluence.log.

The below code worked in a Confluence 6.11.2 with Scriprunner 5.4.26. You will need to change some parameter such as your credential,confluence url and page json body. I suggest you to use Postman to test tour body payload.

PS: This could be without scriptrunner by JAVA/NodeJS/Python or any other language through REST API.

import static
import groovy.json.JsonSlurper
import groovy.json.JsonOutput
import java.util.Base64
import java.util.Base64.Encoder

def url = "http://localhost:8090/rest/api/content/"

def client = new RESTClient(url)
//Change to match your username/password
def authBasic = Base64.getEncoder().encodeToString(("USERNAME"+":"+"PASSWORD").getBytes());

// Change this json to match what you need
// This is creating a simple page in DEMO space
def jsonObj = new JsonSlurper().parseText('{"type":"page","title":"new page","space":{"key":"DEMO"},"body":{"storage":{"value":"<p>This is <br/> a new page</p>","representation":"storage"}}}')
	HttpResponseDecorator response = (HttpResponseDecorator) "/rest/api/content/",
      contentType: JSON,
      body: jsonObj,
	  headers: [Accept: 'application/json',Authorization:"Basic ${authBasic}"]);
    log.error("Status: " + response.status)
    if ( {
      log.error("Content Type: " + response.contentType)
      log.error("Headers: " + response.getAllHeaders())
      log.error("Body:\n" + JsonOutput.prettyPrint(JsonOutput.toJson(

catch(HttpResponseException e){
    log.error e.getResponse().getData()

Thank you so much. That works for me and gives me a foundation to go on. Really appreciate it!

1 Like

Glad to hear that it worked. :slight_smile:

1 Like

Great :sunglasses:!

Can you please set my answer as solution?