Delivery and runs
Send each rendered file to a link list, your webhook or a Slack channel, then test, run and cancel a workflow and read its run history when something fails.
After a workflow renders a row, its deliver steps send the file on. This page covers the three deliveries, then how runs work: testing, the run history, canceling, what happens when something fails, and how to hear about it.
Deliveries
To add one, use + Add a delivery under the render step. To remove one, select it and click Remove this step.
- A workflow needs at least one delivery. Render URL is the simplest.
- You can add several. Every rendered row goes through each of them, in order.
- If one delivery fails, the others still run.
- Each delivery counts as one step toward your plan’s step limit.
| Delivery | What it does |
|---|---|
| Render URL | Keeps a link to each file in the run history and in the API. |
| Send to a webhook | Sends each row and its file links to your URL as JSON. |
| Post to Slack | Posts a message with the image to a Slack channel. |
Render URL
Each render’s file link is kept with its row. You see the files in the Run history tab, and your code gets them from the Workflows API. Links work for an hour each time you open the run history or read the run, and the files are deleted 8 days after the render. See How long files last.
Send to a webhook
JamFrame sends a POST request to your URL for each rendered row.
- Click + Add a delivery and pick Send to a webhook.
- Under Webhook URL, type your endpoint, such as
https://hooks.example.com/renders. It must usehttps://and be reachable from the internet. - Save.
The body is JSON:
{
"event": "workflow.row.rendered",
"workflow": { "id": "cm3k9x2ab0001", "name": "Quote cards" },
"run": { "id": "cm3k9y7cd0004", "trigger": "schedule" },
"row": {
"index": 0,
"values": { "Quote": "Stay hungry", "Author": "Jobs" }
},
"render": {
"id": "cm3k9z1ef0007",
"format": "png",
"url": "https://cdn.jamframe.com/renders/…/0.png?Expires=…",
"urls": ["https://cdn.jamframe.com/renders/…/0.png?Expires=…"]
}
}
row.indexcounts from 0 in the run.row.valuesholds every column of the row.render.urlis the first file.render.urlshas one link per file, for example one per page.run.triggerismanual,schedule,webhook,new_rowsorapi.
The request has the headers Content-Type: application/json and User-Agent: JamFrame-Webhook/1. It
isn’t signed. To check that a call comes from your workflow, put a long secret in the URL, such as
https://hooks.example.com/renders?token=…, and check it on your side.
Any 2xx answer counts as delivered. If your endpoint doesn’t answer within 10 seconds, can’t be reached,
or answers 429 or 5xx, JamFrame tries once more after 2 seconds. Other answers aren’t tried again.
Post to Slack
Posts one message per row to a Slack channel, with the image.
- In Slack, add an incoming webhook to your channel: Apps → Incoming Webhooks → add it to a
channel. Copy its URL. It starts with
https://hooks.slack.com/services/. - In the builder, click + Add a delivery and pick Post to Slack.
- Paste the URL under Slack incoming webhook URL. It’s stored encrypted, and afterwards the box only says it’s saved. Type a new URL to replace it.
- Optional: write the Message. Leave it empty for “New render from” followed by the workflow’s name and the link.
- Save.
In the message, you can use:
| You write | Becomes |
|---|---|
{{Column}} |
The row’s value in that column, such as {{Name}} |
{{render.url}} |
The link to the file |
{{render.id}} |
The render’s id |
For example: New quote card for {{Author}}: {{render.url}}. A message can be up to 3,000 characters.
PNG, JPEG and WebP images show in the message itself. For a PDF, the message has only the link, which
works for 7 days.
If Slack refuses the message because the webhook was removed or its channel archived, the delivery fails and says so. Make a new incoming webhook in Slack and paste its URL.
Runs
A run reads the source once, applies the transforms, then renders and delivers row by row.
Start a run
- Run Now starts a run with every row.
- Test with 1 row starts a run with only the first row. Use it to check the mapping and the deliveries before you render everything.
Both save your changes first, and both open the Run history tab. While a run is going, the list updates every few seconds.
A run needs render credits to start. A test run counts as a run toward your plan’s runs a month, and its row uses credits like any render.
Read the run history
Click the Run history tab under the steps. Runs are listed newest first. Each one shows:
- its status (below), when it started and what started it: Run Now, Schedule, Webhook, New rows or API;
- the rows that went through out of all rows, then the failed rows, the skipped rows and the credits;
- the reason, when the run stopped early;
- notes, such as “Test run: only the first 1 row ran.” or a note that your plan’s rows-per-run limit left rows out.
Click a run to see each row: its row number, its status, its first values, its images (click one to open it), the error if it failed, and the outcome of each delivery with its message. Click Older runs at the bottom to see more.
| Run status | What it means |
|---|---|
| Queued | Waiting to start, for example behind other runs. |
| Running | Rendering and delivering rows. |
| Succeeded | Every row rendered and delivered. |
| Partly succeeded | Some rows failed, the others went through. |
| Failed | No row went through, or the source couldn’t be read. |
| Canceled | Someone canceled the run. |
| Row status | What it means |
|---|---|
| Waiting | Not started yet. |
| Running | Rendering or delivering now. |
| Succeeded | Rendered, and every delivery worked. |
| Partly succeeded | Rendered, but a delivery failed. |
| Failed | The render failed. No credits were used. |
| Skipped | The run stopped or was canceled before this row. |
Cancel a run
Under a queued or running run, click Cancel run. A row that is rendering finishes. Rows that haven’t started are skipped.
When something fails
| What happens | Result |
|---|---|
| The source has a passing problem, such as a time-out or a busy server | JamFrame tries again after about 1 minute, then after about 5 minutes. If it still fails, the run fails. |
| The source can’t be read, for example a sheet that isn’t shared | The run fails at once. The run history says why. |
| The source is empty, or the transforms leave no rows | The run succeeds with the note “No rows to process”. |
| A row’s render fails, for example a broken image link | That row fails, uses no credits, and the run goes on with the next row. |
| A delivery fails | The row is Partly succeeded. The row’s other deliveries still run. |
| Render credits run out | The run stops. The rows left are skipped. |
| The template was deleted | The run stops. The rows left are skipped. |
Rows that fail aren’t tried again by themselves. Fix the cause, then run the workflow again. Keep in mind that a new run renders every row again, not only the failed ones.
Hear when a run ends
Your server can get a webhook event when a run ends:
workflow.run.completed: the run Succeeded, Partly succeeded or was Canceled.workflow.run.failed: the run Failed.
Subscribe to them on the Webhooks page, under Developers in the sidebar. The event’s data is
the run, with its counts, credits and status, plus workflowName. To set up and check webhooks, see
Webhooks.
Credits
- Each render uses 1 render credit per image, or per page of a PDF.
- Failed renders are free.
- AI layers in the template use AI credits too.
- Deliveries cost nothing.
See Credits.
What next
- Start and check runs from your own code: Workflows API.
- See every render a workflow made: Renders.
Last updated
Still stuck?
Email [email protected] and a real person will reply. Tell us the template you were using and what you expected to happen.