Skip to main content

Migration from the old API to the new one

Written by Olga

This guide is for advertisers whose scripts and integrations call the old API at api.kadam.net (the app_id and secret_key parameters, request signing, methods such as ads.campaigns.get). It explains how to move an integration to the new API, what replaces each old method, and what the new API does not support.

New API description: API Advertisers and Swagger.

Important: on November 16, 2026 the old API will be switched off. After that date, requests to api.kadam.net will stop working.

Migration algorithm

The API has been completely redesigned and is not backward compatible. Every call has to be moved to the new API. The following sections contain a table of the basic differences; the specification of each method (parameters, request bodies, responses) is in the new API documentation.

  1. List your calls. Find every request to api.kadam.net in your code and write down the methods (ads.campaigns.get, ads.materials.put, and so on).

  2. Find each method in the tables below. Every method has one of three statuses:

    • Direct replacement: the new API has an endpoint for the same task.

    • Alternative: the same operation does not exist, but the goal can be reached another way through the API.

    • Not supported in the new API: the goal cannot be reached through the new API.

  3. Get a token. Open the advertiser dashboard, go to "Profile and settings" and copy the token. Treat it like a password. You can reset the token with POST /api/users/token-reset.

  4. Replace authorization. Remove the auth.token call, the signature calculation, and the app_id and client_id parameters. Add the Authorization: Bearer <token> header to every request.

  5. Replace addresses and method formats. Convert the calls using the tables.

  6. Replace dictionary IDs. Take campaign types, statuses, countries, regions and browsers from the new API dictionaries (GET /dictionaries/{type}, GET /campaigns/options). Do not carry numeric constants over from the old code.

  7. Rework response parsing. Data now lives in data; an error is success: false with the text in msg.

  8. Check the result against the dashboard. Compare the data returned by the new API with the dashboard: campaign and material lists, statistics, balance.

  9. Launch the integration. Remove any leftover old API calls from your code and turn back on the jobs you stopped.

Authorization example.

Before:

GET https://api.kadam.net/auth.token?app_id=12345&secret_key=SECRET

GET https://api.kadam.net/ads.campaigns.get?app_id=12345&client_id=12345&limit=50&offset=0&signature=<md5 of the signature string>

After:

POST https://partners.kadam.net/api/v1/campaigns
Authorization: Bearer YOUR_TOKEN
Content-Type: application/json

{"page": 1, "perPage": 50, "sort": {"dateCreation": "desc"}}

Basic differences of the new API from the old one

Old API

New API

Address

https://api.kadam.net/<method>

https://partners.kadam.net/api/v1/<path>

Keys

app_id and secret_key

A single Bearer token

Getting a token

auth.token(app_id, secret_key) request, the token lives 7 days

The token is taken in the dashboard under "Profile and settings" and does not expire

Request authorization

signature parameter, calculated for every request

Authorization: Bearer <token> header, no signature

Call format

Method in the resource name (ads.campaigns.get) plus an HTTP method

REST: path and HTTP method (POST /campaigns)

Client

client_id in every call

Not needed: the token is tied to your account

Successful response

{"response": {...}}, HTTP 204 for an empty result

{"success": true, "code": 0, "data": {...}}

Error

{"error": {"code": ..., "msg": ...}}

{"success": false, "code": ..., "msg": ...}

Pagination

limit and offset

page and perPage

Sorting

A string in the sort parameter

An object {"field": "asc" or "desc"}

Dates and time zone

date_from, date_to, timezone as +00:00

dateFrom, dateTo in filters, timezone as an integer from -12 to 12

Method mapping

The "New API" column gives the path and HTTP method. For parameters and request body schemas, see Swagger.

Account and finances

Old method

Status

New API

Notes

ads.account.get (account balance)

Direct replacement

GET /me, GET /finances/balance

GET /me returns the ID, balance, currency, registration date and time zone. To check only the balance, use GET /finances/balance.

data.balance.systems.get (payment systems)

Direct replacement

GET /finances/payment-systems

The list depends on your account: currencies, fees and minimum amounts are already resolved for you.

data.balance.report.operations.get, data.balance.report.types.get, data.balance.report.states.get (operations report dictionaries)

Alternative

POST /finances/operations

There are no separate dictionaries. The operation type is set in filters.type (1 impressions, 2 deposit, 3 deposit by administrator, 4 withdrawal, 5 withdrawal by administrator). The operation status comes in every response row in the status field.

Campaigns

Old method

Status

New API

Notes

ads.campaigns.get (list)

Direct replacement

POST /campaigns

Filters in filters: searchQuery, dateFrom, dateTo, timezone, folderId, campaignId, types, statuses, paymentModels, countries, archive. Archived campaigns: filters.archive = 1.

ads.campaigns.get (single campaign)

Direct replacement

GET /campaigns/{id}

The response has the same format that PUT /campaigns/{id}/update accepts.

ads.campaigns.put (create)

Direct replacement

POST /campaigns/create

The body depends on the campaign type: Native, Banner, Push, Popunder, In-Page Push. To check a body in advance without creating anything, use POST /campaigns/validate.

ads.campaigns.update (change)

Direct replacement

PUT /campaigns/{id}/update

There is no partial update: an omitted field is reset to its default. Fetch the campaign with GET /campaigns/{id}, change what you need and send the whole object back.

ads.campaigns.delete

Direct replacement

POST /campaigns/archive, DELETE /campaigns

The old method moved a campaign to the archive. In the new API, archiving is POST /campaigns/archive, while DELETE /campaigns permanently deletes campaigns with their materials and accepts only archived ones.

ads.campaigns.status.get (statuses by ID)

Direct replacement

POST /campaigns

Each campaign's status comes in the list. For a single campaign, use filters.campaignId or GET /campaigns/{id}.

ads.campaigns.block.update (block and unblock)

Alternative

POST /campaigns/pause, POST /campaigns/activate

This is pause and start, not a technical block with the old status.

ads.campaigns.bwlist.put (site black and white lists)

Direct replacement

POST /stats/sites/block, POST /stats/sites/unblock, PUT /campaigns/{id}/update

Black list: POST /stats/sites/block adds sites to the black list in several campaigns at once, POST /stats/sites/unblock removes them. You do not need to send the other campaign fields. White list or replacing the whole list: the sites field in PUT /campaigns/{id}/update, format {"mode": ..., "list": [site IDs]}, sent together with the other campaign fields.

ads.campaigns.cpa.mode.get (Kadam postback URL)

Not supported in the new API

—

The postback URL is taken from the documentation or from the campaign editing interface.

ads.campaigns.statblock.get, ads.campaigns.statblock2.get

Alternative

POST /stats/sites

These methods are already disabled in the old API. Statistics by site: POST /stats/sites.

ads.campaigns.statblock.put, ads.campaigns.statblock2.put (bid multiplier per site)

Alternative

PUT /stats/sites/bids

Bid for sites: a number, x1.5 for a multiplier, 0 to remove. Site IDs come from the macrosId field of the POST /stats/sites response.

ads.campaigns.categories.get, ads.campaigns.categories.desc.get

Direct replacement

GET /dictionaries/categories

ads.campaigns.formats.get

Direct replacement

GET /dictionaries/campaign-types

Types: 10 Native, 20 Banner, 30 Push, 40 Popunder, 100 In-Page Push.

ads.campaigns.cp.types.get (payment models)

Direct replacement

GET /campaigns/options, cpTypes field

ads.campaigns.tags.get, ads.tags.get (campaign and material tags with a price per tag)

Not supported in the new API

—

The new API has neither tags nor a price per tag.

Campaign bids are changed by separate methods: PUT /campaigns/{id}/bid for one campaign and PUT /campaigns/bids for several.

Materials

Old method

Status

New API

Notes

ads.materials.get (list)

Direct replacement

POST /materials

Filters: searchQuery, dateFrom, dateTo, timezone, campaignId, types, statuses, archive.

ads.materials.get (single material)

Direct replacement

GET /materials/{id}

ads.materials.put (create)

Direct replacement

POST /campaigns/{id}/materials

The image file is sent right in the request (multipart/form-data). Size limits depend on the format, for example 512 KB for Native and Push, 153.6 KB for Banner.

ads.materials.update (change)

Direct replacement

PUT /campaigns/{id}/materials

ads.materials.delete

Direct replacement

POST /materials/archive, DELETE /materials

First move the material to the archive, then you can delete it.

ads.materials.banner.sizes.get

Direct replacement

GET /materials/options, sizes field

data.upload.media.update (preliminary file upload)

Alternative

POST /campaigns/{id}/materials, POST /materials/bulk/upload

There is no separate file upload: the file goes in the material creation request. For a batch of images there is a two-step bulk upload: POST /materials/bulk/upload, then POST /materials/bulk, with the job state in GET /materials/bulk/{jobId}.

ads.materials.partners.get

Not supported in the new API

—

For bulk actions on materials there are POST /materials/activate, /materials/pause, /materials/archive, /materials/restore, /materials/copy, /materials/move. They take a list in the adsIds field.

Audiences

Old method

Status

New API

Notes

ads.audience.get

Direct replacement

POST /audiences, GET /audiences/{audiencesId}

ads.audience.put

Direct replacement

POST /audiences/create

Audience types: audience, audience_code, s2s. To check a body in advance, use POST /audiences/validate.

ads.audience.update

Direct replacement

PUT /audiences/{id}

ads.audience.delete

Direct replacement

DELETE /audiences/{id}

Statistics

Old method

Status

New API

Notes

ads.stats.campaign.get (campaign statistics by date, campaign, region)

Direct replacement

POST /custom-reports/data

Groupings and metrics are chosen in the request body. The list of available groupings and metrics comes from OPTIONS /custom-reports. Saved reports come from POST /custom-reports.

ads.stats.creative.get (material statistics)

Direct replacement

POST /custom-reports/data

Same.

ads.stats.campaign.placement.get, ads.stats.campaign.placement.put

Direct replacement

POST /stats/sites, PUT /stats/sites/bids

ads.analytic.areas.get (analytics by site)

Alternative

POST /stats/sites

ads.analytic.campaign.get, ads.analytic.material.get, ads.analytic.materials.get, ads.analytic.materials2.get

Alternative

POST /custom-reports/data

These methods are already disabled in the old API.

ads.analytic.clicks.get (clicks)

Alternative

POST /custom-reports/data, POST /stats/conversions

There are no raw clicks. Aggregated clicks are in the reports, and raw conversions come from POST /stats/conversions.

Dictionaries

Old method

Status

New API

Notes

ads.targeting.browsers.get

Direct replacement

GET /dictionaries/browsers

ads.targeting.platforms.get

Direct replacement

GET /dictionaries/platforms

ads.targeting.devices.get

Direct replacement

GET /dictionaries/devices

ads.targeting.countries.get, data.geo.countries.get

Direct replacement

GET /dictionaries/countries

ads.targeting.regions.get, data.geo.regions.get

Direct replacement

GET /dictionaries/regions

The country is passed in the countryId parameter.

ads.targeting.cities.get

Direct replacement

GET /dictionaries/cities

ads.targeting.ages.get

Direct replacement

GET /campaigns/options, ages and subAges fields

ads.targeting.langs.get

Direct replacement

GET /campaigns/options, languages field

ads.targeting.cpa.modes.get

Alternative

GET /dictionaries/conversion-templates

The old method returned a list of CPA modes. In the new API the mode is not chosen separately: postback statuses are set with the conversion and postConversion fields in the campaign, and ready-made status templates come from this dictionary.

All GET /dictionaries/{type} dictionaries accept the search, page and perPage (up to 500) parameters.

Not supported in the new API

The first method below has another way to get the same information. The rest belong to functionality that has not existed in Kadam for a long time — there is nothing to migrate for them.

  • ads.campaigns.cpa.mode.get: the postback URL is taken from the documentation or from the campaign editing interface. If you need anything else, contact your manager or support.

  • ads.campaigns.tags.get, ads.tags.get — campaign and material tags with a price per tag, long gone from Kadam.

  • ads.materials.partners.get — long gone from Kadam.

  • ads.offers.* and ads.offers.landings.* — offers and landing pages as separate entities, long gone from Kadam. The click-through link is set in the campaign or material itself.

  • server.time.get, about.methods.get, about.version.get — service methods unrelated to business functionality.

  • ads.clients.* — balance and client management for agency accounts, long gone from Kadam.

What to keep in mind when migrating

  • Campaigns are updated only as a whole. PUT /campaigns/{id}/update replaces the campaign completely. An omitted field returns to its default, for example an omitted dayMoneyLimit removes the daily limit. Always fetch the campaign with GET /campaigns/{id} first.

  • Dictionaries instead of constants. Take status, type and country IDs from the new API dictionaries.

  • Time zone. The timezone parameter in the new API is an integer from -12 to 12, not a +00:00 string.

  • Field names. Bulk methods take lists in the campaignIds and adsIds fields, not in ids.

  • Empty result. The old API answered with HTTP 204. In the new API, for lists expect success: true and an empty set of rows in data, not a separate response code.

  • Material files are sent in the material creation or update request itself.

Errors

Old code

Meaning

Closest case in the new API

0

Unknown error

success: false and the description in msg

1

Method not found

Not applicable: use the paths from this guide. If an object (campaign, material) is not found, the API answers with HTTP 404

2, 7, 9

Parameters not set, bad data, outdated macros

HTTP 422, the fields with errors are listed in msg

3, 8

Client or key not found, incorrect token

HTTP 401

4, 5

Token expired, incorrect signature

Not applicable: the token does not expire and there is no signature

6

Access denied

HTTP 403

10

Too many requests

HTTP 429

The mapping is approximate: rely on success and msg. On an error, the new API returns {"success": false, "code": 400, "msg": {"field": ["error description"]}}.

What the new API gives you

  • Autorules for managing bids in CPC campaigns (/autorules, /campaigns/{campaignId}/autorules).

  • Traffic forecast by bid before launching a campaign or raising a bid (POST /campaigns/forecast).

  • Checking a campaign or an audience without creating it (POST /campaigns/validate, POST /audiences/validate).

  • Bid optimization by statistics slices (/stats/extended).

  • Bulk bids and site blocking, per-country material bids (PUT /stats/sites/bids, POST /stats/sites/block, PUT /materials/bids).

  • Bulk material upload from images and ZIP archives (/materials/bulk/upload, /materials/bulk).

  • Copying campaigns and materials, campaign folders with bulk actions (POST /campaigns/{id}/copy, /materials/copy, /campaigns/folders).

  • Account daily spending limit, Easy Start, creative import from RSS, report builder (/finances/day-money-limit, PUT /campaigns/{id}/easy-start, PUT /campaigns/{id}/rss, /custom-reports).

Did this answer your question?