adPluga

Embedded components

Opening adPluga inside your application

Your team clicks a button in your own admin and creates campaigns, ads and slots without leaving it. The screen is ours, the frame is yours, and nobody signs in inside the window.

How it works

Two steps. Your server asks for a session with the integration key; the browser opens it in a dialog, already authenticated. The user never sees a login screen — deliberately: a login form inside another site's window is indistinguishable from a scam, and the adPluga session does not travel there anyway. So authentication stays on your server, where the key is safe, and the window only shows the screen ready to use.

Customer application with a button to open adPluga
The starting point: a button in your application.
  • The secret is single-use and lasts 5 minutes. Ask for it when the person clicks, not on page load.
  • The page only accepts being framed by the origin you declared. Any other origin is refused by the browser.
  • The screen cannot do more than the key: its scopes rule, and billing, wallet, payouts and key management are out of reach.

Step 1 — your server asks for the session

Server-side, with the integration key. Never from the browser: the key must not leave your backend.

curl -X POST https://api.adpluga.com/v1/embed/sessions \
  -H 'Authorization: Bearer ak_live_•••' \
  -H 'Content-Type: application/json' \
  -d '{"component":"campaign_create","origin":"https://admin.YOUR_COMPANY.com"}'

# {
#   "client_secret": "cs_•••",
#   "url": "https://api.adpluga.com/embed/campanha/?cs=cs_•••&mode=live",
#   "expires_at": "2026-01-01T12:05:00Z"
# }

Return the client_secret and the url to your frontend. The url already carries the secret and the environment.

Step 2 — the browser opens the dialog

One script tag and one call. The dialog sizes itself to the content and goes full screen on a phone.

<script src="https://cdn.adpluga.com/v1/embed.js"></script>
<script>
  async function abrir(component) {
    const r = await fetch("/api/adpluga/session", {
      method: "POST",
      body: JSON.stringify({ component }),
    });
    const s = await r.json();
    AdPlugaEmbed.open({
      url: s.url,
      clientSecret: s.client_secret,
      onDone: (r) => console.log("created", r),
      onClose: () => console.log("closed"),
    });
  }
</script>

The three components

Each component asks for the scopes it needs. A key without them gets 403 when creating the session, not halfway through the screen.

campaign_create — needs campaign:write

The full campaign form: objective, pricing model, bid and budget, schedule, geography, devices and categories. On the free plan it explains that the bid orders and does not yet spend.

adPluga dialog showing the new campaign form
campaign_create open over the customer's application.

ad_create — needs campaign:read, ad:write, asset:read and asset:write

Picks the campaign, the creative type (image, HTML5, native, template, video, rewarded, carousel, audio) and the IAB format. The file upload happens inside the dialog and the ad goes to moderation.

adPluga dialog showing the new ad form
ad_create with the campaign picker and the upload zone.

slot_create — needs property:read and slot:write

The place the ad appears: the property it belongs to, a name, the format and the IAB size. A property that is not verified yet is still offered — it serves in test mode until the domain is verified.

adPluga dialog showing the new slot form
slot_create, with the unverified property notice.

Events back to you

The dialog talks to your page over postMessage. The loader already handles resize and close; onDone hands you what was created.

{ "source": "adpluga", "type": "ready" }
{ "source": "adpluga", "type": "resize", "height": 1240 }
{ "source": "adpluga", "type": "done", "entity": "campaign", "campaign_id": "…", "name": "…" }
{ "source": "adpluga", "type": "done", "entity": "ad", "ad_id": "…", "campaign_id": "…", "status": "in_review" }
{ "source": "adpluga", "type": "done", "entity": "slot", "slot_id": "…", "name": "…" }
{ "source": "adpluga", "type": "close" }

If you wire the listener yourself, always compare event.origin with the adPluga origin before believing the message.

Test and live

The key prefix decides: an ak_test_ key writes in test mode — nothing charged, no quota used, nothing counted — and the dialog says so plainly, with a badge and a note. The mode is baked into the token the page uses, so no header or parameter can move it.

Mapping a promotions admin onto adPluga

Anyone already running campaigns on their side rarely uses the same names. This is the correspondence we checked against the live API, field by field.

In your adminIn adPluga
Campaign namename on the campaign (up to 120 characters)
Objectiveobjective: traffic, awareness or conversions
Campaign type (banner)pricing_model: CPM, CPC, CPA or CPL, with bid_cents. The currency is yours: currency accepts AOA.
Campaign periodstarts_at and ends_at on the campaign. An ad has no window of its own — it inherits the campaign's.
Target audience (VIP, no purchase in 30 days…)First-party audiences: create them at /v1/audiences, push the members, and name them in targeting.audiences.first_party_include.
Position in the app (home top, category…)One slot per position. The campaign points at them through targeting.slots, by id or by name.
Format (1200×400, 800×400, 600×600)width and height on the ad, free up to 8192. You do not have to use IAB sizes.
Up to 4 images in one bannertype: carousel with 2 to 10 slides. One auction, one impression, one destination — swiping spends no decisions.
Alternative textalt_text on the ad. It is what a screen reader announces in place of the image.
Display prioritybid_cents: the auction ranks by eCPM, so a higher bid shows first.
Usage limittargeting.freq_cap.per_user_per_day caps per person per day; budget_total_cents caps the total.
State (active, scheduled, paused)the campaign status plus the window: scheduled is active with starts_at in the future.

What stays on your side: discount, cashback and points are your promotion's mechanics, not the ad server's; push, email and SMS are your channels — adPluga delivers the banner. The internal identifier and the description also stay with you, because we do not store them.

What we guarantee

  • The secret is spent on the first exchange. A second attempt with the same secret returns 401.
  • The page's token lives in memory and is never written to a cookie or to storage, so closing the dialog forgets it.
  • The framing policy is built per session: only the origin you named can display the page.
  • The token is bound to the key's scopes. Even though it is a session token, it is refused on any route the key could not open.