Marketing
When Marketing is included in your purchase, staff plan and publish social posts across connected channels from the admin — campaigns, an approval queue, a calendar, and per-post metrics. See Marketing for what the domain owns underneath.
Open Marketing (admin.your-domain.com/dashboard/marketing).
Connect a channel
Section titled “Connect a channel”Marketing → Channels. Each channel — Meta (Facebook page + optional
linked Instagram), LinkedIn, or X — connects through its own Connect
dialog: it opens that platform’s own authorization screen in a new tab, and
you paste the resulting code back to finish the link. A connected channel
shows a status pill (connected, pending, disconnected, or
error, with a reason); Disconnect unlinks it without deleting any
posts already sent through it. Connecting or disconnecting needs
marketing.manage_channels.
Create the app on each platform
Section titled “Create the app on each platform”Someone with access to the deployment’s .env does this once, before any
store can connect that channel.
Meta (Facebook + Instagram)
- At developers.facebook.com, create an app of type Business.
- Add the Facebook Login for Business and Instagram Graph API products.
- Under Facebook Login → Settings, add your API host’s callback page as a
valid OAuth redirect URI — it must match
META_REDIRECT_URIexactly. - Request these scopes:
pages_show_list,pages_manage_posts,pages_read_engagement,instagram_basic,instagram_content_publish,business_management. Anything beyond what your own account/team can test with needs Meta’s App Review (Advanced Access) before a real customer’s page can grant it. - Copy the App ID and App Secret into the deployment’s
.envasMETA_APP_ID,META_APP_SECRET, andMETA_REDIRECT_URI.
Personal profiles and company pages use separate LinkedIn apps. Keep the personal app’s settings when adding a company app:
| Connection type | App products | Permissions requested |
|---|---|---|
| Personal profile | Share on LinkedIn and Sign In with LinkedIn using OpenID Connect | openid, profile, w_member_social |
| Company page | Community Management API | w_organization_social |
For personal profiles:
- At the LinkedIn Developer Portal, create an app associated with your organization.
- Add the Sign In with LinkedIn using OpenID Connect and Share on LinkedIn products.
- Add your callback URL as an authorized redirect URL — it must match
LINKEDIN_REDIRECT_URIexactly. - Set
LINKEDIN_APP_ID,LINKEDIN_APP_SECRET, andLINKEDIN_REDIRECT_URIin the deployment environment.
For company pages:
- Create a separate app associated with the company page. A Page super admin must verify the app.
- Under Products, request Community Management API access. LinkedIn requires an app without other provisioned products or pending product requests for this Development-tier application. Keep Share on LinkedIn and Sign In with LinkedIn using OpenID Connect on the personal app.
- Complete LinkedIn’s access review. Requesting the product does not grant its permissions until LinkedIn approves access. See the official Community Management access rules and app review requirements.
- Set the company app’s credentials and callback URL in the deployment environment:
| Setting | Value |
|---|---|
LINKEDIN_COMPANY_APP_ID |
Client ID from the company app |
LINKEDIN_COMPANY_APP_SECRET |
Client secret from the same company app |
LINKEDIN_COMPANY_REDIRECT_URI |
Authorized callback URL registered on the company app; defaults to LINKEDIN_REDIRECT_URI when unset |
For example, the callback can be
https://api.your-domain.com/api/v1/marketing/admin/linkedin/callback/.
Register the exact URL under the company app’s Auth settings. Enter
secrets through the deployment’s environment settings, never in a post or
the channel dialog.
The company flow requests only w_organization_social; it does not require
OpenID Connect products. The app must have company-posting access and the
authorizing member must have an appropriate role on the page. See
LinkedIn’s posting permissions.
Missing company app configuration shows an error when Company page is
selected; it does not use the personal app instead.
X
- At developer.x.com, create a project and app with OAuth 2.0 enabled (PKCE — Nudova handles the code challenge/verifier itself).
- Add your callback URL, matching
X_REDIRECT_URIexactly. - Scopes requested:
tweet.read,tweet.write,users.read,offline.access(the last one is what lets Nudova refresh the token without asking a person to reauthorize). - Set
X_APP_ID,X_APP_SECRET,X_REDIRECT_URI.
Connect it in Nudova
Section titled “Connect it in Nudova”Once the app exists, a store owner or manager with marketing.manage_channels
finishes the link from Marketing → Channels:
- Open the provider’s Connect dialog. For LinkedIn, choose Connect as and complete the account fields described below before continuing.
- Choose Continue to open the platform’s consent screen in a new tab. Approve access there.
- The platform redirects to your configured callback URL with a
codein the address bar. Paste that value into Nudova’s OAuth code field. - Meta only — also paste the Facebook Page ID, Page name, Instagram Business Account ID, and Instagram username you’re connecting. Nudova doesn’t call the Graph API to list your pages for you; find these in Meta Business Suite → Settings, or the Graph API Explorer.
- Choose Complete connection. X needs no additional account fields; it posts as the account that approved the consent screen.
LinkedIn account types
Section titled “LinkedIn account types”In Connect LinkedIn, Connect as explicitly selects the destination:
| Choice | Fields shown | Publishing destination |
|---|---|---|
| Personal profile | Optional member display name | The personal profile that authorizes the connection |
| Company page | Required numeric organization ID and optional organization name | The company page identified by that ID |
For a company page, enter its positive numeric ID from LinkedIn’s page
admin tools before choosing Continue to LinkedIn. A vanity URL such as
linkedin.com/company/your-company is not the numeric ID. Sign in with the
LinkedIn profile of a member who has permission to post for that page; the
connected destination is the page.
Changing the account type or organization ID clears an old authorization code. Start authorization again for the destination you selected. Connecting a company page creates that page’s channel; it does not also create a personal-profile channel.
New connections remember which app issued their credentials so refresh and disconnect use the same app. Existing connections made before separate app support continue using the original app settings. Connect again to create a company grant through the new company app.
LinkedIn connection errors
Section titled “LinkedIn connection errors”unauthorized_scope_errorforw_organization_social— LinkedIn has not authorized this permission for the selected app. Check Community Management approval and the company app credentials. Requesting this scope on the personal app or retrying consent does not grant access.- Company app is not configured — ask the deployment operator to set the company app settings above. Personal connections can still use their original app.
- Organization ID required — enter a positive numeric page ID in Company page mode. An empty company ID cannot complete as a personal connection.
- Company-posting permission was not granted — complete a fresh authorization through the approved company app. A personal-only grant cannot complete a company connection.
Campaigns
Section titled “Campaigns”Marketing → Campaigns. A campaign is a name, an objective (awareness, engagement, traffic, conversions, other), a status, and a start/end window — a folder you group posts under, not a workflow of its own.
Composing a post
Section titled “Composing a post”Marketing (the root screen) or + New post. A post is a body, an optional link, one channel, an optional campaign, and an optional schedule time. A post can also arrive from another domain — for example a published Blog article promoted to a channel — tagged with where it came from, without Marketing needing to know anything about Blog.
The post’s Channel determines the account that publishes it. For LinkedIn, select the intended personal-profile or company-page channel; setting up a company app or connecting a page does not change existing posts’ channels. Update the channel on unpublished posts before publishing. Previously published posts are not moved between accounts.
Publish errors and attached images
Section titled “Publish errors and attached images”If publishing is rejected, the post composer shows Last publish failed with the failure reason. Read that reason before trying again; connection, permission, approval, and attachment problems require different fixes.
For LinkedIn, attached images are read through the deployment’s configured file storage and then uploaded to LinkedIn. Publishing does not require a public CDN download of those attachments. If the stored image cannot be read, reattach it or ask the operator to restore storage access. A CDN access error alone does not establish whether the stored file is missing.
Submit → approve → publish
Section titled “Submit → approve → publish”Posts move through a fixed lifecycle; which actions you see depend on your permissions and where the post already is:
draft → submitted → approved → published
- Save while still drafting (
marketing.edit). - Submit for review hands it to the approval queue — only a
draftor a previouslyfailedpost can be submitted (marketing.edit). - Approve and Publish are separate buttons, but they run on the
same permission,
marketing.publish. Approving records who approved it and (for an AI-generated post, when review is required) runs it past a brand guardrail check before the status flips toapproved.
Marketing → Approval lists everything waiting on a reviewer, with the channel and current status on each row, and Approve/Publish actions right there so a reviewer doesn’t have to open every post individually.
Calendar
Section titled “Calendar”Marketing → Calendar lays out scheduled and published posts by date — the same posts as the list view, arranged for “what’s going out this week” rather than “what needs my review.”
Metrics
Section titled “Metrics”Once a post is published, its detail page grows a metrics panel: impressions, reach, clicks, engagements, and shares, with the time they were last pulled from the channel. A post with nothing published yet, or a channel that hasn’t reported back, shows empty rather than zeroed — Nudova never invents a number the platform hasn’t sent.
Autopilot
Section titled “Autopilot”When marketing.autopilot is on the license, Marketing → Autopilot adds
scheduled content plans, pipeline history, and Autopilot settings (weekly
cap and event-source allowlist). Create a plan with a timezone, visual
schedule (repeat + run hours), channel, publish mode, and autonomy. Optional
research runs a web search before drafting and reuses Blog Autopilot search
keys when enabled. Autonomy chooses the gate outcome: draft, submit for
review, or brand-guardrail + schedule. Those posts still use Marketing’s
post model and scheduled publish worker; they do not import Blog domain
models. Event-driven promotion (for example after a blog article publishes)
only runs when the event name is allowlisted and the payload includes an
absolute public URL. See Marketing Autopilot.
Permissions
Section titled “Permissions”Six permissions, each gating a different slice of the workflow:
| Permission | Covers |
|---|---|
marketing.view |
Read posts, campaigns, channels, approval queue, calendar, settings. |
marketing.create |
Create a post or a campaign. |
marketing.edit |
Edit a post or campaign; submit a post for review. |
marketing.publish |
Approve and publish — one permission covers both buttons. |
marketing.manage_channels |
Connect or disconnect Meta, LinkedIn, or X. |
marketing.manage_settings |
Change require_review, the default autonomy level, and the monthly post cap. |
There’s no separate “approver” permission distinct from “publisher” — anyone
who can approve a post can also publish it directly. If you want a real
maker/checker split, give the composer’s role marketing.create +
marketing.edit only, and keep marketing.publish on a second role. Grant
these through Users & roles.
Related: Marketing · Blog / journal · CRM · Entitlements · Users & roles.