Read and write your Gagewire data over plain HTTPS.
One endpoint, a JSON op envelope, and an API key you issue inside Gagewire. No SDK to install, no third-party dashboard — your integration talks to Gagewire directly.
The endpoint and your key.
Every request is a POST to a single URL, with a JSON body describing the operation. Authenticate with a Bearer API key.
POST https://gagewire.com/functions/gagewireApi
Authorization: Bearer gw_live_xxxxxxxxxxxxxxxx
Content-Type: application/json
{
"op": "list",
"entity": "Campaign"
}Keys are issued in-app. An organization owner or admin opens Settings → API keys, creates a labeled key, and copies the plaintext once — it is never shown again. A key is scoped to one organization and acts with admin-level access to that org’s data. Rotate or revoke it any time from the same panel.
One body shape for everything.
Every request body carries an op and an entity, plus the fields each op needs:
{
"op": "filter",
"entity": "Dispatch",
"query": { "brand_id": "BRAND_ID", "status": "ready" },
"sort": "-send_date",
"limit": 20
}| op | extra fields | returns |
|---|---|---|
| list | sort, limit | array |
| filter | query, sort, limit | array |
| get | id | object |
| create | data | object |
| update | id, data | object |
| delete | id | { ok, id } |
| bulkCreate / bulkUpdate | items | array |
Every record carries a brand_id (or organization_id for Brand and DispatchTemplate). Reads are scoped to the organizations your key can access; writes require a contributor role or higher, and Brand/DispatchTemplate writes require admin.
List and filter.
// List recent campaigns in a brand
await fetch("https://gagewire.com/functions/gagewireApi", {
method: "POST",
headers: {
"Authorization": "Bearer " + KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
op: "filter",
entity: "Campaign",
query: { brand_id: BRAND_ID },
sort: "-created_date",
limit: 10,
}),
});Create a dispatch (blocks are canonical).
A dispatch stores its content as ordered blocks. Each block is { type, content, config }. The plain-text content field is a read-only fallback the server derives from your blocks on every write — any value you send is overwritten. The type must be a known dispatch type; unknown types are rejected.
await fetch("https://gagewire.com/functions/gagewireApi", {
method: "POST",
headers: {
"Authorization": "Bearer " + KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
op: "create",
entity: "Dispatch",
data: {
campaign_id: CAMPAIGN_ID,
brand_id: BRAND_ID,
type: "Personal email", // must be a known dispatch type
title: "Launch note",
blocks: [
{ type: "subject", content: "Launch note" },
{ type: "body", content: "<p>We just went live.</p>" },
{ type: "cta", content: "Try it now", config: { url: "https://..." } },
],
},
}),
});To update, send op: "update" with id and the data fields to change. Ownership fields (brand_id, campaign_id, id) can't be re-parented through an update.
Snapshots at send. Setting status to "sent" freezes the outgoing blocks/content as a snapshot, and requires all required blocks to be present (a missing block returns 409). Thereafter, reads of that dispatch return the frozen snapshot, not the live copy — so an integration that records results always measures what actually went out. Send again by moving status back to "ready"; the next send overwrites the prior snapshot.
The entity surface.
Campaignread + writeA planned effort — the brief, channels, dates, status.
CampaignChannelread + writeA channel strategy row — purpose, planned tactics, owner, due date.
Dispatchread + writeChannel-specific copy as structured blocks — the canonical form. content is a derived plain-text fallback; the write type must be a known dispatch type. On a transition into sent, the server freezes the outgoing blocks/content as a snapshot; reads of a sent or archived dispatch return the frozen blocks/content (plus sent_at, sent_by_id), not the live working copy. The sent_* fields are server-derived and cannot be written directly.
CampaignActionread + writeA concrete to-do under a channel in a campaign’s plan.
Resultread + writeWhat happened — metrics, lessons, attribution; links to a channel strategy and, optionally, to a specific sent dispatch whose snapshot it measures.
Contactread + writeA person who might care, with consent flags.
FieldNoteread + writeA short note tied to a campaign, contact or result.
Financial data. Payment and Vendor are not exposed through the REST API. They are internal to Gagewire's vendor-payment workflow and never leave it.
Built-in fields on every record: id, created_date, updated_date, created_by_id.
Status codes.
| 200 | Success — the op result as JSON. |
| 400 | Malformed body, unknown entity or op, unknown dispatch type. |
| 401 | Missing, invalid, or revoked API key. |
| 403 | Key is not valid for the target organization, or role insufficient. |
| 404 | Record not found. |
Errors return { "error": "message" }.