# Automation and webhooks

[Video: Starting a signing from a Jira flow, in 25 seconds, no sound](/images/videos/signplus/automation-light.b2ee6b87.mp4)

What the video shows:

1. In the Jira flow builder, add an action, search for SignPlus and choose Start a SignPlus signing under Other apps.
2. The first time, select Connect. A flag says the connection is created.
3. Choose the space, type part of the page title and pick the page.
4. Under Signers, select a user and select Add signer.
5. Select Save and enable. The flow reads Enabled.

A rule can do everything the panel on the page can: start a signing with any option the
space allows, export a PDF, and react when a signing completes or a signed page changes.

## Which product, and what that changes

**The SignPlus rule components appear in Jira automation**, not in the Confluence rule
builder. Atlassian publishes the module for Jira, and that is where it shows up. It fits
the common case anyway: a work item moves to Approved, and the Confluence page it refers to
goes out for signature.

Confluence rules reach exactly the same things through **Send web request** against the
[REST API](../rest-api/), which works on every Confluence plan.

| You want to | In Jira | In Confluence |
|---|---|---|
| Start a signing | The SignPlus component | Send web request |
| Export a PDF | The SignPlus component | Send web request |
| React when a signing completes | Incoming webhook trigger | Incoming webhook trigger |
| React when a signed page is edited | Incoming webhook trigger | Incoming webhook trigger |

The Jira components need SignPlus connected to Jira. See
[connecting Jira](../install/#connecting-jira).

## What a rule acts as

**SignPlus itself.** Every Confluence call a rule makes runs as the app, so the page
history, the attachment and the activity log name SignPlus rather than a person. There is
nothing to configure for it. Page restrictions apply to the app like anyone else, so a
page an administrator has restricted stays out of reach.

## Add SignPlus to a Jira flow

Jira calls an automation rule a **flow**. In the flow builder, add an action, search for
SignPlus or scroll to **Other apps**, and pick **Start a SignPlus signing** or **Export a page as
PDF**.

<Steps
  items={[
    {
      title: 'Connect it, once',
      body: 'The first time, the step says Atlassian Automation has to be connected to Oktul SignPlus for Confluence. Select Connect. A Connection created message confirms it, and the step then says who it is logged in as.',
    },
    {
      title: 'Choose the page',
      body: 'Pick the Space, then type part of the page title under Page. Only the spaces and pages you can see are offered.',
    },
    {
      title: 'Fill in the rest',
      body: 'Each field left empty follows the space’s SignPlus settings, the same as the form on the page.',
    },
    {
      title: 'Save the flow',
      body: 'There is no Save button inside the step. The flow builder saves it with the rest of the flow, with Save and enable.',
    },
  ]}
/>

### Choosing the page

The **Space** and **Page** pickers suit a flow that always signs the same page, such as a policy
every new starter signs. For a flow that works the page out from the work item it runs on, turn
on **Enter a page ID or smart value instead** and give a page id or a smart value that resolves to
one, such as `{{issue.customfield_10050}}` for a field holding the page id.

## Start a signing from a flow

The step is laid out in sections, like the form on the page.

| Section | What it holds |
|---|---|
| **Page** | The page, picked or given as an id or smart value |
| **Signers** | Everyone invited when the flow runs |
| **Document** | **Document name**, **Format** and **Message to signers**. An empty name takes the page title, with a number added if the page already has a document by that name |
| **Deadline** | When the signing should be finished, if at all |
| **Page access while it is signed** | **Make the page read-only**, **Restrict page viewing to signers and viewers**, **Include attachments**. The space may overrule each |

### Signers

Add people the way the panel on the page does, without leaving the step: choose **Who to add**
(**Internal user**, **External partner** or **Group**), fill in who, choose the **Role**, and
select **Add signer**. Each one joins the list above, where the role can be changed and the row
removed.

For signers the flow only knows when it runs, turn on **More signers from smart values** and
write them in the field it opens: email addresses separated by commas, `Name <address>` to give a
name, and `[viewer]` after one for a viewer. For example
`{{issue.reporter.displayName}} <{{issue.reporter.emailAddress}}>`. Both lists are sent together.

### Deadline

A fixed date and time, picked with the same date and time pickers as the panel. Select
**Advanced** to give a smart value instead, which is what a flow usually wants: a week from the
moment it runs, or the due date of the work item.

```
{{now.plusDays(7).format("yyyy-MM-dd'T'HH:mmXXX")}}
```

The value must be a date and time with its offset, such as `2026-12-31T17:00+02:00`, and in the
future when the flow runs. **Pick a date instead** goes back to the pickers. An empty deadline
leaves it to the space.

### What later steps can read

**Smart values this action returns**, at the foot of the step, opens the list, each one written
out whole so it can be copied:

```
{{signplusSigning.reference}}       the signing reference
{{signplusSigning.status}}          "pending", or "queued" for a large signing
{{signplusSigning.signerCount}}     how many people were asked
{{signplusSigning.documentName}}    the name the document was given
{{signplusSigning.documentUrl}}     the document that was SENT for signing
{{signplusSigning.documentBase64}}  the same, as base64, up to 4MB
{{signplusSigning.documentDigest}}  its SHA-256, as given to Dokobit
```

**`documentUrl` is not a signed document.** It is what went out for signature. Nobody has signed
anything when this step finishes. For the signed file, use the
[completion webhook](#when-a-signing-completes).

A signing for a group, or for more than 100 people, is sent in the background like one started
from the page. Then `status` is `queued`, `reference` and the document fields are empty, and the
completion webhook is where the signing's reference and its signed file arrive.

### The same from Confluence

Add **Send web request**:

| Field | Value |
|---|---|
| Web request URL | `<your SignPlus address>/v1/signings` |
| Method | POST |
| Headers | `Authorization: Bearer <token>` and `Content-Type: application/json` |
| Body | Custom data, below |
| **Wait for response** | **Ticked** |

```json
{
  "pageId": "{{page.id}}",
  "signers": [
    { "email": "{{initiator.email}}", "name": "{{initiator.displayName}}" }
  ],
  "name": "{{page.title}}"
}
```

Later steps read `{{webhookResponse.status}}`, which is `202`, and
`{{webhookResponse.body.jobId}}`. The signing is prepared in the background, so its reference
arrives with the [completion webhook](#when-a-signing-completes), or from
`GET /v1/pages/{pageId}/signing-jobs/{jobId}`. The address and the token are explained under
[REST API](../rest-api/#before-you-start).

<Aside type="caution" title="Tick Wait for response">
Without it `webhookResponse` is empty. That is Atlassian's behaviour, and it is the most
common reason one of these rules appears to do nothing. An Atlassian OAuth token also
expires after an hour, so a rule that runs occasionally should fetch a fresh one first.
</Aside>

## Export a PDF from a flow

**Export a page as PDF** renders the page with the site's styling and attaches the PDF to it. It
takes the same page picker, a **Document name**, which is what the `{documentName}` placeholder
prints, and **Include attachments**. Later steps can read:

```
{{signplusPdf.downloadUrl}}      where it is attached in Confluence
{{signplusPdf.attachmentName}}   the filename
{{signplusPdf.sizeBytes}}        how big it is
{{signplusPdf.contentBase64}}    the bytes, up to 4MB, empty above that
```

From Confluence, send a POST to `<your SignPlus address>/v1/pages/{{page.id}}/pdf?inline=true`
with the same headers and `{"name":"{{page.title}}"}` as the body, and read
`{{webhookResponse.body.downloadUrl}}`.

**Think before putting `contentBase64` in an email or a work item.** It is the document, and
it will sit in the automation audit log as well as wherever you send it. The URL is
usually the right answer: the recipient fetches it with their own Confluence access.

## Webhooks

SignPlus can notify another system when a signing completes or when a signed page is
edited. Both are set on **Webhooks**, in the global settings, and both work the same way
from Jira and from Confluence.

### When a signing completes

A signing takes minutes or days, so nothing that runs when you start one can hand you the
signed document. This webhook can.

1. In Jira or Confluence, create a rule with an **Incoming webhook** trigger. Atlassian
   gives you a URL and a secret.
2. Add the actions you want, then **publish the rule**. An unpublished rule receives
   nothing.
3. In SignPlus, open **Webhooks**, then **When a signing completes**. Turn it on and paste
   the URL.
4. Add a header named `X-Automation-Webhook-Token` with the secret as its value.
5. Leave **Include the signed document as base64** on, unless you only want the link.
6. Save, and **approve the address in the dialog Atlassian shows**.

The rule then receives:

```json
{
  "event": "signing-completed",
  "pageId": "123456",
  "pageTitle": "Supplier terms",
  "pageUrl": "https://your-site.atlassian.net/wiki/spaces/.../pages/123456",
  "spaceName": "Legal",
  "reference": "a3f9c2d1...",
  "documentName": "Supplier agreement.pdf",
  "documentUrl": "https://your-site.atlassian.net/wiki/download/attachments/123456/Supplier%20agreement.pdf?version=1&api=v2",
  "documentBase64": "JVBERi0xLjcK...",
  "sizeBytes": 184320,
  "signedVersion": 7,
  "completedAt": "2026-09-19T09:24:00.000Z",
  "progress": { "total": 1, "required": 1, "signed": 1, "declined": 0 },
  "signers": [
    { "name": "Anna Tamm", "status": "signed", "signedAt": "2026-09-19T09:20:00.000Z" }
  ],
  "signersTruncated": false
}
```

It is sent once per signing. `signers` names the first 500 people; on a larger signing
`signersTruncated` is `true`, `progress` still counts everybody, and the
[REST API](../rest-api/) lists the rest.

It carries names and times, and **no email addresses or personal codes**: an archive or a
countersignature step needs the first and not the second. Above 4MB, `documentBase64` is
`null` and the URL is still there.

### When a signed page is edited

**Webhooks**, then **When a signed page is edited**. The same address, headers and
approval:

```json
{
  "event": "signed-page-modified",
  "pageId": "123456",
  "pageTitle": "Supplier terms",
  "pageUrl": "https://your-site.atlassian.net/wiki/spaces/.../pages/123456",
  "spaceName": "Legal",
  "reference": "a3f9c2d1...",
  "signingStatus": "completed",
  "signedVersion": 7,
  "currentVersion": 8,
  "modifiedAt": "2026-09-19T11:02:00.000Z"
}
```

Identifiers and version numbers only, no content. It is the same fact the panel on the
page reports. A useful rule on it notifies the space owner and starts a fresh signing, so
the new version gets signed too.

<Aside type="note" title="Why Atlassian asks you to approve the address">
A Forge app can only reach the hosts its manifest names, and a webhook address is typed in
after install. So SignPlus asks Atlassian for permission to reach it, and **Atlassian**
shows your administrator a dialog naming the host. Confirm it and the setting saves.
Cancel it and nothing is stored, so there is never a webhook that silently never fires.
You can withdraw the approval later in Atlassian Administration without touching SignPlus.
</Aside>

## When something does not work

| What you see | Usually |
|---|---|
| The SignPlus action is not in the Confluence rule builder | Expected. The components are Jira's; use Send web request in Confluence |
| The SignPlus action is not in the Jira flow builder either | SignPlus is not connected to Jira yet. See [connecting Jira](../install/#connecting-jira) |
| The step asks to connect | Select **Connect**. Atlassian asks before SignPlus can be used in a flow for the first time |
| The Page picker lists nothing | You cannot see any page in that space, or nothing matches what you typed. Turn on **Enter a page ID or smart value instead** to give the id |
| The rule runs and nothing happens | **Wait for response** is not ticked, or the rule is not published |
| `403` from the action | SignPlus cannot edit that page. Check the page restrictions |
| `401` from a web request | The token has expired. They last an hour |
| `400` about a format, a message or a deadline | The space's SignPlus settings forbid what the rule asked for |
| The webhook never arrives | The address was not approved in Atlassian's dialog, or the receiving rule is not published |
| `{{webhookData.documentBase64}}` is empty | The document is over 4MB, or **Include the signed document** is off |
| The signed document is watermarked | The site is in test mode. See [signing mode](../configure/#signing-mode) |

The rule's audit log shows what each step sent and received. SignPlus's own side is on
**Logs**, in the global settings, which records every API request, every notification sent
onwards and every automation action.

## What a rule cannot do

- **Sign on somebody's behalf.** A rule sends the request; only the signer can sign.
- **Get a signed document when a signing starts.** There is nothing signed yet.
- **Reach a page SignPlus itself cannot.**
- **Overrule the space's settings.** A rule is checked against them every time.

## Related

- [REST API](../rest-api/)
- [Sign a page](../sign-a-page/)
- [Privacy and data handling](../privacy/)

---

A problem or a question? Write to [support@oktul.com](mailto:support@oktul.com) or open a request in the [Help Center](https://oktul.atlassian.net/servicedesk/customer/portals). Both reach the same service desk, so either way the request gets a reference and an SLA measuring the response.
