OpenAPI
/api-reference/openapi.json post /api/v1/tools/create_linkedin_image_campaign/execute
openapi: 3.1.0
info:
contact:
email: [email protected]
name: ADSMCP Support
description: >-
REST endpoints for every ADSMCP tool. Same surface as the MCP server, over
plain HTTP for consumers that can't speak SSE (n8n, Zapier, Make, curl, any
language's HTTP client).
## Envelope
Every request wraps tool-specific input in an `arguments` object:
```json
{ "arguments": { <tool-specific fields> } }
```
Every response wraps the result in either a success envelope (`success:
true`, `data: {...}`) or an error envelope (`success: false`, `error:
"..."`, `is_error: true`).
## Authentication
Pass your API key as `Authorization: Bearer sk_live_...` on every request.
Generate keys at https://adsmcp.si/dashboard/api-tokens.
## Quota & billing
Every successful billable call decrements your monthly tool-call allowance.
The current counter is attached to every 200 response under `data.quota`:
```json
"quota": { "used": 42, "limit": 150, "tier": "plus", "period_end":
"2026-05-01" }
```
When the limit is hit, the API returns HTTP 402 with a full `quota` block
including `upgrade_url`. Read-only diagnostic tools (`get_usage_status`,
`list_connected_accounts`, `get_connections_status`) are exempt and never
consume quota.
## Idempotency
Write operations accept an `Idempotency-Key: <uuid>` header. A repeated call
with the same key returns the cached result rather than executing twice.
**Strongly recommended for n8n, Zapier, and any retry-prone client** — it
prevents duplicate campaigns when networks misbehave. Generate a fresh UUID
per logical operation (not per retry).
## Multi-account users
Customers with multiple connected accounts on the same platform (e.g. an
agency with 10 Meta ad accounts) must specify which account to use via
`ad_account_id`, `customer_id`, `advertiser_id`, or `account_id` depending
on the platform. Omitting it returns HTTP 400 with a list of valid account
IDs. See `list_connected_accounts` to discover available IDs.
## HTTP status codes
- `200` — success (parse `data`)
- `400` — tool-level error (surface `error` to users)
- `401` — bad/missing API key
- `402` — ADSMCP quota exhausted
- `404` — unknown tool name
- `429` — upstream ad platform rate-limited us (Meta/Google/etc.) — retry
with backoff
- `500` — server error, report to support
## Streaming
This endpoint is plain request-response JSON. There is **no SSE, no chunked
streaming**. Safe to use from n8n Cloud's HTTP Request node, Zapier
Webhooks, Make HTTP module, curl, and every mainstream HTTP library.
title: ADSMCP REST API
version: 1.0.0
servers:
- description: Production
url: https://api.adsmcp.si
security: []
tags:
- description: Audit tools
name: audit
- description: General (Account Management) tools
name: general
- description: Google Ads tools
name: google-ads
- description: LinkedIn Ads tools
name: linkedin-ads
- description: Meta Ads tools
name: meta-ads
- description: Monitoring & Reporting tools
name: monitoring
- description: TikTok Ads tools
name: tiktok-ads
paths:
/api/v1/tools/create_linkedin_image_campaign/execute:
post:
tags:
- linkedin-ads
summary: Create LinkedIn Image Campaign
description: |
⚠️ STOP - DO NOT CALL THIS TOOL DIRECTLY!
This tool creates REAL LinkedIn campaigns that cost REAL money.
operationId: execute_create_linkedin_image_campaign
parameters:
- description: >-
Client-generated UUID to make writes idempotent. Strongly
recommended for write tools. A repeat call with the same key returns
the cached result instead of re-executing. Example:
550e8400-e29b-41d4-a716-446655440000
example: 550e8400-e29b-41d4-a716-446655440000
in: header
name: Idempotency-Key
required: false
schema:
format: uuid
type: string
requestBody:
content:
application/json:
example:
arguments:
asset_bundle_id: string
call_to_action: LEARN_MORE
campaign_group_id: string
campaign_group_name: string
campaign_name: string
daily_budget: 10
headline: string
image_urn: string
introductory_text: string
landing_page_url: https://example.com
locations:
- string
objective: WEBSITE_VISIT
organization_id: string
schema:
properties:
arguments:
description: Input schema for creating LinkedIn Single Image Ad campaigns
properties:
account_id:
anyOf:
- type: string
- type: 'null'
default: null
description: >-
LinkedIn Ad Account ID (optional - will use primary
account if not provided)
title: Account Id
age_ranges:
anyOf:
- items:
type: string
type: array
- type: 'null'
default: null
description: >-
Optional list of age range URNs. Include-only facet.
Values: urn:li:ageRange:(18,24),
urn:li:ageRange:(25,34), urn:li:ageRange:(35,54),
urn:li:ageRange:(55,2147483647).
title: Age Ranges
asset_bundle_id:
anyOf:
- type: string
- type: 'null'
default: null
description: >-
Asset bundle ID from
validate_and_prepare_linkedin_assets tool. Use this for
NEW image uploads. Mutually exclusive with image_urn.
title: Asset Bundle Id
buyer_groups:
anyOf:
- items:
type: string
type: array
- type: 'null'
default: null
description: >-
Optional list of buyer group URNs (API 2026-03+).
Example: ['urn:li:standardizedProductCategory:1031'].
Target B2B buyers in specific product categories.
title: Buyer Groups
call_to_action:
anyOf:
- type: string
- type: 'null'
default: LEARN_MORE
description: >-
Call-to-action button label. Options: APPLY, DOWNLOAD,
VIEW_QUOTE, LEARN_MORE, SIGN_UP,SUBSCRIBE, REGISTER,
JOIN, ATTEND, REQUEST_DEMO. Default: LEARN_MORE.
title: Call To Action
campaign_group_id:
anyOf:
- type: string
- type: 'null'
default: null
description: >-
Existing Campaign Group ID to add this campaign to (for
multi-audience setups). Pass this to create multiple
campaigns with different targeting under ONE group. Get
this from a prior create_linkedin_*_campaign response.
Format: numeric ID or
urn:li:sponsoredCampaignGroup:XXXXX. If provided,
campaign_group_name is NOT needed.
title: Campaign Group Id
campaign_group_name:
anyOf:
- type: string
- type: 'null'
default: null
description: >-
Name for a NEW campaign group (REQUIRED if
campaign_group_id not provided). This is the top-level
container that groups related campaigns. Example: 'Q2
B2B SaaS Campaign', 'Summer Product Launch'. Max 100
characters.
title: Campaign Group Name
campaign_name:
description: >-
Campaign name (will be automatically suffixed with
timestamp for uniqueness)
title: Campaign Name
type: string
company_sizes:
anyOf:
- items:
type: string
type: array
- type: 'null'
default: null
description: >-
Optional list of company size (staff count range) URNs
to target. URNs use format
urn:li:staffCountRange:(min,max):
1=urn:li:staffCountRange:(1,1),
2-10=urn:li:staffCountRange:(2,10),
11-50=urn:li:staffCountRange:(11,50),
51-200=urn:li:staffCountRange:(51,200),
201-500=urn:li:staffCountRange:(201,500),
501-1000=urn:li:staffCountRange:(501,1000),
1001-5000=urn:li:staffCountRange:(1001,5000),
5001-10000=urn:li:staffCountRange:(5001,10000),
10000+=urn:li:staffCountRange:(10001,2147483647). Note:
staffCountRanges may NOT be AND'ed with employers
targeting.
title: Company Sizes
creative_name:
anyOf:
- type: string
- type: 'null'
default: null
description: >-
Name for the first creative (shown in Campaign Manager
UI). E.g. 'Summer Sale - Ad 1', 'Long Form — Problem
Hook'. If not provided, defaults to '{campaign_name} -
Ad 1'.
title: Creative Name
currency:
anyOf:
- type: string
- type: 'null'
default: USD
description: 'Currency code for budget. Default: USD.'
title: Currency
daily_budget:
description: >-
Daily budget in account currency (minimum 10/day for
LinkedIn). Set currency field if not USD.
minimum: 10
title: Daily Budget
type: number
degrees:
anyOf:
- items:
type: string
type: array
- type: 'null'
default: null
description: >-
Optional list of degree URNs. Example:
['urn:li:degree:700'].
title: Degrees
employers:
anyOf:
- items:
type: string
type: array
- type: 'null'
default: null
description: >-
Optional list of employer (organization) URNs. Example:
['urn:li:organization:1035']. Note: employers may NOT be
AND'ed with industries or staffCountRanges.
title: Employers
end_date:
anyOf:
- type: string
- type: 'null'
default: null
description: >-
Optional campaign end date in ISO format. If not
provided, campaign runs indefinitely until paused.
title: End Date
fields_of_study:
anyOf:
- items:
type: string
type: array
- type: 'null'
default: null
description: >-
Optional list of field of study URNs. Example:
['urn:li:fieldOfStudy:100275'].
title: Fields Of Study
followed_companies:
anyOf:
- items:
type: string
type: array
- type: 'null'
default: null
description: >-
Optional list of followed company (organization) URNs.
Target members who follow specific companies.
title: Followed Companies
genders:
anyOf:
- items:
type: string
type: array
- type: 'null'
default: null
description: >-
Optional list of gender URNs. Include-only facet.
Values: urn:li:gender:MALE, urn:li:gender:FEMALE.
title: Genders
headline:
description: >-
Ad headline (up to 70 characters, REQUIRED). Appears
below the image. Keep it concise and action-oriented.
Ads without headlines perform significantly worse.
maxLength: 70
title: Headline
type: string
image_urn:
anyOf:
- type: string
- type: 'null'
default: null
description: >-
Existing LinkedIn image asset URN from
discover_linkedin_assets tool. Use this to REUSE an
existing image from your LinkedIn asset library. Format:
urn:li:digitalmediaAsset:XXX. Mutually exclusive with
asset_bundle_id.
title: Image Urn
industries:
anyOf:
- items:
type: string
type: array
- type: 'null'
default: null
description: >-
Optional list of industry URNs to target. Example:
['urn:li:industry:4'] for Computer Software. Note:
industries may NOT be AND'ed with employers targeting.
title: Industries
interests:
anyOf:
- items:
type: string
type: array
- type: 'null'
default: null
description: >-
Optional list of interest URNs. Example:
['urn:li:interest:689290']. Target members based on
interests expressed on LinkedIn.
title: Interests
introductory_text:
description: >-
Main ad text/copy (up to 600 characters). This is the
primary message that appears with your ad. Best
practice: Use 150 characters or less for optimal
engagement.
maxLength: 600
title: Introductory Text
type: string
job_functions:
anyOf:
- items:
type: string
type: array
- type: 'null'
default: null
description: >-
Optional list of job function URNs. Example:
['urn:li:function:22']. Note: job functions may NOT be
AND'ed with job titles.
title: Job Functions
job_titles:
anyOf:
- items:
type: string
type: array
- type: 'null'
default: null
description: >-
Optional list of job title URNs to target. Highly
specific targeting. Use targeting search to find title
URNs. Note: job titles may NOT be AND'ed with
seniorities or job functions.
title: Job Titles
landing_page_url:
description: >-
Destination URL where users will be directed. Must be
HTTPS. LinkedIn tracks clicks and conversions through
this URL.
title: Landing Page Url
type: string
locale_country:
anyOf:
- type: string
- type: 'null'
default: US
description: >-
Campaign locale country code (ISO-3166 uppercase).
Default: US. Examples: US, GB, CA, DE, FR, IN, AU, BR,
JP.
title: Locale Country
locale_language:
anyOf:
- type: string
- type: 'null'
default: en
description: >-
Campaign locale language code (ISO-639 lowercase).
Default: en. Examples: en, de, fr, es, pt, ja, zh.
title: Locale Language
locations:
description: >-
List of LinkedIn location URNs to target. Required
field. Use search_linkedin_targeting with
facet='locations' to find URNs. Supports country, state,
city, and metro targeting. Examples:
US=urn:li:geo:103644278,
California=urn:li:geo:102095887, New York
City=urn:li:geo:102571732, UK=urn:li:geo:101165590,
Canada=urn:li:geo:101174742,
Germany=urn:li:geo:101282230.
items:
type: string
title: Locations
type: array
member_behaviors:
anyOf:
- items:
type: string
type: array
- type: 'null'
default: null
description: >-
Optional list of member behavior URNs. Example:
['urn:li:memberBehavior:2'] (Mobile Users). Note: may
NOT be AND'ed with contact/website retargeting segments.
title: Member Behaviors
member_groups:
anyOf:
- items:
type: string
type: array
- type: 'null'
default: null
description: >-
Optional list of LinkedIn group URNs. Example:
['urn:li:group:1234']. Include-only facet. Disabled in
EEA/CH since May 2024.
title: Member Groups
objective:
anyOf:
- type: string
- type: 'null'
default: WEBSITE_VISIT
description: >-
Campaign objective (use SINGULAR form). Options:
BRAND_AWARENESS, ENGAGEMENT, WEBSITE_VISIT,
WEBSITE_CONVERSION, VIDEO_VIEW, JOB_APPLICANT. Default:
WEBSITE_VISIT (optimizes for clicks to your landing
page). Note: LEAD_GENERATION is NOT supported for Single
Image Ads - it requires Lead Gen Forms.
title: Objective
organization_id:
description: >-
LinkedIn Organization (Company Page) ID. The
organization that will appear as the ad author. Must be
a Company Page you have admin access to.
title: Organization Id
type: string
schools:
anyOf:
- items:
type: string
type: array
- type: 'null'
default: null
description: >-
Optional list of school (organization) URNs. Example:
['urn:li:organization:1035'].
title: Schools
seniorities:
anyOf:
- items:
type: string
type: array
- type: 'null'
default: null
description: >-
Optional list of seniority level URNs to target. URNs:
Entry=urn:li:seniority:3, Senior=urn:li:seniority:4,
Manager=urn:li:seniority:5, Director=urn:li:seniority:6,
VP=urn:li:seniority:7, CXO=urn:li:seniority:8,
Partner=urn:li:seniority:9, Owner=urn:li:seniority:10.
Note: seniorities may NOT be AND'ed with job titles
targeting.
title: Seniorities
skills:
anyOf:
- items:
type: string
type: array
- type: 'null'
default: null
description: >-
Optional list of skill URNs. Example:
['urn:li:skill:17']. Use search_linkedin_targeting to
discover skill URNs.
title: Skills
start_date:
anyOf:
- type: string
- type: 'null'
default: null
description: >-
Optional campaign start date in ISO format (e.g.,
'2024-01-15T00:00:00Z'). If not provided, campaign
starts immediately.
title: Start Date
status:
anyOf:
- type: string
- type: 'null'
default: PAUSED
description: >-
Initial campaign status. Options: ACTIVE, PAUSED, DRAFT.
Default: PAUSED (campaign created paused for review
before spending money).
title: Status
total_budget:
anyOf:
- type: number
- type: 'null'
default: null
description: >-
Optional total lifetime budget. If set, campaign will
stop after spending this amount.
title: Total Budget
years_of_experience:
anyOf:
- items:
type: string
type: array
- type: 'null'
default: null
description: >-
Optional list of years of experience URNs. Example:
['urn:li:yearsOfExperience:3']. Range: 1-12+ years. Up
to 2 URNs for lower/upper limit.
title: Years Of Experience
required:
- campaign_name
- daily_budget
- organization_id
- introductory_text
- headline
- landing_page_url
- locations
type: object
required:
- arguments
type: object
description: >-
All tool arguments are wrapped in an `arguments` object. The fields
accepted inside `arguments` are listed below — required fields are
marked with a red asterisk.
required: true
responses:
'200':
content:
application/json:
example:
data:
quota:
limit: 150
period_end: '2026-05-01'
tier: plus
used: 42
text: >-
(tool-specific textual output for
create_linkedin_image_campaign)
success: true
tool: create_linkedin_image_campaign
schema:
$ref: '#/components/schemas/SuccessResponse'
description: >-
Tool executed successfully. `data.text` carries the human-readable
result (markdown-friendly). `data.quota` shows your current usage
against the plan limit. `data.structured` appears when the tool
emits machine-parseable structured content. `data.content` appears
for tools that return non-text blocks (images, resources).
'400':
content:
application/json:
example:
error: >-
You have 25 meta_ads accounts connected. Please specify which
account to use by passing the ad_account_id parameter:
- Acme Holdings (ad_account_id="act_123456789")
- Acme EU (ad_account_id="act_987654321")
is_error: true
success: false
tool: create_linkedin_image_campaign
schema:
$ref: '#/components/schemas/ErrorResponse'
description: >-
Tool-level error. The `error` string is safe to surface to end
users. Common causes: missing required argument, multi-account user
didn't specify which account, upstream platform validation failure.
'401':
content:
application/json:
example:
error: >-
Not authenticated. Please connect your ADSMCP account first
at https://adsmcp.si
is_error: true
success: false
tool: create_linkedin_image_campaign
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Invalid, expired, or revoked API key.
'402':
content:
application/json:
example:
error: |-
🚨 Monthly limit reached (150/150 tool calls on Plus tier).
Upgrade to Pro at https://adsmcp.si to keep building.
is_error: true
quota:
limit: 150
period_end: '2026-05-01'
tier: plus
upgrade_url: https://adsmcp.si
used: 150
success: false
tool: create_linkedin_image_campaign
schema:
$ref: '#/components/schemas/QuotaErrorResponse'
description: >-
Quota exhausted for the current billing period. The response
includes a `quota` block with the current used/limit/tier values and
an `upgrade_url` to move up a tier.
'404':
content:
application/json:
example:
error: 'Tool not found: create_linkedin_image_campaign'
is_error: true
success: false
tool: create_linkedin_image_campaign
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unknown tool_name. Check /openapi.json for the full catalog.
'429':
content:
application/json:
example:
error: >-
Upstream platform rate limit hit (Meta Business Use Case
throttle at 95%). Retry after 60 seconds.
is_error: true
success: false
tool: create_linkedin_image_campaign
schema:
$ref: '#/components/schemas/ErrorResponse'
description: >-
Rate-limited by the upstream ad platform (Meta, Google, LinkedIn,
TikTok). Retry with exponential backoff. Not the same as ADSMCP's
own quota — that returns 402.
'500':
content:
application/json:
example:
error: 'Internal error: RuntimeError'
is_error: true
success: false
tool: create_linkedin_image_campaign
schema:
$ref: '#/components/schemas/ErrorResponse'
description: >-
Unexpected server error. Report to [email protected] with
request_id.
security:
- ApiKeyAuth: []
components:
schemas:
SuccessResponse:
description: >-
Returned on HTTP 200. `data.text` is the primary human-readable output.
`data.quota` is always present for billable calls. `data.structured` is
set only when the tool emits machine-parseable structured content.
`data.content` is set only when the tool emits non-text content blocks.
properties:
data:
properties:
content:
description: Non-text content blocks (images, resources).
items:
$ref: '#/components/schemas/ContentBlock'
type: array
quota:
$ref: '#/components/schemas/QuotaBlock'
structured:
additionalProperties: true
description: >-
Machine-parseable structured content when the tool provides it
(e.g. account selection prompts, widget payloads).
type: object
text:
description: >-
Human-readable output. Markdown-friendly for tools that emit
formatted lists, tables, or recommendations.
type: string
required:
- text
type: object
success:
const: true
type: boolean
tool:
description: Echoed tool_name from the request URL.
type: string
required:
- success
- data
- tool
type: object
ErrorResponse:
description: >-
Returned on HTTP 4xx / 5xx (except 402 which uses `QuotaErrorResponse`).
`error` is always a human-readable string safe to surface to end users.
properties:
error:
description: Human-readable error message.
type: string
is_error:
const: true
type: boolean
structured_content:
additionalProperties: true
description: >-
Present when the underlying tool attached structured metadata to the
error (e.g. account-selection lists).
type: object
success:
const: false
type: boolean
tool:
type: string
required:
- success
- error
- tool
type: object
QuotaErrorResponse:
description: >-
Returned on HTTP 402 when the monthly quota is exhausted. Identical to
`ErrorResponse` but with an additional `quota` block.
properties:
error:
type: string
is_error:
const: true
type: boolean
quota:
$ref: '#/components/schemas/QuotaBlock'
success:
const: false
type: boolean
tool:
type: string
required:
- success
- error
- tool
- quota
type: object
ContentBlock:
additionalProperties: true
description: >-
A non-text content block. Rare today; tools that attach images,
resources, or widget payloads populate `data.content` with blocks of
this shape.
properties:
type:
example: image
type: string
required:
- type
type: object
QuotaBlock:
description: >-
Current quota state for the API key owner. Attached to every successful
billable response under `data.quota`, and to 402 errors under `quota`
(plus `upgrade_url`).
properties:
limit:
description: Tool call allowance for the current tier.
example: 150
type: integer
period_end:
description: When the monthly counter resets (ISO date).
example: '2026-05-01'
format: date
type: string
tier:
description: Subscription tier of the account that owns the API key.
enum:
- free
- plus
- pro
- max
example: plus
type: string
upgrade_url:
description: Upgrade link (present only on 402 quota errors).
format: uri
type: string
used:
description: Tool calls consumed this billing period.
example: 42
type: integer
required:
- used
- limit
- tier
- period_end
type: object
securitySchemes:
ApiKeyAuth:
bearerFormat: API Key (sk_live_...)
description: >-
API key from https://adsmcp.si/dashboard/api-tokens. Prefix `sk_live_`. Treat as a
secret — never commit.
scheme: bearer
type: http