X Ads
Create campaigns and promote tweets via Zernio API - OAuth 1.0a and approval handled for you
Included with the Usage plan. No X Ads API approval application needed. OAuth 1.0a request signing is handled server-side.
accountId accepts either shape. Pass the posting X/Twitter account ID or the X Ads credential account ID, Zernio resolves the sibling internally so either value works. If no X Ads credential is connected for the resolved profile, the API returns code: "ads_connection_required".
What's Supported
| Feature | Status |
|---|---|
| Standalone campaigns (Campaign > Line Item > Promoted Tweet) | Yes |
| Promote existing tweets | Yes |
| Location + language targeting | Yes |
| Real-time analytics (spend, CPE, CPM, link clicks) | Yes |
| OAuth 1.0a signing handled | Yes |
| Keyword targeting | Roadmap |
| Follower look-alike targeting | Roadmap |
| Tailored Audiences (read, create, member upload) | Yes |
Promote an Existing Tweet
const ad = await zernio.ads.boostPost({ body: {
postId: "POST_ID",
accountId: "ACCOUNT_ID",
adAccountId: "18ce54d4x5t",
name: "Boost launch tweet",
goal: "engagement",
budget: { amount: 50, type: "daily" },
schedule: { startDate: "2026-04-20", endDate: "2026-04-27" },
}});ad = client.ads.boost_post(
post_id="POST_ID",
account_id="ACCOUNT_ID",
ad_account_id="18ce54d4x5t",
name="Boost launch tweet",
goal="engagement",
budget={"amount": 50, "type": "daily"},
schedule={"startDate": "2026-04-20", "endDate": "2026-04-27"},
)curl -X POST "https://zernio.com/api/v1/ads/boost" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"postId": "POST_ID",
"accountId": "ACCOUNT_ID",
"adAccountId": "18ce54d4x5t",
"name": "Boost launch tweet",
"goal": "engagement",
"budget": { "amount": 50, "type": "daily" },
"schedule": { "startDate": "2026-04-20", "endDate": "2026-04-27" }
}'Create a Standalone Campaign
const ad = await zernio.ads.createStandaloneAd({ body: {
accountId: "acc_xads_123",
adAccountId: "18ce54d4x5t",
name: "Q2 Product Awareness",
goal: "awareness",
budgetAmount: 75,
budgetType: "daily",
body: "Ship faster with platform engineering done right.",
linkUrl: "https://example.com/platform",
countries: ["US"],
}});ad = client.ads.create_standalone_ad(
account_id="acc_xads_123",
ad_account_id="18ce54d4x5t",
name="Q2 Product Awareness",
goal="awareness",
budget_amount=75,
budget_type="daily",
body="Ship faster with platform engineering done right.",
link_url="https://example.com/platform",
countries=["US"],
)curl -X POST "https://zernio.com/api/v1/ads/create" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"accountId": "acc_xads_123",
"adAccountId": "18ce54d4x5t",
"name": "Q2 Product Awareness",
"goal": "awareness",
"budgetAmount": 75,
"budgetType": "daily",
"body": "Ship faster with platform engineering done right.",
"linkUrl": "https://example.com/platform",
"countries": ["US"]
}'For X, body is the tweet text (max 280 chars; X shortens linkUrl to ~24 chars against that limit). headline, imageUrl, and callToAction are ignored on X. Valid goal values: engagement, traffic, awareness, video_views, app_promotion.
OAuth 1.0a
The X Ads API uses OAuth 1.0a request signing (not OAuth 2.0 Bearer tokens). Zernio computes HMAC-SHA1 signatures server-side, so your integration uses a standard Bearer token like every other platform.
Tailored Audiences
Create a Tailored (custom) Audience and upload members. adAccountId is the X Ads account ID. Email only (any phone is ignored); values are SHA256-hashed server-side. An audience must match at least 100 recently-active users before X will let you target it, so the size stays 0/- until then.
// 1. Create the (empty) tailored audience
await zernio.adaudiences.createAdAudience({
body: {
accountId: 'acc_xads_123',
adAccountId: '18ce55abc12', // X Ads account ID
type: 'customer_list',
name: 'Trial signups',
},
});
// 2. Upload members to the returned audience id
await zernio.adaudiences.addUsersToAdAudience({
path: { audienceId: 'aud_abc123' }, // id from the create response
body: { users: [{ email: 'jane@example.com' }, { email: 'sam@example.com' }] },
});# 1. Create the (empty) tailored audience
client.ad_audiences.create_ad_audience(
account_id="acc_xads_123",
ad_account_id="18ce55abc12", # X Ads account ID
type="customer_list",
name="Trial signups",
)
# 2. Upload members to the returned audience id
client.ad_audiences.add_users_to_ad_audience(
audience_id="aud_abc123", # id from the create response
users=[{"email": "jane@example.com"}, {"email": "sam@example.com"}],
)# 1. Create
curl -X POST "https://zernio.com/api/v1/ads/audiences" \
-H "Authorization: Bearer YOUR_API_KEY" -H "Content-Type: application/json" \
-d '{ "accountId": "acc_xads_123", "adAccountId": "18ce55abc12", "type": "customer_list", "name": "Trial signups" }'
# 2. Upload members (use the audience id from the create response)
curl -X POST "https://zernio.com/api/v1/ads/audiences/AUDIENCE_ID/users" \
-H "Authorization: Bearer YOUR_API_KEY" -H "Content-Type: application/json" \
-d '{ "users": [{ "email": "jane@example.com" }, { "email": "sam@example.com" }] }'Media Requirements
| Type | Format | Max Size | Notes |
|---|---|---|---|
| Image | JPEG, PNG, GIF, WebP | 5 MB | 1200x675 (16:9) recommended |
| Video | MP4, MOV | 1 GB | 0.5-140 sec, H.264+AAC |
| Tweet text | UTF-8 | 280 chars | Standard limit |
| Website Card | URL + text | 70 char title | Landing page card |