Pipedream receives store events with its HTTP / Webhook trigger, and can check their signatures and call the store in a Node.js code step.
1. Paid order → Google Sheets row
Catch the event
- In Pipedream, create a workflow. For the trigger, choose HTTP / Webhook → New Requests and save it. Pipedream shows the endpoint URL: copy it.
- In the store's admin, open Configuration → Integration Hub → Webhooks → Add webhook and choose
Zapier, Make or n8n.
- Name: "Pipedream: orders"
- URL: the endpoint you copied
- Events: only
order.paid - Save, and copy the signing secret it shows once.
- Send a sample: open Preview, choose
order.paid, an order and the Pipedream webhook, click Show message and then Send to this webhook. The event appears in the trigger; select it.
Check the signature
Pipedream gives the raw body to code steps, so you can refuse messages that didn't come from the store. In the
workflow's Settings → Environment variables (or your project's), add CARTENVO_SECRET with the signing secret,
make the trigger's HTTP Response "Return a custom response from your workflow", then add a Node.js step:
import crypto from 'crypto';
export default defineComponent({
async run({ steps, $ }) {
const event = steps.trigger.event;
const raw = typeof event.body === 'string' ? event.body : JSON.stringify(event.body);
const timestamp = event.headers['x-cartenvo-timestamp'];
const expected = 'sha256=' + crypto.createHmac('sha256', process.env.CARTENVO_SECRET)
.update(`${timestamp}.${raw}`).digest('hex');
const signature = event.headers['x-cartenvo-signature'] ?? '';
const fresh = Math.abs(Date.now() / 1000 - Number(timestamp)) <= 300;
const valid = fresh && signature.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
await $.respond({ status: valid ? 200 : 401, body: valid ? 'ok' : 'bad signature' });
if (!valid) return $.flow.exit('Not signed by the store');
return typeof event.body === 'string' ? JSON.parse(event.body) : event.body;
},
});The signature is over the raw body exactly as sent. Set the trigger to pass the raw body (its event data setting):
rebuilding the body with JSON.stringify can change numbers such as 132.00 and fail the check.
Add the row
Add the Google Sheets app's add-row action, connect your Google account, choose the spreadsheet, and fill the
columns from the previous step (steps.check_signature.$return_value.data.number and so on):
| Column | Value |
|---|---|
| Order | data.number |
| Customer | data.customer.firstName and data.customer.lastName |
data.customer.email | |
| Total | data.totals.total |
| Items | {{steps.check_signature.$return_value.data.items.map(i => i.sku).join(", ")}} |
Deploy the workflow.
2. New order → Slack message
Another workflow (or the same one, with order.placed added to the webhook's events and a filter on type), then the
Slack app's send-message action with:
New order {{steps.check_signature.$return_value.data.number}}: {{steps.check_signature.$return_value.data.totals.total}} {{steps.check_signature.$return_value.data.currency}}3. Calling the store
Add an API key in admin under API keys, store it as the environment variable CARTENVO_KEY, and call the API from
a Node.js step:
export default defineComponent({
async run({ steps, $ }) {
const response = await fetch('https://shop.example.com/api/cartenvo/v1/stock', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CARTENVO_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': steps.trigger.context.id,
},
body: JSON.stringify({ lines: [{ sku: 'MUG-01', adjustment: -1 }] }),
});
return await response.json();
},
});The Idempotency-Key makes a retried step safe: the store applies the change once. The API guide lists
every call.
Things to know
- Repeats: the store retries a delivery that fails or times out, with the same
id. Use it with Pipedream's data stores to skip an event you've already handled. - Samples: messages from Send to this webhook have
context.sample= true.