REST API reference
All paths are relative to https://shopify.workflow-transactional-email.app. Every endpoint except the index needs Authorization: Bearer fak_... - see Authentication and API keys.
Responses are JSON. Errors use the same shape throughout:
{ "error": "Invalid or missing API key" }Index and identity
| Method | Path | Level | Purpose |
|---|---|---|---|
| GET | /api/v1 |
none | API index. Confirms the API is up and reports the current release |
| GET | /api/v1/me |
read | Check a key works and see its access level |
The index needs no key, so it is a safe health check to point a monitor at.
HTTP requests
| Method | Path | Level | Purpose |
|---|---|---|---|
| GET | /api/v1/http-requests |
read | List HTTP request actions |
| POST | /api/v1/http-requests |
write | Create one |
| GET | /api/v1/http-requests/:id |
read | Get one |
| PUT / PATCH | /api/v1/http-requests/:id |
write | Update one |
| DELETE | /api/v1/http-requests/:id |
write | Delete one |
| POST | /api/v1/http-requests/:id/test |
execute | Run it against the real target |
List accepts page (default 1), limit (default 25, max 100) and q to search by name.
The target url must be http:// or https://. Other schemes are rejected when you save.
Literal credentials written into a header or body are masked in every response. Values referenced as {{ secrets.KEY }} are returned as written, because the reference itself is not sensitive.
Email layouts and senders
| Method | Path | Level | Purpose |
|---|---|---|---|
| GET | /api/v1/email-templates |
read | List email layouts |
| GET | /api/v1/email-templates/:id |
read | Get one layout, including its rendered body |
| GET | /api/v1/smtp-configs |
read | List SMTP senders |
| GET | /api/v1/senders |
read | List connected mailboxes (Microsoft 365, Google) |
Layouts accept the same page, limit and q parameters as HTTP requests.
SMTP configurations report hasUsername and hasPassword rather than the credential itself - both halves are withheld, since a username is as much a part of the credential as the password. A configuration stays identifiable by its name, host and from-address. Connected mailboxes report a partially masked address such as so***@example.com and never their OAuth tokens.
Secrets
| Method | Path | Level | Purpose |
|---|---|---|---|
| GET | /api/v1/secrets |
read | List secret names and descriptions |
Returns hasValue, never the value. There is no endpoint that reads a secret back. Create and update secrets in the app.
History and statistics
| Method | Path | Level | Purpose |
|---|---|---|---|
| GET | /api/v1/history |
read | List executed actions |
| GET | /api/v1/history/:id |
read | Get one execution with request and response data |
| GET | /api/v1/stats |
read | Totals and success rate |
History accepts page, limit (max 100), actionType (HTTP_REQUEST or EMAIL), status, and actionConfigId to filter to a single action.
Stats accepts days (default 30, max 365).
Status codes
| Code | Meaning |
|---|---|
| 200 | Success |
| 201 | Created |
| 400 | Malformed request or failed validation |
| 401 | Missing, malformed or revoked API key |
| 403 | Key is valid but its level is too low for this endpoint |
| 404 | Not found, or belongs to a different shop |
| 429 | Rate limited - see below |
| 502 | The action ran but the third-party target failed |
A record belonging to another shop returns 404 rather than 403, so the API never confirms that an id exists elsewhere.
Rate limits
Two independent budgets, both per key:
- 300 requests per 60 seconds across all endpoints.
- 60 execute calls per hour on top of that, covering
POST /api/v1/http-requests/:id/test.
Exceeding either returns 429 with an explanatory error. The execute budget is deliberately tight: a runaway loop firing live requests at a payment provider is a much worse failure than a slow script.
Budgets are per key, not per store, so one integration cannot exhaust another's allowance.

