@taskmagic/apps-sklik
v0.0.2
Published
PPC campaign management for [Sklik](https://www.sklik.cz/), the advertising platform run by Seznam.cz — the Czech search engine's equivalent of Google Ads.
Readme
Sklik
PPC campaign management for Sklik, the advertising platform run by Seznam.cz — the Czech search engine's equivalent of Google Ads.
This piece speaks API Fénix, Sklik's REST/JSON API under https://api.sklik.cz/v1. The
machine-readable spec at https://api.sklik.cz/v1/openapi.json is the authoritative reference;
the human-facing documentation lives at https://napoveda.sklik.cz/.
Authentication is OAuth2 bearer, in two stages: you paste a long-lived API Fénix key (the API calls it a refresh token), and TaskMagic exchanges it for a 1-hour access token that it caches and reuses.
- Actions: List Campaigns, Pause Campaign, Enable Campaign, Update Campaign Budget, List Ad Groups, Update Ad Group, List Ads, Get Account Info, Get Account Credit.
- Triggers: New Campaign (polling), Campaign Status Changed (polling).
Connection: sign in at sklik.cz, open Nastavení ("Settings") and
find Správa klíčů API Fénix ("API Fénix key management"). Create a key, giving it a name, an
expiry date and access rights — r (read), rw (read/write) or rwa (adds administrative
actions such as linking accounts). The write actions in this piece need at least rw. Copy the
key immediately: Sklik shows it once and it cannot be retrieved afterwards. Delete the key on
the same screen to revoke it; an account can hold several keys.
You must be logged into Sklik directly, with the e-mail address and password of the account you want the key for. If you only impersonate into that account — for example as an account Administrator — Sklik does not offer the option to generate a token at all. This is the single most common reason people cannot find the button.
The optional Managed Account User ID on the connection is for agencies: it mints the access token for a linked account you have already been granted access to, rather than for the account that owns the key.
Notes
- All money is in hellers (haléře): 100 hellers = 1 CZK. Every budget, bid and money-shaped
statistic Sklik returns —
dayBudget,totalBudget,clickMoney,totalMoney,avgCpc,conversionValue,cpc,cpmand the rest — is an integer in minor units. The write actions take CZK and convert (750 CZK is sent as75000); the list actions leave Sklik's raw values untouched and add amoneyInCzkobject beside them so nothing downstream has to divide by 100 by hand. The Statistic Conditions filter is passed straight through to Sklik, so thresholds there are still in hellers. The one exception is Get Account Credit —/user/me/creditis documented in CZK, not hellers, and is returned exactly as received. - The status enum is
active/suspend. Notsuspended, notpaused. Pause Campaign writessuspend; the status filters and Update Ad Group use the same two values. - Nothing is returned unless you ask for it. Sklik's list endpoints take a repeated
aquery parameter naming each attribute (?a=id&a=name&a=status&a=clicks), and return only their own small default set otherwise. That is what the Campaign Fields / Ad Group Fields / Ad Fields and Statistics selectors drive. Selecting any statistic makes Statistics Date From and Statistics Date To mandatory (YYYY-MM-DD); the piece checks that locally rather than letting Sklik answer 422. - Entities and statistics come back together.
GET /sklik/campaigns/merges campaign fields and statistics into one response, so there is no report job to submit and poll — List Campaigns is usually all a reporting flow needs. - Updates must echo the campaign type. Sklik's PATCH body is a union discriminated on
typeand is rejected without it, even though a campaign's type can never be changed. Leave Campaign Type empty and the piece looks the type up first; set it to save a request. - Dry run. Pause, Enable, Update Campaign Budget and Update Ad Group all expose Sklik's
dryRunflag, which validates the change and reports problems without saving anything. - Partial updates never blank what you left alone. Every empty field is omitted from the request body, and Update Ad Group's status is a three-state dropdown rather than a checkbox so an untouched step cannot silently resume a paused group.
- Access tokens are cached, on purpose. The spec is explicit: "Do not call
/user/tokenendpoint prior to each API call, the endpoint is rate-limited. The intended use is to call it once before all the processing you need to do, then reuse the token until it expires." The piece caches the 1-hour token per connection (keyed by a hash of the credential, never the credential itself) with a 5-minute safety margin, shared across the project, and re-mints only when Sklik actually rejects a token — once, then it fails rather than hammering the endpoint. Callers that arrive while a mint is already running share its result, so parallel steps cannot turn one expiry into a burst of token requests. - Rate limit: 5 requests per second for the whole API, shared across every endpoint, with
429plus aRetry-Afterheader when exceeded./user/tokenis limited separately and more aggressively. The list actions therefore default tolimit=1000(Sklik's own maximum) so one page beats many small calls, and a429is waited out and retried twice before the step fails. - Polling triggers, not webhooks. Fenix has no callback, subscription or webhook endpoint
anywhere in its 35 paths, and no "modified since" filter either. New Campaign dedupes on
createDate, the only monotonic timestamp on a campaign. Campaign Status Changed keeps its ownid → statussnapshot in the flow store and emits the difference — a status flip updates no timestamp, so a diff is the only way to see one. That snapshot is seeded when the trigger is enabled (so turning the flow on does not report every campaign) and deleted when it is disabled. A campaign appearing for the first time is reported by New Campaign only, never by Campaign Status Changed. - Keyword management is not covered.
keywords.list,keywords.update, negative keywords, keyword reports and search-term reports do not exist on API Fénix at all — they live only on Sklik's legacy "Drak" XML-RPC API, whoseclient.loginByTokensession has an undocumented TTL. Shipping Drak alongside Fenix would mean a second auth model with unknown expiry semantics, so v1 is Fenix-only. Campaign-level negative keywords can still be set through Sklik's campaign update endpoint, but that is not exposed as an action here. - Also not implemented: creating campaigns, ad groups and ads (
POST), deleting anything, image upload, ad suggestions, conversion listing, the asynchronous/sklik/reports/job API, and the entire/nakupy/(Zboží.cz shopping) surface. These are additive and can follow once the core management flows are proven. - No custom API call action. A passthrough would hand this connection's API key to any URL a flow supplies.
- A documentation warning. Sklik's Czech example page ships a broken
get_access_tokensnippet that posts to/user/meinstead of/user/token. Trust https://api.sklik.cz/v1/openapi.json over the prose examples.
