# Triggers

> Running an Oktul Code Studio script on a Jira or Confluence event, a schedule, a Jira automation rule or an HTTP request, and what each hands it.
>
> Documentation for Oktul Code Studio, for Jira Cloud and Confluence Cloud, by Oktul: https://oktul.com/docs/plugins/code-studio/triggers/

Every trigger takes the same path: the server decides the mode, the principal and the script from
stored configuration, stores the run and queues it.

- **Where:** the console's Listeners, Schedules and API triggers, a script's **Where it runs**, or
  the run panel's **Triggers** tab.
- **Who:** only an administrator changes them.

## Listeners

A listener runs a script when a Jira or Confluence event happens: a work item created, updated,
assigned or commented, a page published, a sprint started, an attachment added and the other events
Atlassian's Forge platform delivers. A listener filters on the event, and runs in the sandbox or
in production.

<Figure
  src="/images/docs/code-studio/highlight-listeners.a727c077.webp"
  alt="Listeners: Cost centre on new FIN work items on Work item created, in production and enabled, and Label new pages on Page created, in the sandbox and off."
  caption="Each listener names its events, its script and its mode."
  width={2592}
  height={1718}
/>

- **The event is the one ScriptRunner scripts expect.** Atlassian's events are thin, so before the
  script runs Code Studio fetches what the event names (the whole work item, the page, the user) and
  hands the script the payload Jira's webhook or Confluence Connect would have sent:
  `webhookEvent`, `issue`, `user`, `changelog`, `comment`. A ScriptRunner Connect listener runs
  unchanged. The raw Forge event is `context.forgeEvent`.
- **Each event runs once per listener**, even when Forge delivers it twice.
- **A loop is stopped.** A run caused by another run's change is one deeper; the eleventh in a
  chain is stopped before it does anything, as ScriptRunner stops its eleventh self-triggered run.
- **A failing listener pauses.** After the number of failed production runs in a row set in the
  site settings, it pauses until its script runs successfully in the console.

<Aside type="note" title="Event delivery is Atlassian's">
Atlassian delivers a product event up to 3 minutes after the change, and does not deliver an event
over 200 KB. A run starts when the event arrives.
</Aside>

## Schedules

A schedule runs a published script at the times you pick, in its own time zone. **How often**
offers every few minutes, hourly, daily, weekdays, weekly and monthly in words, or a cron
expression of your own.

<Figure
  src="/images/docs/code-studio/support-schedules.b8d77fae.webp"
  alt="Schedules: Weekday cost centre check, every weekday at 06:00 Europe/Tallinn, with its script, its next run and its mode."
  caption="A schedule in words, with its time zone and next run."
  width={2592}
  height={1718}
/>

A cron expression of your own can be:

- **Standard cron**, five fields: `minute hour day-of-month month day-of-week`, as Unix writes it.
- **Quartz**, six or seven fields with seconds and `?`, as ScriptRunner for Jira Data Center writes
  it. `L`, `W` and `#` are refused with a message.
- `@hourly`, `@daily`, `@weekly`, `@monthly` and `@yearly`.

- **Queued** about ten minutes early and started on its minute. Until then it shows as
  **Scheduled**, with **Cancel**.
- **Deleting a schedule** cancels its waiting runs.
- **Missed** while the app could not run: it runs once, and the schedule moves on from now.
- **Pauses** after failed runs, as a listener does.

## API triggers

An API trigger runs a script from an HTTP request, from another system or a webhook.

- One address for the app, with the trigger named in the query parameter `cc-trigger`.
- Its secret travels as `Authorization: Bearer <secret>`. A secret in the address is refused. Only
  the secret's SHA-256 is stored, compared in constant time.
- `GET` or `POST`. The script's `event` is the request; a JSON body's own fields sit beside it, so a
  webhook-shaped body reads as an event.
- The trigger answers `202` at once, or waits up to 45 seconds and answers with what the script
  returns (`{ statusCode, headers, body }`, or its result as JSON). A run that outlasts the wait is
  read later with `GET` and `cc-run=<id>`, with the same secret.

Calling one:

- **From Code Studio on another site:** a connection of type **An HTTP API**, the address up to the
  `?` as its **Base URL**, **Bearer token** holding the secret.
- **From a Forge app:** declare the trigger's host, keep the address and secret in encrypted
  variables.
- **With curl:** the whole address in quotes.

Code Studio:

```ts
export default async function () {
    return http.post('invoices', '/', { invoice: 'INV-1042' }, {
        query: { 'cc-trigger': '<the trigger id from its address>' },
    });
}
```

Forge:

```js
import { fetch } from '@forge/api';

const response = await fetch(process.env.TRIGGER_URL, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.TRIGGER_SECRET}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ invoice: 'INV-1042' })
});
console.log(response.status, await response.json());
```

curl:

```bash
curl -X POST "$TRIGGER_URL" \
  -H "Authorization: Bearer $TRIGGER_SECRET" \
  -H "Content-Type: application/json" \
  -d '{ "invoice": "INV-1042" }'
```

## Jira automation

**Run a Code Studio script** is an action in Jira automation. It needs Jira: the Jira listing, or
the Confluence listing with Jira connected.

| Input | What it is |
|---|---|
| **Script** | One an administrator allowed for rules |
| **Mode** | `sandbox` or `production`, as allowed for that script |
| **Parameters** | JSON the script receives as `event.params`, smart values included |
| **Wait for the result** | Whether the step waits up to 45 seconds |
| **Work item key**, **Work item ID**, **Rule**, **Initiator** | Smart values the script receives on `event` |

Later steps read the run's `runId`, `status` and, when it finished within the wait, its `result`
as JSON. A failed run fails the step. The rule runs the script as the app.

Their smart values are `{{triggeredCodestudioRun.runId}}`, `{{triggeredCodestudioRun.status}}`
and `{{triggeredCodestudioRun.result}}`.
Jira builds the name from the action and allows no capital inside it, so it reads `Codestudio`.

## Common questions

**What can start a Code Studio script?**

The console, a Jira or Confluence event through a listener, a schedule, a Jira automation rule, or an HTTP request through an API trigger.

**How does an API trigger authenticate a request?**

With its secret, sent as `Authorization: Bearer <secret>`. A secret in the address is refused.

**Can a Confluence automation rule run a script?**

Through an API trigger, with **Send web request**. **Run a Code Studio script** is an action in Jira automation.

**How soon does a listener run after a change?**

When Atlassian delivers the event, up to 3 minutes after the change.

## Related

- [Sandbox and production](../sandbox-and-production/)
- [Fields and forms](../fields-and-forms/)
- [Limits](../limits/)

---

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 open a request with a reference and an SLA.
