Skill Tracer
Skills › Knowledge Work Plugins › canva-creator › hubspot-staging.md

hubspot-staging.md

137 lines · small-business/skills/canva-creator/reference/hubspot-staging.md at 2574e29

Open on GitHub
1# HubSpot Campaign Staging Reference
2
3Requires: **HubSpot Marketing Hub Professional** (or higher).
4Base URL: `https://api.hubapi.com`
5Auth: Bearer token (OAuth 2.0 or private app token).
6
7---
8

HubSpot Campaign Staging Reference

Requires: HubSpot Marketing Hub Professional (or higher). Base URL: https://api.hubapi.com Auth: Bearer token (OAuth 2.0 or private app token).


Raw lines 1 to 8
9## Table of contents
111. [Tier check](#tier-check)
122. [Create a campaign](#create-a-campaign)
133. [Create a social post](#create-a-social-post)
144. [Verify the scheduled queue](#verify-the-scheduled-queue)
155. [CSV fallback (non-Professional users)](#csv-fallback-non-professional-users)
166. [Field reference](#field-reference)
18---

Table of contents

  1. Tier check
  2. Create a campaign
  3. Create a social post
  4. Verify the scheduled queue
  5. CSV fallback (non-Professional users)
  6. Field reference

Raw lines 9 to 19
20## Tier check
22If you're unsure whether the user has Marketing Hub Professional:
24```
25GET /crm/v3/objects/companies?limit=1
26```
28Check the `subscriptionType` on the account. If the API returns a 403 on
29social endpoints, tell the user: "HubSpot campaign staging requires Marketing
30Hub Professional. Your current plan doesn't include it. I can export a
31scheduling CSV instead — would that work?"
33---

Tier check

If you're unsure whether the user has Marketing Hub Professional:

GET /crm/v3/objects/companies?limit=1

Check the subscriptionType on the account. If the API returns a 403 on social endpoints, tell the user: "HubSpot campaign staging requires Marketing Hub Professional. Your current plan doesn't include it. I can export a scheduling CSV instead — would that work?"


Raw lines 20 to 34
35## Create a campaign
37```
38POST /marketing/v3/campaigns
40 "name": "Summer Sale 2026 — Social",
41 "startDate": "2026-06-01",
42 "endDate": "2026-06-30",
43 "currencyCode": "<Currency from the Business context block, e.g. AUD>",
44 "utm": {
45 "source": "social",
46 "medium": "owned",
47 "campaign": "summer-sale-2026"
48 }
50```
52Response: `{ "id": "<campaign_id>", ... }` — save this for social post association.
54---

Create a campaign

POST /marketing/v3/campaigns
{
  "name": "Summer Sale 2026 — Social",
  "startDate": "2026-06-01",
  "endDate":   "2026-06-30",
  "currencyCode": "<Currency from the Business context block, e.g. AUD>",
  "utm": {
    "source": "social",
    "medium": "owned",
    "campaign": "summer-sale-2026"
  }
}

Response: { "id": "<campaign_id>", ... } — save this for social post association.


Raw lines 35 to 55
56## Create a social post
58One call per calendar row. Stage as `SCHEDULED`, never `PUBLISHED`.
60```
61POST /marketing/v3/social/posts
63 "campaignId": "<campaign_id>",
64 "channelId": "<hubspot_channel_id>",
65 "content": {
66 "body": "<approved caption text>"
67 },
68 "scheduledAt": "2026-06-03T10:00:00Z",
69 "attachments": [
70 {
71 "url": "<canva_export_png_url>"
72 }
73 ],
74 "status": "SCHEDULED"
76```
78**`channelId`** — the HubSpot Social account ID (not the platform name).
79Retrieve connected accounts:
80```
81GET /marketing/v3/social/channels
82```
83Match by `type` (`INSTAGRAM`, `FACEBOOK`, `TWITTER`, `LINKEDIN`) and use the `id` field.
85**`scheduledAt`** — must be in the future (relative to the time of the API
86call). Use noon local time for the owner's timezone unless they specify
87otherwise.
89---

Create a social post

One call per calendar row. Stage as SCHEDULED, never PUBLISHED.

POST /marketing/v3/social/posts
{
  "campaignId": "<campaign_id>",
  "channelId":  "<hubspot_channel_id>",
  "content": {
    "body": "<approved caption text>"
  },
  "scheduledAt": "2026-06-03T10:00:00Z",
  "attachments": [
    {
      "url": "<canva_export_png_url>"
    }
  ],
  "status": "SCHEDULED"
}

**channelId** — the HubSpot Social account ID (not the platform name). Retrieve connected accounts:

GET /marketing/v3/social/channels

Match by type (INSTAGRAM, FACEBOOK, TWITTER, LINKEDIN) and use the id field.

**scheduledAt** — must be in the future (relative to the time of the API call). Use noon local time for the owner's timezone unless they specify otherwise.


Raw lines 56 to 90
91## Verify the scheduled queue
93After staging all posts:
95```
96GET /marketing/v3/social/posts?status=SCHEDULED&campaignId=<campaign_id>
97```
99Surface results in a table: date, channel, first 60 chars of caption, status.
100Provide the direct HubSpot campaign URL:
101`https://app.hubspot.com/content/{portalId}/social/campaigns/{campaign_id}`
103Tell the user: "Posts are scheduled and will publish automatically. You can
104cancel or edit any post in HubSpot before the send time."
106---

Verify the scheduled queue

After staging all posts:

GET /marketing/v3/social/posts?status=SCHEDULED&campaignId=<campaign_id>

Surface results in a table: date, channel, first 60 chars of caption, status. Provide the direct HubSpot campaign URL: https://app.hubspot.com/content/{portalId}/social/campaigns/{campaign_id}

Tell the user: "Posts are scheduled and will publish automatically. You can cancel or edit any post in HubSpot before the send time."


Raw lines 91 to 107
108## CSV fallback (non-Professional users)
110When HubSpot staging is not available, export a CSV the user can import into
111Buffer, Later, or their scheduler of choice.
113Column headers:
114```
115Date,Time,Channel,Caption,ImageURL,Status
116```
118Example row:
119```
1202026-06-03,10:00 AM CDT,Instagram,"Summer Sale: 30% off candles ☀️ ...",https://canva.com/export/...,Scheduled
121```
123Tell the user: "I've prepared a scheduling CSV since your HubSpot plan doesn't
124include social staging. You can import this into Buffer or Later. [file path]"
126---

CSV fallback (non-Professional users)

When HubSpot staging is not available, export a CSV the user can import into Buffer, Later, or their scheduler of choice.

Column headers:

Date,Time,Channel,Caption,ImageURL,Status

Example row:

2026-06-03,10:00 AM CDT,Instagram,"Summer Sale: 30% off candles ☀️ ...",https://canva.com/export/...,Scheduled

Tell the user: "I've prepared a scheduling CSV since your HubSpot plan doesn't include social staging. You can import this into Buffer or Later. [file path]"


Raw lines 108 to 127
128## Field reference
130| Field | Type | Notes |
131|-------|------|-------|
132| `campaignId` | string | UUID from campaign creation |
133| `channelId` | string | From `GET /social/channels` |
134| `content.body` | string | Caption text; max 2,000 chars |
135| `scheduledAt` | ISO 8601 | Must be future time; include timezone offset |
136| `attachments[].url` | string | Public URL (Canva export URL works) |
137| `status` | enum | Always `"SCHEDULED"` — never `"PUBLISHED"` |

Field reference

FieldTypeNotes
campaignIdstringUUID from campaign creation
channelIdstringFrom GET /social/channels
content.bodystringCaption text; max 2,000 chars
scheduledAtISO 8601Must be future time; include timezone offset
attachments[].urlstringPublic URL (Canva export URL works)
statusenumAlways "SCHEDULED" — never "PUBLISHED"
Raw lines 128 to 137